Tải bản đầy đủ
Lab 24.1: Extending Functionality with Oracle-Supplied Packages

Lab 24.1: Extending Functionality with Oracle-Supplied Packages

Tải bản đầy đủ

TheUTL_FILEpackageprovidesserver-sidetextfileaccess,soitcannotreadbinary
files.Forthatpurpose,youwouldusetheDBMS_LOBpackage.Thefilesthatyouaccess
mustbemappedtoadriveontheserver.Thesecuritysettingsthatdeterminewhich
directoriesyoucanaccessarecontrolledintheINIT.ORAfile;yousetthedrivesthatcan
beaccessedwiththeUTL_FILE_DIRinitializationparameter.
UTL_FILE_DIR=‘C:\WORKING'

Youcanalsobypassallserver-sidesecurityandallowallfilestobeaccessedwiththe
UTL_FILEpackagewiththefollowingsetting:
UTL_FILE_DIR=*

IfyoudonothaveaccesstotheINIT.ORAfileonthedatabaseserver,youcanquery
thedatadictionarytofindthevaluethathasbeensetinyourdatabasewiththefollowing
SQLcode:
SELECTname,value
FROMV$SYSTEM_PARAMETER
WHEREname=‘utl_file_dir’

BytheWay
ItisnotadvisabletoallowUTL_FILEaccesstoallfilesinaproduction
environment.Thissettingmeansthatallfiles,includingimportantfilesthat
managetheoperationofthedatabase,areaccessible.Developersmay
potentiallywriteaprocedurethatcorruptsthedatabaseinsuchacase.
TousetheUTL_FILEfilepackage,youopenthetextfile,processthefilebywritingto
itandgettinglinesfromthefile,andclosethefile.Ifyoudonotclosethefile,the
operatingsystemwillthinkthatthefileisinuseandwillnotallowyoutowritetothefile
untilitisclosed.Table24.1liststhemajorfunctions,procedures,anddatatypesinthe
UTL_FILEpackage.Table24.2identifiestheexceptionsfoundinthispackage.

Table24.1UTL_FILEFunctions,Procedures,andDataTypes

Table24.2UTL_FILEExceptions
Thefollowingexampledemonstratesaprocedurethatwritestoalogfilethedate,time,
andnumberofuserswhoarecurrentlyloggedon.Tomakeuseofthisexample,theuser
STUDENTneedstohaveprivilegestoaccessthev$sessiontable.Accesscanbe
grantedbythedatabaseadministrator(DBA)toSTUDENTasfollows:
Clickheretoviewcodeimage

GRANTSELECTONsys.v_$sessionTOstudent;
ch24_1.sql”

ForExamplech24_1.sql
Clickheretoviewcodeimage
CREATEORREPLACEPACKAGEBODYschool_apiAS
CREATEORREPLACEPROCEDURELOG_USER_COUNT
(PI_DIRECTORYINVARCHAR2,
PI_FILE_NAMEINVARCHAR2)
AS
V_File_handleUTL_FILE.FILE_TYPE;
V_user_countnumber;
BEGIN
SELECTcount(*)
INTOV_user_count
FROMv$session
WHEREusernameisnotnull;
V_File_handle:=
UTL_FILE.FOPEN(PI_DIRECTORY,PI_FILE_NAME,‘A’);
UTL_FILE.NEW_LINE(V_File_handle);
UTL_FILE.PUT_LINE(V_File_handle,‘–-Userlog–—’);
UTL_FILE.NEW_LINE(V_File_handle);
UTL_FILE.PUT_LINE(V_File_handle,‘on‘||
TO_CHAR(SYSDATE,‘MM/DD/YYHH24:MI’));
UTL_FILE.PUT_LINE(V_File_handle,
‘Numberofusersloggedon:‘||V_user_count);
UTL_FILE.PUT_LINE(V_File_handle,‘–-Endlog–—’);
UTL_FILE.NEW_LINE(V_File_handle);
UTL_FILE.FCLOSE(V_File_handle);
EXCEPTION
WHENUTL_FILE.INVALID_FILENAMETHEN
DBMS_OUTPUT.PUT_LINE(‘Fileisinvalid’);
WHENUTL_FILE.WRITE_ERRORTHEN
-DBMS_OUTPUT.PUT_LINE(‘Oracleisnotabletowritetofile’);
END;

TheLOG_USER_COUNTprocedurecanbeexecutedtologthenumberofusersintothe
filec:\working\user.log.
Clickheretoviewcodeimage
SQL>execLOG_USER_COUNT(‘C:\working',‘USER.LOG’);
PL/SQLproceduresuccessfullycompleted.

HerearetheresultingUSER.LOGcontents:
–-Userlog–—
on07/05/0313:09
Numberofusersloggedon:1
–-Endlog–—

AccessFileswithUTL_FILE
ThefollowingPL/SQLscriptcreatesaproceduretoreadafileanddisplaythecontents.
TheexceptionWHENNO_DATA_FOUNDwillberaisedwhenthelastlineofthefilehas
beenreadandtherearenomorelinestoread.

ForExamplech24_2.sql
Clickheretoviewcodeimage
CREATEORREPLACEPROCEDUREREAD_FILE
(PI_DIRECTORYINVARCHAR2,
PI_FILE_NAMEINVARCHAR2)
AS
V_File_handleUTL_FILE.FILE_TYPE;
V_FILE_LineVARCHAR2(1024);
BEGIN
V_File_handle:=
UTL_FILE.FOPEN(PI_DIRECTORY,PI_FILE_NAME,‘R’);
LOOP
UTL_FILE.GET_LINE(V_File_handle,v_file_line);
DBMS_OUTPUT.PUT_LINE(v_file_line);
ENDLOOP;
EXCEPTION
WHENNO_DATA_FOUND
THENUTL_FILE.FCLOSE(V_File_handle);
END;

SchedulingJobswithDBMS_JOB
TheOracle-suppliedpackageDBMS_JOBallowsyoutoscheduletheexecutionofa
PL/SQLprocedure.ItwasfirstintroducedinPL/SQLversion2.2.DBMS_JOBisan
OraclePL/SQLpackageprovidedtousers.Ajobissubmittedtoajobqueueandrunsat
thespecifiedtime.Theusercanalsoinputaparameterthatspecifieshowoftenthejob
shouldrun.AjobcanconsistofanyPL/SQLcode.TheDBMS_JOBpackagehas
proceduresforsubmittingjobsforscheduledexecution,executingajobthathasbeen
submittedoutsideofitsschedule,changingtheexecutionparametersofapreviously
submittedjob,suspendingajob,andremovingjobsfromtheschedule(Table24.3).The
primaryreasonsyoumightwanttousethisfeaturewouldbetorunabatchprogram
duringoffhourswhentherearefewerusersloggedintothesystemortomaintainalog.

Table24.3TheMainProceduresintheDBMS_JOBPackage
ThejobqueueisgovernedbytheSNP(SnapshotProcess)processthatrunsinthe
background.Thisprocessisusedtoimplementdatasnapshotsaswellasjobqueues.Ifit
fails,thedatabasewillattempttorestarttheprocess.Thedatabaseinitializationparameter

JOB_QUEUE_PROCESSES(setintheINIT.ORAfileandviewableintheDBAview
V$SYSTEM_PARAMETER)determineshowmanyprocessescanstart.Itmustbesettoa
numbergreaterthan0(thedefaultis0).
WatchOut!
SNPbackgroundprocesseswillnotexecutejobsifthesystemhasbeen
startedinrestrictedmode.Itisexpectedbehaviorforjobsnottobeexecuted
whilethedatabaseisinrestrictedmode.However,youcanusetheALTER
SYSTEMcommandtoturnthisbehavioronandoffasfollows:
Clickheretoviewcodeimage
ALTERSYSTEMENABLERESTRICTEDSESSION;
ALTERSYSTEMDISABLERESTRICTEDSESSION;

SubmittingJobs
AnimportantfirststepwhensubmittingjobstothequeueistoensurethatyourPL/SQL
procedureisvalidandexecutesthewayyouexpectittorun.PriortosubmittingaPL/SQL
procedure,thoroughlytesttheprocedure’sfunctionality.Jobsubmissionassumesyourjob
isvalid.TheSUBMITprocedurewilltakefourINparametersandreturnoneOUT
parameter(Table24.4).TheOUTparameteristhejobnumberofthejobyouhave
submitted.ThisjobnumberisalsovisibleintheDBA_JOBSview.

Table24.4ParametersfortheDBMS_JOB.SUBMITProcedure
ThefollowingexamplewillsubmittheLOG_USER_COUNTprocedure(createdwith
ch24_3.sql)andsetittorunevery6hours.
ForExamplech24_3.sql
Clickheretoviewcodeimage
DECLARE
V_JOB_NONUMBER;
BEGIN
DBMS_JOB.SUBMIT(JOB=>v_job_no,
WHAT-=>‘LOG_USER_COUNT
(”C:\WORKING'’,”USER.LOG”);’,
NEXT_DATE=>SYSDATE,
INTERVAL=>‘SYSDATE+1/4‘);
Commit;

DBMS_OUTPUT.PUT_LINE(v_job_no);
END;

Toseethisjobinthequeue,querytheDBA_JOBview.FortheSTUDENTusertobe
abletoperformthisquery,theDBAneedstoperformthefollowinggrant:
Clickheretoviewcodeimage
GRANTSELECTonDBA_JOBStoSTUDENT;

RunningtheSELECTstatement
Clickheretoviewcodeimage
SELECTJOB,NEXT_DATE,NEXT_SEC,BROKEN,WHAT
FROMDBA_JOBS;

thenproducesthefollowingresult:
Clickheretoviewcodeimage
JOBNEXT_DATENEXT_SECBWHAT
–-–––––—-––––––––––––––—
105-JUL-0316:56:30NLOG_USER_COUNT(‘D:\WORKING’,‘USER.LOG’);

Toforcejobnumber1torunortochange,usetheRUNorCHANGEprocedure.To
removejobnumber1fromthejobqueue,usetheREMOVEprocedure.
Clickheretoviewcodeimage
—executejobnumber1
execdbms_job.run(1);
—removejobnumber1fromthejobqueue
execdbms_job.remove(1);
—changejobnumber1torunimmediatelyandtheneveryhourof
—theday
execDBMS_JOB.CHANGE(1,null,SYSDATE,‘SYSDATE+1/24‘);

Oncethejobhasfailed,itwillbemarkedasbrokeninthejobqueue.Brokenjobsdo
notrun.Youcanalsoforceajobtobeflaggedasbroken.Youmaywanttodothisifyou
haveenteredalltheparameterscorrectlyyetdonotwantthejobtorunonitsnormalcycle
whileyouareinthemiddleofalteringoneofitsdependencies.Youcanthenrunthejob
againbyforcingthebrokenflagoff.
Clickheretoviewcodeimage
—setjob1tobebroken
execdbms_job.BROKEN(1,TRUE);
—setjob1nottobebroken
execdbms_job.BROKEN(1,FALSE);

Whenjobsarerunning,youwillseetheiractivityintheviewDBA_JOBS_RUNNING.
Oncetherunhascompleted,itwillnolongerbevisibleinthisview.
Inthefollowingexample,theprocedureDELETE_ENROLLwilldeleteastudent’s
enrollmentiftherearenogradesintheGRADEtableforthatstudentandthestartdateof
thesectionisalreadyonemonthpastthecurrentsystemdate.
ForExamplech24_4.sql

Clickheretoviewcodeimage
CREATEorREPLACEprocedureDELETE_ENROLL
AS
CURSORC_NO_GRADESis
SELECTst.student_id,se.section_id
FROMstudentst,
enrollmente,
sectionse
WHEREst.student_id=e.student_id
ANDe.section_id=se.section_id
ANDse.start_date_timeANDNOTEXISTS(SELECTg.student_id,g.section_id
FROMgradeg
WHEREg.student_id=st.student_id
ANDg.section_id=se.section_id);
BEGIN
FORRinC_NO_GRADESLOOP
DELETEenrollment
WHEREsection_id=r.section_id
ANDstudent_id=r.student_id;
ENDLOOP;
COMMIT;
EXCEPTION
WHENOTHERSTHEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;

ThefollowingscriptshowshowtosubmittheprocedureDELETE_ENROLLtothejob
queuesothatitwillexecuteonceamonth:
Clickheretoviewcodeimage
SQL>VARIABLEV_JOBNUMBER
SQL>EXECDBMS_JOB.SUBMIT(:v_job,‘DELETE_ENROLL;’,SYSDATE,
‘ADD_MONTHS(SYSDATE,1)’);
PL/SQLproceduresuccessfullycompleted
SQL>commit;
Commitcomplete.
SQL>printv_job
V_JOB
–––2

GeneratinganExplainPlanwithDBMS_XPLAN
TheDBMS_XPLANpackagebecameavailableinOracleversion9.2.Thispackagehelpsto
displaytheexecutionplanofanSQLstatementastheoutputoftheexplainplan
command.Itprovidestheoutputinaneasier-to-understandformatthanwaspossiblein
priorversionsofOracle.TheSQLexecutionplanandruntimestatisticsthatarestoredin
V$SQL_PLAN,V$SQL,andPLAN_STATISTICSaredisplayedwiththeDBMS_XPLAN
package.TheSQLcommandforcreatinganexplainplantakesthisinformationandusesit
topopulatethePLAN_TABLE.Youmustknowagreatdealaboutqueryoptimizationto
makethemosteffectiveuseofanexplainplan.

BytheWay
FordetailsonSQLoptimizationanduseoftheresultsinanexplainplan,see
OracleSQLbyExamplebyAliceRischert(ISBN-10:0137142838;ISBN-13:
978-0137142835).
TheDBMS_XPLANpackagedependsonPLAN_TABLE—atablethatholdstheresults
fromrunninganexplainplanonaSELECTstatement.ThefollowingDDLisusedto
createthePLAN_TABLE:
Clickheretoviewcodeimage
createtablePLAN_TABLE(
statement_idvarchar2(30),
plan_idnumber,
timestampdate,
remarksvarchar2(4000),
operationvarchar2(30),
optionsvarchar2(255),
object_nodevarchar2(128),
object_ownervarchar2(30),
object_namevarchar2(30),
object_aliasvarchar2(65),
object_instancenumeric,
object_typevarchar2(30),
optimizervarchar2(255),
search_columnsnumber,
idnumeric,
parent_idnumeric,
depthnumeric,
positionnumeric,
costnumeric,
cardinalitynumeric,
bytesnumeric,
other_tagvarchar2(255),
partition_startvarchar2(255),
partition_stopvarchar2(255),
partition_idnumeric,
otherlong,
distributionvarchar2(30),
cpu_costnumeric,
io_costnumeric,
temp_spacenumeric,
access_predicatesvarchar2(4000),
filter_predicatesvarchar2(4000),
projectionvarchar2(4000),
timenumeric,
qblock_namevarchar2(30),
other_xmlclob
);

BytheWay
TheRDBMS/ADMIN/subdirectoryunderyourOraclehomedirectorywill
alwayscontainthemostup-to-dateDDLscripttocreateaPLAN_TABLE.
YoucanconnectastheSYSDBAtocreatethistableandmakeitavailableto
allusers.ThefollowingstatementswillcreatethePLAN_TABLEunderthe
SYSschema,createapublicschema,andallowalluserstomakeuseofthe
PLAN_TABLE:
Clickheretoviewcodeimage
SQL>CONNsys/passwordASSYSDBA
Connected
SQL>@$ORACLE_HOME/rdbms/admin/utlxplan.sql
SQL>GRANTALLONsys.plan_tableTOpublic;
SQL>CREATEPUBLICSYNONYMplan_tableFORsys.plan_table;

Bydefault,ifseveralplansintheplantablematchthestatement_idparameterthat
ispassedtothedisplaytablefunction(thedefaultvalueisNULL),onlytheplan
correspondingtothelastEXPLAINPLANcommandisdisplayed.Hence,thereisnoneed
topurgetheplantableaftereachEXPLAINPLANiscreated.However,youshouldpurge
theplantableregularly(forexample,byusingtheTRUNCATETABLEcommand)to
ensuregoodperformanceintheexecutionoftheDISPLAYtablefunction.
InpriorversionsofOracle,anumberofoptionswereavailable.Forexample,youcould
usetheSQL*PluscommandSETAUTOTRACETRACEEXPLAINtogeneratean
immediateexplainplan.
Clickheretoviewcodeimage
SQL>SETAUTOTRACETRACEEXPLAIN
1SELECTs.course_no,
2c.description,
3i.first_name,
4i.last_name,
5s.section_no,
6TO_CHAR(-s.start_date_time,‘Mon-DD-YYYYHH:MIAM’),
7s.location
8FROMsections,
9coursec,
10instructori
11WHEREs.course_no=c.course_no
12*ANDs.instructor_id=i.instructor_id
ExecutionPlan
––––––––––––––––––––0SELECTSTATEMENTOptimizer=CHOOSE(Cost=9Card=78Bytes=4368)
10HASHJOIN(Cost=9Card=78Bytes=4368)
21HASHJOIN(Cost=6Card=78Bytes=2574)
32TABLEACCESS(FULL)OF‘INSTRUCTOR’(Cost=3Card=10Bytes=140)
42TABLEACCESS(FULL)OF‘SECTION’(Cost=3Card=78Bytes=1482)
51TABLEACCESS(FULL)OF‘COURSE’(Cost=3Card=30Bytes=690)

YoucanalsogenerateanexplainplanthatwillbestoredinthePLAN_TABLEandthen
querytheresultsofanexplainplan.

Clickheretoviewcodeimage
SQL>explainplanfor
2SELECTs.course_no,
3c.description,
4i.first_name,
5i.last_name,
6s.section_no,
7TO_CHAR(s.start_date_time,‘Mon-DD-YYYYHH:MIAM’),
8s.location
9FROMsections,
10coursec,
11instructori
12WHEREs.course_no=c.course_no
13ANDs.instructor_id=i.instructor_id;
Explained.
selectrtrim(lpad(‘‘,2*level)||
rtrim(operation)||‘‘||
rtrim(options)||‘‘||
object_name||‘‘||
partition_start||‘‘||
partition_stop||‘‘||
to_char(partition_id)
)the_query_plan
fromplan_table
connectbypriorid=parent_id
startwithid=0;

THE_QUERY_PLAN
–––––––––––––—
SELECTSTATEMENT
HASHJOIN
HASHJOIN
TABLEACCESSBYINDEXROWIDSECTION
INDEXFULLSCANSECT_INST_FK_I
SORTJOIN
TABLEACCESSFULLINSTRUCTOR
TABLEACCESSFULLCOURSE

TomakeuseoftheDBMS_XPLANprocedure,usetheSELECT*FROM
TABLE(DBMS_XPLAN.DISPLAY)commandtogeneratetheexplainplan.
Clickheretoviewcodeimage
SQL>explainplanfor
2SELECTs.course_no,
3c.description,
4i.first_name,
5i.last_name,
6s.section_no,
7TO_CHAR(s.start_date_time,‘Mon-DD-YYYYHH:MIAM’),
8s.location
9FROMsections,
10coursec,
11instructori
12WHEREs.course_no=c.course_no
13ANDs.instructor_id=i.instructor_id;

Explained.
SQL>SELECT*FROMTABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
–––––––––––––––––––––––––––
–––––––––––––––––––––––––––
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|
Time|
–––––––––––––––––––––––––––
|0|SELECTSTATEMENT||78|4368|9(34)|
*00:00:01|
|*1|HASHJOIN||78|4368|9(34)|
00:00:01|
|*2|HASHJOIN||78|2574|6(34)|
00:00:01|
|3|TABLEACCESSFULL|INSTRUCTOR|10|140|3(34)|
00:00:01|
|4|TABLEACCESSFULL|SECTION|78|1482|3(34)|
00:00:01|
|5|TABLEACCESSFULL|COURSE|30|690|3(34)|
00:00:01|
–––––––––––––––––––––––––––
PredicateInformation(identifiedbyoperationid):
–––––––––––––––––
1-access(“S”.“COURSE_NO”=“C”.“COURSE_NO”)
2-access(“S”.“INSTRUCTOR_ID”=“I”.“INSTRUCTOR_ID”)
17rowsselected.

GeneratingImplicitStatementResultswithDBMS_SQL
InolderversionsofOracle,therewereafewoperationsavailableinotherdatabase
productssuchasMicrosoftSQLServerthatcouldnotbedoneaselegantlyintheOracle
platform.Thiscreatedachallengeforcompaniesthatweremigratingtheirapplicationsto
Oraclebecausetheywouldhavetomakeagreatmanychangestotheirstoredprocedures
—evenrewritethem—foruseontheOracleplatform.Considertheabilitytopassthe
resultsofaSQLstatementoutofastoredprocedure.Thiscanbedonerathereasilywith
theTransactSQL(T-SQL)procedurallanguageofSQLServer,butintheOracleplatform
ithadtobedonewithaREFCURSORparameter.ThisisbecauseT-SQLsyntaxpermits
implicitreturnsofaSQLresultsetfromqueries.Asimilarkindoffunctionalityisnow
allowedinOracle12cthroughuseoftheDBMS_SQLpackageandtheRETURN_RESULT
procedureinthatsystempackage.
UsingDBMS_SQLtoReturnaResultSet
TheOracle-suppliedpackageDBMS_SQLincludesanentitycalledaSQLcursornumber.
ThisPL/SQLintegercanbepassedasanINorOUTparameter.Youshouldusethe
DBMS_SQLpackagetorundynamicSQLwhenyoudon’tknowthedetailsofthe
SELECTstatementuntilitisrunoryoudon’tknowwhichcolumnswillbecalledinthe
SELECTstatementuntilitisrun.