wOracle8 PL/SQLvO~OxR[hof[^
 Chapter 1`Last
R[hƃR[h̋؂͋󔒍s3sĂ܂B

Chapter 1
DELETE FROM students
  WHERE major = 'Nutrition';



LOOP over each student record
  IF this record has major = 'Nutrition' THEN
    DELETE this record;
  END IF;
END LOOP;



-- Available online as 3gl_4gl.sql
DECLARE
  /* SQLŎgpϐ̐錾 */
  v_NewMajor VARCHAR2(10) := 'History'; 
  v_FirstName VARCHAR2(10) := 'Scott'; 
  v_LastName VARCHAR2(10) := 'Urman'; 
BEGIN
  /* \students̍XV */
  UPDATE students
    SET major = v_NewMajor
    WHERE first_name = v_FirstName
    AND last_name = v_LastName; 
  /* R[hA`FbNBȂꍇɂ́A
     YR[h}KvB */
  IF SQL%NOTFOUND THEN
    INSERT INTO students (ID, first_name, last_name, major) 
      VALUES (students_sequence.NEXTVAL, v_FirstName, v_LastName, v_NewMajor); 
  END IF; 
END;



DECLARE
/*錾ZNV | ɂ́APL/SQL̕ϐA^AJ[\Aу[JȃTuvOLq܂B*/
BEGIN
/*s\ZNV | ɂ́A葱SQLLq܂BꂪubÑCZNVłAB̕K{ZNVłB*/
EXCEPTION
/*OZNV | ɂ́AG[p̕Lq܂B*/
END;



-- Available online as error.sql
DECLARE
  v_ErrorCode NUMBER;          -- G[R[h
  v_ErrorMsg  VARCHAR2(200);   -- G[̃bZ[WeLXg
  v_CurrentUser VARCHAR2(8);   -- ݂̃f[^x[X[U
  v_Information VARCHAR2(100); -- G[Ɋւ
BEGIN
/*f[^sR[h*/
 .... 
EXCEPTION
  WHEN OTHER THEN
  v_ErrorCode := SQLCODE; 
  v_ErrorMsg := SQLERRM; 
  v_CurrentUser := USER; 
  -- gݍ݊֐gpāAOϐɒl
  v_Information := 'Error encountered on ' ||
    TO_CHAR(SYSDATE) || ' by database user ' || v_CurrentUser; 
  -- log_tableɃObZ[W}
  INSERT INTO log_table (code, message, info) 
    VALUES (v_ErrorCode, v_ErrorMsg, v_information); 
END; 



DECLARE
  v_StudentName  VARCHAR2(20);
  v_CurrentDate  DATE;
  v_NumberCredits NUMBER(3);



DECLARE
  v_LoopCounter BINARY_INTEGER;
  v_CurrentlyRegistered BOOLEAN;



DECLARE
  TYPE t_StudentRecord IS RECORD (
    FirstName  VARCHAR2(10),
    LastName   VARCHAR2(10),
    CurrentCredits NUMBER(3)
  );
  v_Student t_StudentRecord;



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE StudentObj AS OBJECT (
  ID               NUMBER(5),
  first_name       VARCHAR2(20),
  last_name        VARCHAR2(20),
  major            VARCHAR2(30),
  current_credits  NUMBER(3),

  -- ƐXy[Xŋ؂ĕԂB
  MEMBER FUNCTION FormattedName
    RETURN VARCHAR2,
  PRAGMA RESTRICT_REFERENCES(FormattedName, RNDS, WNDS, RNPS, WNPS),

  -- p_NewMajorɎw肳ꂽlɐUXVB
  MEMBER PROCEDURE ChangeMajor(p_NewMajor IN VARCHAR2),
  PRAGMA RESTRICT_REFERENCES(ChangeMajor, RNDS, WNDS, RNPS, WNPS),

  -- p_CompletedClass݂̐̒lɑāAcurrent_creditsXVB
  MEMBER PROCEDURE UpdateCredits(p_CompletedClass IN ClassObj),
  PRAGMA RESTRICT_REFERENCES(UpdateCredits, RNDS, WNDS, RNPS, WNPS)
);



-- Available online as simple.sql
DECLARE
  v_LoopCounter BINARY_INTEGER := 1; 
BEGIN
  LOOP
    INSERT INTO temp_table (num_col) 
      VALUES (v_LoopCounter); 
    v_LoopCounter := v_LoopCounter + 1; 
    EXIT WHEN v_LoopCounter > 50; 
  END LOOP; 
END;



-- Available online as numeric.sql
BEGIN
  FOR v_LoopCounter IN 1..50 LOOP
    INSERT INTO temp_table (num_col) 
      VALUES (v_LoopCounter); 
  END LOOP; 
END;



-- Available online as cursor.sql
DECLARE
  v_FirstName VARCHAR2(20); 
  v_LastName  VARCHAR2(20); 
  -- J[\錾BA̍sԂ߂SQL`
  CURSOR c_Students IS
    SELECT first_name, last_name
      FROM students; 
BEGIN
  -- J[\̊Jn
  OPEN c_Students; 
  LOOP
    -- Pso
    FETCH c_Students INTO v_FirstName, v_LastName; 
    -- ׂĂ̍soIA[vI
    EXIT WHEN c_Students%NOTFOUND; 
    /* ŁAf[^ */
  END LOOP; 
  -- ̏I
  CLOSE c_Students; 
END; 



ڑ:
Personal Oracle7 Release 7.3.2.3.1 - Production Release
With the distributed and replication options
PL/SQL Release 2.3.2.3.0 - Production



ڑ:
Oracle8 Server Release 8.0.3.0.0 - Production Release
With the distributed, heterogeneous,replication,objects, parallel query and Spatial Data options
PL/SQL Release 8.0.3.0.0 - Production



CREATE SEQUENCE student_sequence
  START WITH 10000
  INCREMENT BY 1;



CREATE TABLE students (
  id               NUMBER(5) PRIMARY KEY,
  first_name       VARCHAR2(20),
  last_name        VARCHAR2(20),
  major            VARCHAR2(30),
  current_credits  NUMBER(3)
  );

INSERT INTO students (id, first_name, last_name, major,
                      current_credits)
  VALUES (student_sequence.NEXTVAL, 'Scott', 'Smith',
          'Computer Science', 0);

INSERT INTO students (id, first_name, last_name, major,
                      current_credits)
  VALUES (student_sequence.NEXTVAL, 'Margaret', 'Mason',
          'History', 0);

INSERT INTO students (id, first_name, last_name, major,
                      current_credits)
  VALUES (student_sequence.NEXTVAL, 'Joanne', 'Junebug',
         'Computer Science', 0);

INSERT INTO students (id, first_name, last_name, major,
                      current_credits)
  VALUES (student_sequence.NEXTVAL, 'Manish', 'Murgratroid',
          'Economics', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES(student_sequence.NEXTVAL, 'Patrick', 'Poll',
         'History', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES (student_sequence.NEXTVAL, 'Timothy', 'Taller',
          'History', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES (student_sequence.NEXTVAL, 'Barbara', 'Blues',
          'Economics', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES (student_sequence.NEXTVAL, 'David', 'Dinsmore',
          'Music', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES (student_sequence.NEXTVAL, 'Ester', 'Elegant',
          'Nutrition', 0);

INSERT INTO students(id, first_name, last_name, major,
                     current_credits)
  VALUES (student_sequence.NEXTVAL, 'Rose', 'Riznit',
          'Music', 0);

INSERT INTO STUDENTS(id, first_name, last_name, major,
                     current_credits)

  VALUES (student_sequence.NEXTVAL, 'Rita', 'Razmataz',
          'Nutrition', 0);



CREATE TABLE major_stats (
  major          VARCHAR2(30),
  total_credits  NUMBER,
  total_students NUMBER);



CREATE TABLE rooms (
  room_id          NUMBER(5) PRIMARY KEY,
  building         VARCHAR2(15),
  room_number      NUMBER(4),
  number_seats     NUMBER(4),
  description      VARCHAR2(50)
  );

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99999, 'Building 7', 310, 1000, 'Large Lecture Hall');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99998, 'Building 6', 101, 500, 'Small Lecture Hall');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99997, 'Building 6', 150, 50, 'Discussion Room A');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99996, 'Building 6', 160, 50, 'Discussion Room B');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99995, 'Building 6', 170, 50, 'Discussion Room C');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99994, 'Music Building', 100, 10, 'Music Practice Room');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99993, 'Music Building', 200, 1000, 'Concert Room');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99992, 'Building 7', 300, 75, 'Discussion Room D');

INSERT INTO rooms
  (room_id, building, room_number, number_seats, description)
  VALUES (99991, 'Building 7', 310, 50, 'Discussion Room E');



CREATE TABLE classes (
  department       CHAR(3),
  course           NUMBER(3),
  description      VARCHAR2(2000),
  max_students     NUMBER(3),
  current_students NUMBER(3),
  num_credits      NUMBER(1),
  room_id          NUMBER(5),
  CONSTRAINT classes_department_course
    PRIMARY KEY (department, course),
  CONSTRAINT classes_room_id
    FOREIGN KEY (room_id) REFERENCES rooms (room_id)
  );

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('HIS', 101, 'History 101', 30, 0, 4, 99999);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('HIS', 301, 'History 301', 30, 0, 4, 99995);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('CS', 101, 'Computer Science 101', 50, 0, 4, 99998);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('ECN', 203, 'Economics 203', 15, 0, 3, 99997);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('CS', 102, 'Computer Science 102', 35, 0, 4, 99996);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('MUS', 410, 'Music 410', 5, 0, 3, 99994);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('ECN', 101, 'Economics 101', 50, 0, 4, 99992);

INSERT INTO classes
  (department, course, description, max_students,
   current_students, num_credits, room_id)
  VALUES ('NUT', 307, 'Nutrition 307', 20, 0, 4, 99991);



CREATE TABLE registered_students (
  student_id NUMBER(5) NOT NULL,
  department CHAR(3)   NOT NULL,
  course     NUMBER(3) NOT NULL,
  grade      CHAR(1),
  CONSTRAINT rs_grade
    CHECK (grade IN ('A', 'B', 'C', 'D', 'E')),
  CONSTRAINT rs_student_id
    FOREIGN KEY (student_id) REFERENCES students (id),
  CONSTRAINT rs_department_course
    FOREIGN KEY (department, course)
    REFERENCES classes (department, course)
  );

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10000, 'CS', 102, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10002, 'CS', 102, 'B');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10003, 'CS', 102, 'C');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10000, 'HIS', 101, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10001, 'HIS', 101, 'B');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10002, 'HIS', 101, 'B');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10003, 'HIS', 101, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10004, 'HIS', 101, 'C');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10005, 'HIS', 101, 'C');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10006, 'HIS', 101, 'E');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10007, 'HIS', 101, 'B');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10008, 'HIS', 101, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10009, 'HIS', 101, 'D');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10010, 'HIS', 101, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10008, 'NUT', 307, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10010, 'NUT', 307, 'A');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10009, 'MUS', 410, 'B');

INSERT INTO registered_students
  (student_id, department, course, grade)
  VALUES (10006, 'MUS', 410, 'E');



CREATE TABLE RS_audit (
  change_type    CHAR(1)     NOT NULL,
  changed_by     VARCHAR2(8) NOT NULL,
  timestamp      DATE        NOT NULL,
  old_student_id NUMBER(5),
  old_department CHAR(3),
  old_course     NUMBER(3),
  old_grade      CHAR(1),
  new_student_id NUMBER(5),
  new_department CHAR(3),
  new_course     NUMBER(3),
  new_grade      CHAR(1)
  );



CREATE TABLE log_table (
  code             NUMBER,
  message          VARCHAR2(200),
  info             VARCHAR2(100)
  );



CREATE TABLE temp_table (
  num_col    NUMBER,
  char_col   VARCHAR2(60)
  );



CREATE TABLE debug_table (
  linecount  NUMBER,
  debug_str  VARCHAR2(100)
  );



Chapter 2
-- Available online as anon.sql
DECLARE
  /* ubNŎgpϐ̐錾 */
  v_Num1      NUMBER := 1;
  v_Num2      NUMBER := 2;
  v_String1   VARCHAR2(50) := '₠Aɂ!';
  v_String2   VARCHAR2(50) := '-- ̃bZ[WPL/SQL 
                               ͂ꂽ̂łB';
  v_OutputStr VARCHAR2(50);
BEGIN
  /* ܂Aϐ̒lgpāAtemp_table2s}B*/
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num1, v_String1);
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num2, v_String2);
  
  /* temp_table₢킹āA}΂2soADBMS_OUTPUTpbP[Wgpĉʂɏo͂B */
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num1;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
  
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num2;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
END;



-- Available online as labeled.sql
<<l_InsertIntoTemp>>
DECLARE
  /* ubNŎgpϐ̐錾 */
  v_Num1      NUMBER := 3;
  v_Num2      NUMBER := 4;
  v_String1   VARCHAR2(50) := '₠Aɂ!';
  v_String2   VARCHAR2(50) := '-- ̃bZ[WPL/SQL 
                               ͂ꂽ̂łB';
  v_OutputStr VARCHAR2(50);
BEGIN
  /* ܂Aϐ̒lgpāAtemp_table2s}B */
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num1, v_String1);
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num2, v_String2);
  
  /* temp_table₢킹āA}΂2soADBMS_OUTPUTpbP[Wgpĉʂɏo͂B */
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num1;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
  
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num2;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
END l_InsertIntoTemp;



-- Available online as proc.sql
CREATE OR REPLACE PROCEDURE InsertIntoTemp AS
  /* ubNŎgpϐ̐錾 */
  v_Num1      NUMBER := 5;
  v_Num2      NUMBER := 6;
  v_String1   VARCHAR2(50) := '₠Aɂ!';
  v_String2   VARCHAR2(50) := '-- ̃bZ[WPL/SQL 
                               ͂ꂽ̂łB';
  v_OutputStr VARCHAR2(50);
BEGIN
  /* ܂Aϐ̒lgpāAtemp_table2s}B */
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num1, v_String1);
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_Num2, v_String2);
  
  /* temp_table₢킹āA}΂2soADBMS_OUTPUTpbP[Wgpĉʂɏo͂B */
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num1;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
  
  SELECT char_col
    INTO v_OutputStr
  FROM temp_table
  WHERE num_col = v_Num2;
  DBMS_OUTPUT.PUT_LINE(v_OutputStr);
END InsertIntoTemp;



-- Available online as trigger.sql
CREATE OR REPLACE TRIGGER OnlyPositive
  BEFORE INSERT OR UPDATE OF num_col
  ON temp_table
  FOR EACH ROW
BEGIN
  IF :new.num_col < 0 THEN
    RAISE_APPLICATION_ERROR(-20100, 'Please insert a positive value');
  END IF;
END OnlyPositive;



-- Available online as allthree.sql
DECLARE
  /* s\ZNV̊Jn */  
  v_StudentID NUMBER(5) := 10000;  -- ϐ10,000ŏ
  v_FirstName VARCHAR2(20);        -- ϐl̕񒷂́Aő20
BEGIN
  /* s\ZNV̊Jn */
  -- ID10,000̊w̖OoB
  SELECT first_name
    INTO v_FirstName
    FROM students
    WHERE = V_StudentID; 
EXCEPTION
  /* OZNV̊Jn */
  WHEN NO_DATA_FOUND THEN
  -- G[̏
    INSERT INTO log_table (info) 
      VALUES ('Student 10,000 dose not exist!'); 
END;



DECLARE
   /* 錾ZNV */
BEGIN
   /* s\ZNV */
EXCEPTION
   /* OZNV */
END; 



BEGIN
   /* s\ZNV */
END;



DECLARE
   /* 錾ZNV */
BEGIN
   /* s\ZNV */
END;



x
v_StudentID
TempVar
v1
v2_
social_security_#



x+y                               -- +́AȕB
_temp_                            -- 擪́AAt@xbgłȂ΂ȂȂB
                                     A_[XRAł͂ȂB
First Name                        -- 󔒂́AB
This_is_a_really_long_identifier  -- 30𒴂ĂB
1_variable                        -- 擪ł͂ȂB



Room_Description
room_description
ROOM_DESCRIPTION
rOOm_DEscriPTIOn



DECLARE
  begin number;



DECLARE
  v_BeginDate  DATE;



"A number"
"Linda's variable"
"x/y"
"X/Y"



DECLARE
  v_Exception   VARCHAR2(10);
BEGIN
  SELECT "EXCEPTION"
    INTO v_Exception
    FROM exception_table;
END;




-- Available online as part of tables.sql
CREATE TABLE exception_table (
  exception      VARCHAR2(20),
  date_occurred  DATE);



CREATE VIEW exception_view AS
     SELECT exception  exception_description,
            date_occurred
       FROM exception_table;



'12345'
'Four score and seven years ago...'
'100%'
'"'



'Mike''s string



''''



''



123
-7
+12
0



-17.1
23.0
3.



1.345E7
9.87E-3
-7.12e+12



1.345E7 = 1.345~i107j
        = 1.345~10,000,000
        = 13,450,000
9.87E-3 = 9.87~i10-3j
        = 9.87~.001
        = 0.00987
-7.12e+12 = -7.12~i1012j
          = -7.12~1,000,000,000,000
          = -7,120,000,000,000



-- Available online as part of comments.sql
DECLARE
  v_Department  CHAR(3);
  v_Course      NUMBER;
BEGIN
  INSERT INTO classes (department, course)
    VALUES (v_Department, v_Course);
END;



-- Available online as part of comments.sql
DECLARE
  v_Department  CHAR(3);  -- 3̊wR[h
                          -- i[邽߂̕ϐB
  v_Course      NUMBER;   -- wȔԍi[邽߂̕ϐB
BEGIN
  -- v_Departmentv_CourseŎw肵wȂ
  -- f[^x[X̕\classesɑ}B
  INSERT INTO classes (department, course)
    VALUES (v_Department, v_Course);
END;



-- Available online as part of comments.sql
DECLARE
  v_Department  CHAR(3); /* 3̊w
                            i[邽߂̕ϐ */
  v_Course      NUMBER;  /* wȔԍi[邽߂̕ϐ */
BEGIN
  /* v_Departmentv_CourseŎw肵wȂ
     f[^x[X̕\classesɑ} */
  INSERT INTO classes (department, course)
    VALUES (v_Department, v_Course);
END;



-- Available online as part of comments.sql
BEGIN
  /* ́ARg̓łB/* ̂悤 */ ʂ̃Rgr
   Jn̂́AłB */
  NULL;
END;



DECLARE
  v_Description     VARCHAR2(50);
  v_NumberSeats     NUMBER := 45;
  v_Counter         BINARY_INTEGER := 0;



DECLARE
  v_TempVar  NUMBER NOT NULL;



DECLARE
  v_TempVar  NUMBER NOT NULL := 0;




DECLARE
  c_MinimumStudentID  CONSTANT NUMBER(5) := 10000;



DECLARE
  v_NumberSeats  NUMBER DEFAULT 45;
  v_Counter      BINARY_INTEGER DEFAULT 0;
  v_FirstName    VARCHAR2(20) DEFAULT 'Scott';



DECLARE
  v_FirstName, v_LastName  VARCHAR2(20);



DECLARE
  v_FirstName VARCHAR2(20);
  v_LastName  VARCHAR2(20);



BBBBBBBB.RRRR.FFFF



0000001E.00FF.0001



DECLARE
  v_ContinueFlag  BOOLEAN := 0;



DECLARE
  v_FirstName    VARCHAR2(20);



DECLARE
  v_FirstName  VARCHAR2(25);



DECLARE
  v_FirstName  students.first_name%TYPE;



DECLARE
  v_RoomID     classes.room_id%TYPE;  -- NUMBER(5)ԂB
  v_RoomID2    v_RoomID%TYPE;         -- NUMBER(5)ԂB
  v_TempVar    NUMBER(7,3) NOT NULL := 12.3;
  v_AnotherVar v_TempVar%TYPE;        -- NUMBER(7,3)ԂB



DECLARE
  SUBTYPE t_LoopCounter IS NUMBER;  -- VTu^Cv̒`B
  v_LoopCounter   t_LoopCounter;    -- YTu^Cv
                                    -- ϐ錾B
  SUBTYPE t_NameType IS students.first_name%TYPE;



DECLARE
  SUBTYPE t_LoopCounter IS NUMBER(4);  -- ȐB



DECLARE
  v_DummyVar  NUMBER(4);  -- _~[̕ϐB̕ϐ́Aۂɂ͎gpȂB
  SUBTYPE t_LoopCounter is v_DummyVar%TYPE;  -- NUMBER(4)ԂB
  v_Counter  t_LoopCounter;



DECLARE
  SUBTYPE  t_Numeric IS NUMBER; -- ̂ȂTu^Cv̒`B
  v_Counter is t_Numeric(5);    -- Aϐɂ݂͐B 



DECLARE
  v_CurrentCredits  VARCHAR2(5);
BEGIN
  SELECT current_credits
    INTO v_CurrentCredits
    FROM students
    WHERE id = 10002;
END;



DECLARE
  v_CurrentCredits  VARCHAR2(5);
BEGIN
  SELECT TO_CHAR(current_credits)
    INTO v_CurrentCredits
    FROM students
    WHERE id = 10002;
END;



I_Outer.v_SSN



DECLARE
  v_String1  VARCHAR2(10);
  v_String2  VARCHAR2(15);
  v_Numeric  NUMBER;
BEGIN
  v_String1 := 'Hello';
  v_String2 := v_String1;
  v_Numeric := -12.4;
END;



DECLARE
  v_Val1 NUMBER;
  v_Val2 NUMBER;
  v_Val3 NUMBER;
BEGIN
  v_Val1 := v_Val2 := v_Val3 := 0;
END;



3 + 5 * 7



(3 + 5) * 7



'Hello ' || 'World' || '!'



'Hello World!'



DECLARE
  v_TempVar  VARCHAR2(10) := 'PL';
  v_Result   VARCHAR2(20);
BEGIN
  v_Result := v_TempVar || '/SQL';
END;



X > Y
NULL
(4 > 5) OR (-1 != Z)



TRUE AND NULL



'Scott' LIKE 'Sc%t'


'Scott' LIKE 'Sc_tt'


'Scott' LIKE '%'



100 BETWEEN 110 AND 120



100 BETWEEN 90 AND 110



'Scott' IN ('Mike', 'Pamela', 'Fred')



-- Available online as if1.sql
DECLARE
  v_NumberSeats rooms.number_seats%TYPE;
  v_Comment VARCHAR2(35);
BEGIN
  /* 99999ƂIDŎw肵̍ȐoB
     ʂ́Av_NumberSeatsɊi[B */
  SELECT number_seats
    INTO v_NumberSeats
    FROM rooms
    WHERE room_id = 99999;
  IF v_NumberSeats < 50 THEN
    v_Comment := 'Fairly small';
  ELSIF v_NumberSeats < 100 THEN
    v_Comment := 'A little bigger';
  ELSE
    v_Comment := 'Lots of room';
  END IF;
END;



v_NumberSeats < 50



v_Comment := 'Fairly small';



v_NumberSeats < 100



v_Comment := 'A little bigger';



v_Comment := 'Lots of room';



-- Available online as if2.sql
DECLARE
  v_NumberSeats rooms.number_seats%TYPE;
  v_Comment VARCHAR2(35);
BEGIN
  /* 99999ƂIDŎw肵̍ȐoB
     ʂ́Av_NumberSeatsɊi[B */
  SELECT number_seats
    INTO v_NumberSeats
    FROM rooms
    WHERE room_id = 99999;
  IF v_NumberSeats < 50 THEN
    v_Comment := 'Fairly small';
    INSERT INTO temp_table (char_col)
      VALUES ('Nice and cozy');
  ELSIF v_NumberSeats < 100 THEN
    v_Comment := 'A little bigger';
    INSERT INTO temp_table (char_col)
      VALUES ('Some breathing room');
  ELSE
    v_Comment := 'Lots of room';
  END IF;
END;



/* ubN1 */
DECLARE 
  v_Number1 NUMBER;
  v_Number2 NUMBER;
  v_Result  VARCHAR2(7); 
BEGIN 
  ... 
  IF v_Number1 < v_Number2 THEN
    v_Result := 'Yes';
  ELSE
    v_Result := 'No'; 
  END IF; 
END;


/* ubN2 */
 DECLARE
v_Number1 NUMBER;
v_Number2 NUMBER;
v_Result VARCHAR2(7);
BEGIN
  ...
  IF v_Number1 >= v_Number2 THEN
    v_Result := 'No';
  ELSE 
    v_Result := 'Yes';
  END IF; 
END;



/* ubN1 */
DECLARE 
  v_Number1 NUMBER; 
  v_Number2 NUMBER; 
  v_Result  VARCHAR2(7); 
BEGIN 
  ... 
  IF v_Number1 IS NULL OR 
       v_Number2 IS NULL THEN 
    v_Result := 'Unknown';
  ELSIF v_Number1 < v_Number2 THEN
    v_Result := 'Yes'; 
  ELSE
    v_Result := 'No'; 
  END IF;
END;


/* ubN2 */
DECLARE
  v_Number1 NUMBER;
  v_Number2 NUMBER;
  v_Result VARCHAR2(7);
BEGIN
 ...
 IF v_Number1 IS NULL OR
      v_Number2 IS NULL THEN
    v_Result := 'Unknown';
  ELSIF v_Number1 >= v_Number2 THEN
    v_Result := 'No';
  ELSE
    v_Result := 'Yes';
  END IF;
 END;



-- Available online as simple.sql
DECLARE
  v_Counter BINARY_INTEGER := 1;
BEGIN
  LOOP
    -- [vJE^̌ݒls
    -- temp_tableɑ}
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop index');
    v_Counter := v_Counter + 1;
    -- Ii[vJE^ >50 j
    -- [v𔲂
    IF v_Counter > 50 THEN
      EXIT;
    END IF;
  END LOOP;
END;



-- Available online as exitwhen.sql
DECLARE
  v_Counter BINARY_INTEGER := 1;
BEGIN
  LOOP
    -- [vJE^̌ݒls
    -- temp_tableɑ}
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop index');
    v_Counter := v_Counter + 1;
    -- Ii[vJE^ >50 j
    -- [v𔲂
    EXIT WHEN v_Counter > 50;
  END LOOP;
END;



-- Available online as while1.sql
DECLARE
  v_Counter BINARY_INTEGER := 1;
BEGIN
  -- [v̊esOɁA[vJE^50ȉł邩
  -- eXg
  WHILE v_Counter <= 50 LOOP
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop index');
    v_Counter := v_Counter + 1;
  END LOOP;
END;



-- Available online as while2.sql
DECLARE
  v_Counter BINARY_INTEGER;
BEGIN
  -- v_Counter̓fBtHglNULLɂď邽
  -- ̏NULLɕ]
  WHILE v_Counter <= 50 LOOP
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop index');
    v_Counter := v_Counter + 1;
  END LOOP;
END;



-- Available online as forloop.sql
BEGIN
  FOR v_Counter IN 1..50 LOOP
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop Index');
  END LOOP;
END;



-- Available online as forscope.sql
DECLARE
  v_Counter  NUMBER := 7;
BEGIN
  -- temp_tableɒl7}
  INSERT INTO temp_table (num_col)
    VALUES (v_Counter);
  -- ̃[vł́Av_CounterBINARY_INTEGERƂĐ錾
  -- ɂANUMBER^ƂĐ錾v_Counter͉B
  FOR v_Counter IN 20..30 LOOP
    -- v_Counter̒ĺA[v2030ɕω
    INSERT INTO temp_table (num_col)
      VALUES (v_Counter);
  END LOOP;
  -- temp_tableɒl7P}
  INSERT INTO temp_table (num_col)
    VALUES (v_Counter);
END;



BEGIN
  FOR v_Counter in REVERSE 10..50 LOOP
    -- v_Counter50n܂A[v𔽕邽т
    -- 1ZB
    NULL;
  END LOOP;
END;



DECLARE
  v_LowValue  NUMBER := 10;
  v_HighValue NUMBER := 40;
BEGIN
  FOR v_Counter IN REVERSE v_LowValue .. v_HighValue LOOP
    INSERT INTO temp_table
      VALUES (v_Counter, 'Dynamically specified loop ranges');
  END LOOP;
END;



-- Available online as goto.sql
DECLARE
  v_Counter  BINARY_INTEGER := 1;
BEGIN
  LOOP
    INSERT INTO temp_table
      VALUES (v_Counter, 'Loop count');
    v_Counter := v_Counter + 1;
    IF v_Counter > 50 THEN
      GOTO l_EndOfLoop;
    END IF;
  END LOOP;

  <<l_EndOfLoop>>
  INSERT INTO temp_table (char_col)
    VALUES ('Done!');
END;



BEGIN
  GOTO l_InnerBlock;  -- B̃ubNɂ̓u`łȂB
  BEGIN
    ...
    <<l_InnerBlock>>
    ...
  END;

  GOTO l_InsideIf;  -- BIF̒ɂ̓u`łȂB
  IF x > 3 THEN
    ...
    <<l_InsideIf>>
    INSERT INTO ...
  END IF;
END;



BEGIN
  IF x > 3 THEN
    ...
    GOTO l_NextCondition;
  ELSE
    <<l_NextCondition>>
    ...
  END IF;
END;



DECLARE
  v_Room  rooms%ROWTYPE;
BEGIN
  -- \roomss1soB
  SELECT *
    INTO v_Room
    FROM rooms
    WHERE rowid = 1;
  <<l_Insert>>
  INSERT INTO temp_table (char_col)
    VALUES ('Found a row!');
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    GOTO l_Insert;  -- B݂̃ubNɃu`Ŗ߂邱Ƃ͂łȂB
END;



BEGIN
  <<l_Outer>>
  FOR v_OuterIndex IN 1..50 LOOP
    ...
    <<l_Inner>>
    FOR v_InnerIndex IN 2..10 LOOP
      ...
      IF v_OuterIndex > 40 THEN
        EXIT l_Outer; -- ̃[vIB
      END IF;
    END LOOP l_Inner;
END LOOP l_Outer;



-- Available online as null.sql
DECLARE
  v_TempVar  NUMBER := 7;
BEGIN
  IF v_TempVar < 5 THEN
    INSERT INTO temp_table (char_col)
      VALUES ('Too small');
  ELSIF v_TempVar < 10 THEN
    INSERT INTO temp_table (char_col)
      VALUES ('Just right');
  ELSE
    NULL; -- sȂB
  END IF;
END;



declare
x number;
y number;
begin if x < 10 then y := 7; else y := 3; end if; end;


DECLARE
  v_Test   NUMBER;  -- eXgΏۂϐ
  v_Result NUMBER;  -- eXgʂ̊i[ƂȂϐ
BEGIN
  -- v_TesteXgAv_Test < 10̏ꍇv_Result7B
  IF v_Test < 10 THEN
    v_Result := 7;
  ELSE
    v_Result := 3;
  END IF;
END;



DECLARE
  v_Temp NUMBER := 0;  -- v_Temp0B



DECLARE
  v_Temp NUMBER := 0;  -- C[vňꎞIɎgϐB



x number;



v_StudentID  NUMBER(5);



v_VariableName     vOϐ
e_ExceptionName    [U[`̗O
t_TypeName         [U[`̌^
p_ParameterName    vV[W܂͊֐ɓnp[^
c_ConstantValue    CONSTANTɐϐ



IF x < y THEN IF z IS NULL THEN x := 3; ELSE x := 2; END IF; ELSE x := 4; END IF;


IF x < y THEN
  IF z IS NULL THEN
    x := 3;
  ELSE 
    x := 2;
  END IF;
ELSE
  x := 4;
END IF;



SELECT id, first_name, last_name
  INTO v_StudentID, v_FirstName, v_LastName
  FROM STUDENTS
  WHERE id = 10002;



Chapter 3
DECLARE
  v_StudentID  NUMBER(5);
  v_FirstName  VARCHAR2(20);
  v_LastName   VARCHAR2(20);



DECLARE
  /* wɋʂȏi[邽߂̃R[h^̒` */
  TYPE t_StudentRecord IS RECORD (
    StudentID  NUMBER(5),
    FirstName  VARCHAR2(20),
    LastName   VARCHAR2(20));

  /* Y^̕ϐ錾 */
  v_StudentInfo  t_StudentRecord



DECLARE
  TYPE t_SampleRecord IS RECORD (
    Count          NUMBER(4),
    Name           VARCHAR2(10) := 'Scott',
    EffectiveDate  DATE,
    Description    VARCHAR2(45) NOT NULL := 'Unknown');
  v_Sample1  t_SampleRecord;
  v_Sample2  t_SampleRecord;



BEGIN
  /* SYSDATÉA݂̓tƎԂ
     gݍ݊֐łB*/
  v_Sample1.EffectiveDate := SYSDATE;
  v_Sample2.Description := 'Pesto Pizza';
END;



v_Sample1 := v_Sample2;



-- Available online as assign.sql
DECLARE
  TYPE t_Rec1Type IS RECORD (
    Field1 NUMBER,
    Field2 VARCHAR2(5));
  TYPE t_Rec2Type IS RECORD (
    Field1 NUMBER,
    Field2 VARCHAR2(5));
  v_Rec1 t_Rec1Type;
  v_Rec2 t_Rec2Type;
BEGIN
  /* v_Rec1v_Rec2́AtB[h̖Oь^łĂ
     R[h^قȂĂB
     ̂߁Ȃ͖łAPLS-382B */
  v_Rec1 := v_Rec2;

  /* AtB[ȟ^ł邽
     ̑͗LłB */
  v_Rec1.Field1 := v_Rec2.Field1;
  v_Rec2.Field2 := v_Rec2.Field2;
END;



-- Available online as select.sql
DECLARE
  -- \studentŝ̃tB[hɈv郌R[h`B
  -- tB[hɑ΂%TYPEgpĂ_ɒӁB
  TYPE t_StudentRecord IS RECORD (
    FirstName  students.first_name%TYPE,
    LastName   students.last_name%TYPE,
    Major      students.major%TYPE);

  -- f[^󂯎邽߂̕ϐ錾B
  v_Student  t_StudentRecord;
BEGIN
  -- ID10,000̊wɊւoB
  -- v_Student̃tB[hɈv⍇ǂ̂悤
  -- ԂɒӁB
  SELECT first_name, last_name, major
    INTO v_Student
    FROM students
    WHERE ID = 10000;
END;



DECLARE
  v_RoomRecord  rooms%ROWTYPE;



(room_id      NUMBER(5),
 building     VARCHAR2(15),
 room_number  NUMBER(4),
 number_seats NUMBER(4),
 description  VARCHAR2(50))



DECLARE
  /* \̌^`B̌^ϐɂ́A
     10ȉ̊ei[łB */
  TYPE t_CharacterTable IS TABLE OF VARCHAR2(10)
    INDEX BY BINARY_INTEGER;

  /* Ľ^ϐ錾Bɂ
     ̈悪ۂɊ蓖ĂB */
  v_Characters t_CharacterTable;



DECLARE
  TYPE t_NameTable IS TABLE OF students.first_name%TYPE
    INDEX BY BINARY_INTEGER;
  TYPE t_DateTable IS TABLE OF DATE
    INDEX BY BINARY_INTEGER;
  v_Names t_NameTable;
  v_Dates t_DateTable;



BEGIN
v_Names(1) := 'Scott';
v_Dates(-4) := SYSDATE - 1; /* uSYSDATE - 1v]ƁA24ԑO
                                ̎ɂȂB */
END;



v_Names(0) := 'Harold';
v_Names(-7) := 'Susan';
v_Names(3) := 'Steve'



ORA-01403: f[^܂B 



-- Available online as tabrec.sql
DECLARE
  TYPE t_StudentTable IS TABLE OF students%ROWTYPE
    INDEX BY BINARY_INTEGER;
  /* v_Students̊evf́AR[hłB */
  v_Students t_StudentTable;
BEGIN
  /* id = 10,001̃R[hoA
 v_Students(10001)Ɋi[B */
  SELECT *
    INTO v_Students(10001)
    FROM students
    WHERE id = 10001;
END;



v_Students(10001).first_name := 'Larry';
DBMS_OUTPUT.PUT_LINE(v_Students(10001).first_name);



-- Available online as count.sql
DECLARE
  TYPE t_NumberTable IS TABLE OF NUMBER
    INDEX BY BINARY_INTEGER;
  v_Numbers t_NumberTable;
  v_Total NUMBER;
BEGIN
  -- \50s}B
  FOR v_Counter IN 1..50 LOOP
    v_Numbers(v_Counter) := v_Counter;
  END LOOP;

  v_Total := v_Numbers.COUNT;
END;



-- Available online as delete.sql
DECLARE
  TYPE t_ValueTable IS TABLE OF VARCHAR2(10)
    INDEX BY BINARY_INTEGER;
  v_Values t_ValueTable;
BEGIN
  -- \ɍs}B
  v_Values(1) := 'One';
  v_Values(3) := 'Three';
  v_Values(-2) := 'Minus Two';
  v_Values(0) := 'Zero';
  v_Values(100) := 'Hundred';
  
  DBMS_OUTPUT.PUT_LINE('Before DELETE, COUNT=' || v_Values.COUNT);
  v_Values.DELETE(100);  'Hundred'폜B
  DBMS_OUTPUT.PUT_LINE('After first DELETE, COUNT=' ||
                       v_Values.COUNT);
  v_Values.DELETE(1,3);  'One''Three'폜B
  DBMS_OUTPUT.PUT_LINE('After second DELETE, COUNT=' ||
                       v_Values.COUNT);
  v_Values.DELETE;       c̒lׂč폜B
  DBMS_OUTPUT.PUT_LINE('After last DELETE, COUNT=' ||
                       v_Values.COUNT);
END;



-- Available online as exists.sql
DECLARE
  TYPE t_FirstNameTable IS TABLE OF students.first_name%TYPE
    INDEX BY BINARY_INTEGER;
  FirstNames  t_FirstNameTable;
BEGIN
  -- \ɍs}B
  FirstNames(1) := 'Scott';
  FirstNames(3) := 'Joanne';

  -- s݂Ă邩A`FbNB
  IF FirstNames.EXISTS(1) THEN
    INSERT INTO temp_table (char_col) VALUES
      ('Row 1 exists!');
  ELSE
    INSERT INTO temp_table (char_col) VALUES
      ('Row 1 doesn't exist!');
  END IF;
  IF FirstNames.EXISTS(2) THEN
    INSERT INTO temp_table (char_col) VALUES
      ('Row 2 exists!');
  ELSE
    INSERT INTO temp_table (char_col) VALUES
      ('Row 2 doesn''t exist!');
  END IF;
END;



-- Available online as frstlast.sql
DECLARE
  TYPE t_LastNameTable IS TABLE OF students.last_name%TYPE
    INDEX BY BINARY_INTEGER;
  v_LastNames  t_LastNameTable;
  v_Index  BINARY_INTEGER;
BEGIN
  -- \ɍs}B
  v_LastNames(43) := 'Mason';
  v_LastNames(50) := 'Junebug';
  v_LastNames(47) := 'Taller';

  -- v_Index43B
  v_Index := v_LastNames.FIRST;

  -- v_Index50B
  v_Index := v_LastNames.LAST;
END;



-- Available online as nxtprior.sql
DECLARE
  TYPE t_MajorTable IS TABLE OF students.major%TYPE
    INDEX BY BINARY_INTEGER;
  v_Majors t_MajorTable;
  v_Index  BINARY_INTEGER;
BEGIN
  -- \ɍs}B
  v_Majors(-7) := 'Computer Science';
  v_Majors(4) := 'History';
  v_Majors(5) := 'Economics';

  -- \ׂ̂Ă̍s[vŒׁA̍s
  -- temp_tableɑ}B
  v_Index := v_Majors.FIRST;
  LOOP
    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_Index, v_Majors(v_Index));
    EXIT WHEN v_Index = v_Majors.LAST;
    v_Index := v_Majors.NEXT(v_Index);
  END LOOP;
END;



-- Available online as nulltab.sql
DECLARE
  TYPE t_NameTable IS TABLE OF students.first_name%TYPE
    INDEX BY BINARY_INTEGER;
  v_Names t_NameTable;
  v_EmptyTable t_NameTable;
BEGIN
  /* Assign some rows to v_Names. */
  v_Names(1) := 'Scott';
  v_Names(2) := 'Lefty';
  v_Names(3) := 'Susan';
  /* v_NameŝׂĂ폜B */
  v_Names := v_EmptyTable;
END;



Chapter4
BEGIN
  CREATE TABLE temp_table (
    num_value   NUMBER,
    char_value  CHAR(10));
  INSERT INTO temp_table (num_value, char_value)
    VALUES (10, 'Hello');
END;



UPDATE CLASSES
  SET num_credits = 3
  WHERE department = 'HIS'
  AND course = 101;



-- Available online as bindvar.sql
DECLARE
  v_NumCredits  classes.num_credits%TYPE;
BEGIN
  /* v_NumCreditsւ̑ */
  v_NumCredits := 3;
  UPDATE CLASSES
    SET num_credits = v_NumCredits
    WHERE department = 'HIS'
    AND course = 101;
END;



ORA-01422: v̍so܂B 



-- Available online as select.sql
DECLARE
  v_StudentRecord  students%ROWTYPE;
  v_Department     classes.department%TYPE;
  v_Course         classes.course%TYPE;
BEGIN
  -- \students烌R[hPoAv_StudentRecord
  -- Ɋi[BWHERÉA\̂Psv_ɂĒӁB
  -- ܂A⍇́A\StudentŝׂẴtB[hԂi*
  -- IĂ邽߁j_ɂĂӁB̂߁AoƂȂ郌R[h́A
  -- students%ROWTYPEƒ`ĂB
  SELECT *
    INTO v_StudentRecord
    FROM students
    WHERE id = 10000;

  -- \classestB[hQoAꂩv_Department
  -- v_CourseɊi[B̏ꍇAWHERE傪\̂Psɂ
  -- v_ɒӁB
  SELECT department, course
    INTO v_Department, v_Course
    FROM classes
    WHERE room_id = 99997;
END;



-- Available online as insert.sql
DECLARE
  v_StudentID  students.id%TYPE;
BEGIN
  -- VwIDԍoB
  SELECT student_sequence.NEXTVAL
    INTO v_StudentID
    FROM dual;

  -- \studentsɍsPsǉB
  INSERT INTO students (id, first_name, last_name)
    VALUES (v_StudentID, 'Timothy', 'Taller');

  -- QsڂǉBAINSERT̒ŏԍ
  -- ڎw肷B
  INSERT INTO students (id, first_name, last_name)
    VALUES (student_sequence.NEXTVAL, 'Patrick', 'Poll');
END;



INSERT INTO rooms
  SELECT * FROM classes;



INSERT INTO classes
  SELECT * FROM classes;



-- Available online as update.sql
DECLARE
  v_Major           students.major%TYPE;
  v_CreditIncrease  NUMBER := 3;
BEGIN
  -- UPDATEł́AjUĂ邷ׂĂ̊wcurrent_credits
  -- tB[hɂRZB
  v_Major := 'History';
  UPDATE students
    SET current_credits = current_credits + v_CreditIncrease
    WHERE major = V_Major;
END;



-- Available online as delete.sql
DECLARE
  v_StudentCutoff  NUMBER;
BEGIN
  v_StudentCutoff := 10;
  -- w̓o^s\ȃNXAׂč폜B
  DELETE FROM classes
    WHERE current_students < v_StudentCutoff;

  -- ocwŮw̓APʂ܂KĂȂwׂč폜B
  DELETE FROM students
    WHERE current_credits = 0
    AND   major = 'Economics';
END;



DECLARE
  v_Department  CHAR(3);
BEGIN
  v_Department := 'CS';
  -- Rs[^TCGXiCSj̃NXׂč폜B
  DELETE FROM classes
    WHERE department = v_Department;
END;



DECLARE
 Department  CHAR(3);
BEGIN
  Department := 'CS';
  -- Rs[^TCGXiCSj̃NXׂč폜B  
  DELETE FROM classes
    WHERE department = Department;
END;



<<l_DeleteBlock>>
DECLARE
  Department  CHAR(3);
BEGIN
  Department := 'CS';
  -- Rs[^TCGXiCSj̃NXׂč폜B
  DELETE FROM classes
    WHERE department = l_DeleteBlock.Department;
END;



'abc' = 'abc'
'abc   ' = 'abc'  -- ŏ̖̕ɋ󔒂_ɒӁB
'ab' < 'abc'
'abcd' > 'abcc'



'abc' = 'abc'
'ab' < 'abc'
'abcd' > 'abcc'



'abc   ' = 'abc'  -- ŏ̖̕ɋ󔒂_ɒӁB



DECLARE
 v_Department  VARCHAR2(3);
BEGIN
  v_Department := 'CS';
  -- Rs[^TCGXiCSj̃NXׂč폜B
  DELETE FROM classes
    WHERE department = v_Department;
END;



UPDATE students
  SET major = 'Music'
  WHERE id = 10005;



ORA-00942: \܂̓r[݂܂B



PLS-00201: ʎq: <O>͐錾Ă܂B



UPDATE example.students
  SET major = 'Music'
  WHERE id = 10005;



CREATE DATABASE LINK example_backup
  CONNECT TO example IDENTIFIED BY example
  USING 'backup_database';



UPDATE students@example_backup
  SET major = 'Music'
  WHERE id = 10005;



CREATE SYNONYM backup_students
  FOR students@example_backup;



UPDATE backup_students
  SET major = 'Music'
  WHERE id = 10005;



CREATE SEQUENCE student_sequence
  START WITH 10000;

-- ̕ł́AIDlƂ10,000gpB
INSERT INTO students (id, first_name, last_name)
  VALUES (student_sequence.NEXTVAL, 'Scott', 'Smith');
-- ̕ł́AIDlƂ10,001gpB
INSERT INTO students (id, first_name, last_name)
  VALUES (student_sequence.NEXTVAL, 'Margaret', 'Mason');

SELECT student_sequence.NEXTVAL "Value"
  FROM dual;  -- ԍA܂1₷B
Value
----------
10002

SELECT student_sequence.CURRVAL "Value"
  FROM dual;  -- ݂̒lԂB
Value
----------
10002



SELECT ROWID
  FROM rooms;

ROWID
------------------
00000045.0000.0002
00000045.0001.0002
00000045.0002.0002
00000045.0003.0002
00000045.0004.0002



SELECT *
  FROM students
  WHERE ROWNUM < 3;



GRANT SELECT ON classes TO userA;



GRANT UPDATE, DELETE ON students TO userA;



GRANT CREATE TABLE, ALTER ANY PROCEDURE to userA;



REVOKE SELECT ON classes FROM userA;



REVOKE UPDATE, DELETE, INSERT ON students FROM userA;



REVOKE ALTER TABLE, EXECUTE ANY PROCEDURE FROM userA;



CREATE ROLE table_query;
GRANT SELECT ON students TO table_query;
GRANT SELECT ON classes TO table_query;
GRANT SELECT ON rooms TO table_query;



GRANT table_query TO userA;
GRANT table_query TO userB;



GRANT privilege TO PUBLIC;



UPDATE accounts
  SET balance = balance - transaction_amount
  WHERE account_no = from_acct;
UPDATE accounts
  SET balance = balance + transaction_amount
  WHERE account_no = to_acct;



BEGIN
  INSERT INTO temp_table (char_col) VALUES ('Insert One');
  SAVEPOINT A;
  INSERT INTO temp_table (char_col) VALUES ('Insert Two');
  SAVEPOINT B;
  INSERT INTO temp_table (char_col) VALUES ('Insert Three');
  SAVEPOINT C;
  /* X */
  COMMIT;
END;



ROLLBACK TO B;



ROLLBACK TO A;



-- Available online as 1trance.sql
INSERT INTO classes
   (department, course, description, max_students, 
    current_students, num_credits, room_id) 
  VALUES ('CS', 101, 'Computer Science 101', 50, 10, 4, 99998);
BEGIN
  UPDATE rooms
    SET room_id = room_id - 1000;
  ROLLBACK WORK;
END;



-- Available online as 1block.sql
DECLARE
  v_NumIterations   NUMBER;
BEGIN
  -- 1500܂ł̃[vɂA1`500̐ltemp_tableɑ}B
  -- R~bǵA50sƂɎsB
  FOR v_LoopCounter IN 1..500 LOOP
    INSERT INTO temp_table (num_col) VALUES (v_LoopCounter);
    v_NumIterations := v_NumIterations + 1;
    IF v_NumIterations = 50 THEN
      COMMIT;
      v_NumIterations := 0;
    END IF;
  END LOOP;
END;



Chapter 5
SELECT UPPER(first_name)
  FROM students;



DECLARE
  v_FirstName  students.first_name%TYPE;
BEGIN
  v_FirstName := UPPER('Charlie');
END;



SQL> SELECT CHR(37) a, CHR(100) b, CHR(101) c
  2    FROM dual;
A B C
- - -
% d e 



SELECT CONCAT('Alphabet ', 'Soup') "Dinner"
  FROM dual;
Dinner
-------------
Alphabet Soup 



SELECT INITCAP('4 scoRE and 7 YEARS ago...') "Speech"
  FROM dual;



Speech
--------------------------
4 Score And 7 Years Ago...



SELECT LOWER('4 scoRE and 7 YEARS ago...') "Speech"
  FROM dual;
Speech
--------------------------
4 score and 7 years ago...



SELECT LPAD('Short String', 15) "First"
  FROM dual;
First
---------------
   Short String

SELECT LPAD('Short String', 20, 'XY') "Second"
  FROM dual;
Second
--------------------
XYXYXYXYShort String

SELECT LPAD('Short String', 13, 'XY') "Third"
  FROM dual;
Third
-------------
XShort String



SELECT LTRIM('   End of the string') "First"
  FROM dual;
First
-----------------
End of the string

SELECT LTRIM('xxxEnd of the string', 'x') "Second"
  FROM dual;
Second
-----------------
End of the string

SELECT LTRIM('xyxyxyEnd of the string', 'xy') "Third"
  FROM dual;
Third
-----------------
End of the string

SELECT LTRIM('xyxyxxxyEnd of the string', 'xy') "Fourth"
  FROM dual;
Fourth
-----------------
End of the string



SELECT NLS_INITCAP('ijsbeer', 'NLS_SORT = Xdutch') "Result"
  FROM dual;
Result
------
IJsbeer 



SELECT NLS_LOWER('CITA''DEL', 'NLS_SORT = Xgerman') "Result"
  FROM dual;
Result
---------
cit_del 



SELECT NLS_UPPER('groe', 'NLS_SORT = Xgerman') "Result"
  FROM dual;
Result
------
GROSS 



SELECT REPLACE ('This and That', 'Th', 'B') "First"
  FROM dual;
First
-----------
Bis and Bat

SELECT REPLACE ('This and That', 'Th') "Second"
  FROM dual;
Second
---------
is and at

SELECT REPLACE ('This and That', NULL) "Third"
  FROM dual;
Third
-------------
This and That



SELECT RPAD('Nifty', 10, '!') "First"
  FROM dual;
First
----------
Nifty!!!!!

SELECT RPAD('Nifty', 10, 'AB') "Second"
  FROM dual;
Second
----------
NiftyABABA 



SELECT RTRIM('This is a stringxxxxx', 'x') "First"
  FROM dual;
First
----------------
This is a string

SELECT RTRIM('This is also a stringxxXXxx', 'x') "Second"
  FROM dual;
Second
-------------------------
This is also a stringxxXX

SELECT RTRIM('This is a string as well', 'well') "Third"
  FROM dual;
Third
--------------------
This is a string as



SELECT first_name, SOUNDEX(first_name)
  FROM students;
FIRST_NAME           SOUN
-------------------- ----
Scott                S300
Margaret             M626
Joanne               J500
Manish               M520
Patrick              P362
Timothy              T530

SELECT first_name
  FROM students
  WHERE SOUNDEX(first_name) = SOUNDEX('skit');
FIRST_NAME
--------------------
Scott



SELECT SUBSTRB('abc123def', 4, 4) "First"
  FROM dual;
First
-----
123d

SELECT SUBSTR('abc123def', -4, 4) "Second"
  FROM dual;
Second
------
3def 

SELECT SUBSTR('abc123def', 5) "Third"
  FROM dual;

Third
-----
23def



SELECT SUBSTR("abc123def", 2, 6) "Example"
  FROM DUAL;
Example
-------
bc1



SELECT TRANSLATE('abcdefghij', 'abcdef', '123456')
  FROM dual;
TRANSLATE(
----------
123456ghij

SELECT TRANSLATE('abcdefghij', 'abcdefghij', '123456')
  FROM dual;
TRANSL
------
123456



SELECT UPPER('THE quick bROwn Fox jumped over THE LAZY
             dOg...') "Result"
  FROM dual;
Result
-----------------------------------------------
THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG...



SELECT ASCII(' ')
  FROM dual;
ASCII('')
---------
       32

SELECT ASCII('a')
  FROM dual;
ASCII('A')
----------
        97



SELECT INSTR('Scott''s spot', 'ot', 1, 2) "First"
  FROM dual;
    First
---------
       11

SELECT INSTR('Scott''s spot', 'ot', -1, 2) "Second"
  FROM dual;
   Second
---------
        3

SELECT INSTR('Scott''s spot', 'ot', 5) "Third"
  FROM dual;
    Third
---------
       11

SELECT INSTR('Scott''s spot', 'ot', 12) "Fourth"
  FROM dual;
   Fourth
---------
        0



SELECT INSTRB('Scott''s spot', 'ot', 1, 2) "INSTRB"
  FROM dual;
   INSTRB
---------
       21



SELECT LENGTH('Mary had a little lamb') "Length"
  FROM dual;
   Length
---------
       22



SELECT LENGTHB('Mary had a little lamb') "Length"
  FROM dual;
   Length
---------
       44



SELECT NLSSORT('Scott') "NLS"
  FROM dual;
NLS
--------------------------------------------
53636F747400



SELECT ABS(-7), ABS(7)
  FROM dual;
  ABS(-7)    ABS(7)
--------- ---------
        7         7



SELECT ACOS(-1), ACOS(0.5)
  FROM dual;

  ACOS(-1)  ACOS(0.5)
---------- ----------
3.14159265 1.04719755



SELECT ASIN(1), ASIN(0.5)
  FROM dual;

   ASIN(1)  ASIN(0.5)
---------- ----------
1.57079633 .523598776



SELECT ATAN(0), ATAN(0.5)
  FROM dual;

   ATAN(0)  ATAN(0.5)
---------- ----------
         0 .463647609



SELECT ATAN2(1, 2)
  FROM dual;

ATAN2(1,2)
----------
.463647609



SELECT CEIL(18.1), CEIL(-18.1)
  FROM dual;
CEIL(18.1) CEIL(-18.1)
---------- -----------
        19         -18



SELECT COS(0), COS(90 * 3.14159265359/180)
  FROM dual;
   COS(0) COS(90*3.14159265359/180)
--------- -------------------------
        1                        -1



SELECT COSH(0), COSH(90 * 3.14159265359/180)
  FROM dual;
  COSH(0) COSH(90*3.14159265359/180)
--------- --------------------------
        1                  2.5091785



SELECT EXP(1), EXP(2.7)
  FROM dual;
   EXP(1)  EXP(2.7)
--------- ---------
2.7182818 14.879732



SELECT FLOOR(-23.5), FLOOR(23.5)
  FROM dual;
FLOOR(-23.5) FLOOR(23.5)
------------ -----------
         -24          23



SELECT LN(100)
  FROM dual;
  LN(100)
---------
4.6051702



SELECT LOG(2, 32), LOG(5, 25)
  FROM dual;
LOG(2,32) LOG(5,25)
--------- ---------
        5         2



SELECT MOD(23, 5), MOD(4, 1.3)
  FROM dual;
MOD(23,5) MOD(4,1.3)
--------- ----------
        3         .1



SELECT POWER(4, 3), POWER(1.1, 2.6), POWER(25, -2), POWER
   FROM dual;
POWER(4,3) POWER(1.1,2.6) POWER(25,-2) POWER(-2,3)
---------- -------------- ------------ -----------
        64       1.281212        .0016          -8



SELECT ROUND(1.56), ROUND(1.56, 1), ROUND(12.34, -2)
  FROM dual;
ROUND(1.56) ROUND(1.56,1) ROUND(12.34,-2)
----------- ------------- ---------------
          2           1.6               0



SELECT SIGN(-47.3), SIGN(0), SIGN(47.3)
  FROM dual;
SIGN(-47.3)   SIGN(0) SIGN(47.3)
----------- --------- ----------
         -1         0          1



SELECT SIN(0), SIN(60 * 3.14159265359/180)
  FROM dual;
   SIN(0) SIN(60*3.14159265359/180)
--------- -------------------------
        0                  .8660254



SELECT SINH(0), SINH(60 * 3.14159265359/180)
  FROM dual;
  SINH(0) SINH(60*3.14159265359/180)
--------- --------------------------
        0                  1.2493671



SELECT SQRT(64), SQRT(97.654)
  FROM dual;
 SQRT(64) SQRT(97.654)
--------- ------------
        8    9.8820038



SELECT TAN(0), TAN(-60 * 3.14159265359/180)
  FROM dual;
   TAN(0) TAN(-60*3.14159265359/180)
--------- --------------------------
        0                  -1.732051



SELECT TANH(0), TANH(-60 * 3.14159265359/180)
  FROM dual;
  TANH(0) TANH(-60*3.14159265359/180)
--------- ---------------------------
        0                   -.7807144



SELECT TRUNC(-123.456), TRUNC(-123.456, 1), TRUNC(-123.456, -1)
  FROM dual;
TRUNC(-123.456) TRUNC(-123.456,1) TRUNC(-123.456,-1)
--------------- ----------------- ------------------
           -123            -123.4               -120



SELECT ADD_MONTHS('02-FEB-91', 1), ADD_MONTHS('19-JAN-87', 1),
       ADD_MONTHS('30-JAN-87', 13)
  FROM dual;
ADD_MONTH ADD_MONTH ADD_MONTH
--------- --------- ---------
02-MAR-91 19-FEB-87 29-FEB-88



SELECT LAST_DAY('12-APR-71') "Current",
       LAST_DAY('12-APR-71') - TO_DATE('12-APR-71') "Days Left"
  FROM dual;
Current   Days Left
--------- ---------
30-APR-71        18



SELECT MONTHS_BETWEEN('12-APR-71', '12-MAR-97') "First",
       MONTHS_BETWEEN('12-APR-71', '22-MAR-60') "Second"
  FROM dual;
First     Second
--------- ---------
     -311 132.67742



SELECT TO_CHAR(NEW_TIME(TO_DATE('12-APR-71 12:00:00',
                                'DD-MON-YY HH24:MI:SS'),
                        'PST', 'EST'),
               'DD-MON-YY HH24:MI:SS') "Pacific -> Eastern"
  FROM dual;
Pacific -> Eastern
------------------
12-APR-71 15:00:00



SELECT NEXT_DAY('12-APR-71', 'thursday') "Result"
   FROM dual;
Result
--------
15-APR-71



SELECT ROUND(TO_DATE('12-APR-71'), 'MM') "Nearest Month"
  FROM dual;
Nearest Month
-------------
01-APR-71



SELECT TO_CHAR(SYSDATE, 'Month DD, YYYY HH24:MI:SS') "Now"
  FROM dual;
Now
----------------------------------------------------------------
April  13, 1997 23:31:17



SELECT TRUNC(TO_DATE('12-APR-71 13:21:00', 'DD-MON-YY HH24:MI:SS'),
             'Year') "First Day"
  FROM dual;
First Day
---------
01-JAN-71



SELECT SYSDATE "Today", SYSDATE + 1 "Tomorrow"
  FROM dual;

Today     Tomorrow
--------- ---------
29-MAR-97 30-MAR-97

SELECT TO_DATE('12-APR-71 12:00:00', 'DD-MON-YY HH24:MI:SS') -
       TO_DATE('15-MAR-71 15:00:00', 
               'DD-MON-YY HH24:MI:SS') "Difference"
  FROM dual
Difference
----------
    27.875



SELECT description
  FROM classes
  WHERE rowid = CHARTOROWID('0000002D.0002.0002');
DESCRIPTION
-------------
Economics 203



SELECT CONVERT('Gro', 'WE8HP', 'WE8DEC') "Conversion"
  FROM dual;
Conversion
----------
Gro



INSERT INTO raw_table (raw_column)
  VALUES (HEXTORAW('017D3F'));



SELECT RAWTOHEX(raw_column)
  FROM raw_table;
RAW_COLUMN
----------
017D3F 



SELECT ROWIDTOCHAR(rowid)
  FROM classes;

ROWIDTOCHAR(ROWID)
------------------
0000002D.0000.0002
0000002D.0002.0002
0000002D.0003.0002



SELECT TO_CHAR(SYSDATE, 'DD-MON-YY HH24:MI:SS') "Right Now"
  FROM dual;
Right Now
------------------
15-NOV-95 01:17:14



SELECT TO_CHAR(123456, '99G99G99') "Result"
  FROM dual;
Result
---------
 12,34,56

SELECT TO_CHAR(123456, 'L99G99D99',
               'NLS_NUMERIC_CHARACTERS = '',.''
                NLS_CURRENCY = ''Money'' ') "Result 2"
  FROM dual;
Result 2
-------------
Money12,34.56



DECLARE
  v_CurrentDate  DATE;
BEGIN
  v_CurrentDate := TO_DATE('January 7, 1973', 'Month DD, YYYY');
END;



SELECT TO_MULTI_BYTE('Hello') "Multi"
  FROM dual;
Multi
----------
Hello 



DECLARE
  v_Num  NUMBER;
BEGIN
  v_Num := TO_NUMBER('$12345.67', '$99999.99');
END;



SELECT TO_SINGLE_BYTE('Greetings') "Single"
  FROM dual;
Single
----------
Greetings 



SELECT AVG(number_seats)
  FROM rooms;
   AVG(NUMBER_SEATS)
--------------------
                 330



SELECT COUNT(*)
  FROM students;
  COUNT(*)
----------
         6
SELECT COUNT(DISTINCT major) "Majors"
  FROM students;
    Majors
----------
         3
SQL> SELECT major, COUNT(major)
  2    FROM students
  3    GROUP BY major;

MAJOR                          COUNT(MAJOR)
------------------------------ ------------
Computer Science                          2
Economics                                 2
History                                   3
Music                                     2
Nutrition                                 2



SELECT MAX(LENGTH(first_name))
  FROM students;
MAX(LENGTH(FIRST_NAME))
-----------------------
                      8



SELECT MIN(id)
  FROM students;
  MIN(ID)
---------
    10000



SELECT STDDEV(number_seats)
  FROM rooms;
STDDEV(NUMBER_SEATS)
--------------------
           422.19664



SELECT department dept, SUM(num_credits)
  FROM classes
  GROUP by department;
DEPT SUM(NUM_CREDITS)
---- ----------------
CS                  4
ECN                 3
HIS                 4



SELECT VARIANCE(number_seats)
  FROM rooms;
VARIANCE(NUMBER_SEATS)
----------------------
                178250



SELECT DECODE('abc', 'a', 1,
                     'b', 2,
                     'abc', 3,
                     'd', 4,
                     -1) "Decode 1"
  FROM dual;
 Decode 1
---------
        3

SELECT DECODE(NULL, 'a', 1,
                    NULL, 2) "Decode 2"
  FROM dual;
Decode 2
---------
        2



SELECT first_name, DUMP(first_name) "Dump"
   FROM students
FIRST_NAME           Dump
-------------------- ---------------------------------------------
Scott                Typ=1 Len=5: 83,99,111,116,116
Margaret             Typ=1 Len=8: 77,97,114,103,97,114,101,116
Joanne               Typ=1 Len=6: 74,111,97,110,110,101
Manish               Typ=1 Len=6: 77,97,110,105,115,104
Patrick              Typ=1 Len=7: 80,97,116,114,105,99,107
Timothy              Typ=1 Len=7: 84,105,109,111,116,104,121

SELECT first_name, DUMP(first_name, 17) "Dump"
  FROM students
FIRST_NAME           Dump
-------------------- --------------------------------------
Scott                Typ=1 Len=5: S,c,o,t,t
Margaret             Typ=1 Len=8: M,a,r,g,a,r,e,t
Joanne               Typ=1 Len=6: J,o,a,n,n,e
Manish               Typ=1 Len=6: M,a,n,i,s,h
Patrick              Typ=1 Len=7: P,a,t,r,i,c,k
Timothy              Typ=1 Len=7: T,i,m,o,t,h,y

SELECT first_name, DUMP(first_name, 17, 2, 4) "Dump"
  FROM students;
FIRST_NAME           Dump
-------------------- --------------------------------------
Scott                Typ=1 Len=5: c,o,t,t
Margaret             Typ=1 Len=8: a,r,g,a
Joanne               Typ=1 Len=6: o,a,n,n
Manish               Typ=1 Len=6: a,n,i,s
Patrick              Typ=1 Len=7: a,t,r,I



SELECT GREATEST(10, '7', -1)
  FROM dual;
GREATEST(10,'7',-1)
-------------------
                 10



SELECT LEAST('abcd', 'ABCD', 'a', 'xyz') "Least"
  FROM dual;
Least
-----
ABCD 



SELECT NVL('non null value', 7) "First",
       NVL(NULL, 'null value') "Second"
  FROM dual;
First          Second
-------------- ----------
non null value null value 



SQL> connect scott/tiger
Connected.
SQL> SELECT UID
  2    FROM dual;
      UID
---------
        8

SQL> connect system/manager
Connected.
SQL> SELECT UID
  2    FROM dual;
      UID
---------
        5



SQL> connect scott/tiger
Connected.
SQL> SELECT USER
  2    FROM dual;
USER
------------------------------
SCOTT

SQL> connect sys/change_on_install
Connected.
SQL> SELECT USER
  2    FROM dual;
USER
------------------------------
SYS



SELECT USERENV('TERMINAL'), USERENV('LANGUAGE')
  FROM dual;
USERENV( USERENV('LANGUAGE')
-------- --------------------------------------------
Windows  AMERICAN_AMERICA.WE8ISO8859P1



SELECT last_name, VSIZE(last_name) "Size"
  FROM students;
LAST_NAME                 Size
-------------------- ---------
Smith                        5
Mason                        5
Junebug                      7
Murgratroid                 11
Poll                         4
Taller                       6



SQL> set serveroutput on
SQL> BEGIN
  2    DBMS_OUTPUT.PUT_LINE('12340: ' || DH_UTIL.SPELL(12340));
  3    DBMS_OUTPUT.PUT_LINE('987.123: ' || DH_UTIL.SPELL(987.123));
  4    DBMS_OUTPUT.PUT_LINE('10000: ' || DH_UTIL.SPELL(10000));
  5  END;
  6  /
12340: Twelve Thousand Three Hundred Forty
987.123: Nine Hundred Eighty-Seven and One Hundred 
         Twenty-Three / Thousandths
10000: Ten Thousand

PL/SQL procedure successfully completed.



SQL> set serveroutput on
SQL> BEGIN
  2    DBMS_OUTPUT.PUT_LINE('12340: ' ||                                                      DH_UTIL.CHECK_PROTECT(12340));
  3    DBMS_OUTPUT.PUT_LINE('987.12: ' ||
                            DH_UTIL.CHECK_PROTECT(987.12));
  4    DBMS_OUTPUT.PUT_LINE('10000: ' ||
                            DH_UTIL.CHECK_PROTECT(10000));
  5  END;
  6  /
12340: Twelve Thousand Three Hundred Forty Dollars and Zero Cents
987.12: Nine Hundred Eighty-Seven Dollars and Twelve Cents
10000: Ten Thousand Dollars and Zero Cents

PL/SQL procedure successfully completed.



-- Available online as spelchek.sql
REM **************************************************************
REM David L. Hunt (file author) distributes this and other 
REM files/scripts for educational purposes only, to illustrate the 
REM use or application of various computing techniques. Neither the 
REM author nor Oracle Corporation makes any warranty regarding this 
REM script's fitness for any industrial application or purpose nor is 
REM there any claim that this or any similarly-distributed scripts 
REM are error free or should be used for any purpose other than
REM illustration.
REM 
REM Please contact the author via email (see address below) when 
REM you have comments, suggestions, and/or difficulties with this
REM packages functions.
REM
REM [Please keep the above disclaimer and the embedded electronic 
REM  documentation with this script.]
REM **************************************************************
REM About this script/file:
REM
REM NAME: SPELCHEK.SQL - PL/SQL code to create a package (DH_UTIL)
REM       providing 1) Number spelling and 2) Bank Draft/Checking
REM       protection via spelled amounts.
REM
REM AUTHOR: Dave Hunt, Senior Principal Instructor
REM         Oracle Eduction Services
REM         170 South Main Street, Suite 1150
REM         Salt Lake City, Utah, USA  84101
REM         dhunt@us.oracle.com
REM
REM **************************************************************
REM Maintenance History:
REM
REM 24-APR-96: Original Code
REM 03-MAR-96: Enhanced to handle 1) negative numbers and 2) zero
REM 16-JAN-97: Enhanced to translate non-integer decimal numbers
REM 20-JAN-97: Enhanced to handle numbers in the range:
REM            (-10 ** 100)+1 to (10 ** 100) -1 with precision to
REM            40 digits. Up to 40 digits behind the decimal point
REM            can be spelled.
REM 25-JAN-97: Added additional documentation and remarks.
REM **************************************************************
REM This package contains two GLOBAL functions:
REM   1) DH_UTIL.SPELL: Translates a number into English words.
REM      [Note: This version contains "American" (vs. "British")
REM             numeric-magnitude wordings: 
REM
REM                         Number American     British 
REM      ------------------------- -----------  -----------------
REM                  1,000,000,000 Billion      Milliard
REM              1,000,000,000,000 Trillion     Billion
REM          1,000,000,000,000,000 Quadrillion  Thousand Billion
REM      1,000,000,000,000,000,000 Quintillion  Trillion
REM
REM      For British system spellings, modify the table as needed
REM      at the end of the Package Body.]
REM 
REM **************************************************************
REM      Function 1 Usage: "DH_UTIL.SPELL(any-number)"
REM      SQL Example:
REM         SELECT last_name,
REM            salary, DH_UTIL.SPELL(salary) Worded
REM         FROM s_emp;"
REM
REM         LAST_NAME    SALARY WORDED
REM         ------------ ------ --------------------------------
REM         Velasquez      2500 Two Thousand Five Hundred
REM         Ngao           1450 One Thousand Four Hundred Fifty
REM         Nagayama       1400 One Thousand Four Hundred
REM
REM **************************************************************
REM      PL/SQL Example:
REM         BEGIN
REM            DBMS_OUTPUT.PUT_LINE
REM              (dh_util.spell(-123456789.123456789));
REM         END;
REM         /
REM         Negative One Hundred Twenty-Three Million Four 
REM         Hundred Fifty-Six Thousand Seven Hundred Eighty-Nine
REM         and One Hundred Twenty-Three Million Four 
REM         Hundred Fifty-Six Thousand Seven Hundred
REM         Eighty-Nine / Billionths
REM
REM **************************************************************
REM **************************************************************
REM   2) DH_UTIL.CHECK_PROTECT: Translates a number into spelled
REM         "Dollars & Cents".
REM      Function 2 Usage: "DH_UTIL.CHECK_PROTECT(any-number)"
REM **************************************************************
REM      SQL Example:
REM         select 'Pay to the order of: '||
REM           rpad(ltrim(first_name||' '||last_name||' '),22,'*')
REM           ||'  '||lpad(rtrim(' '||ltrim(nvl(
REM           to_char(salary,'$99,999,990.00'),'Null Amount')
REM                )),16,'*')||chr(10)||
REM           rpad('** '||
REM           dh_util.check_protect(SALARY)||' ',56,'*') " "
REM         from s_emp
REM         where rownum <= 3;
REM         
REM  Pay to the order of: Carmen Velasquez *****  ****** $2,500.00
REM  ** Two Thousand Five Hundred Dollars and Zero Cents *********
REM         
REM  Pay to the order of: LaDoris Ngao *********  ****** $1,450.00
REM  ** One Thousand Four Hundred Fifty Dollars and Zero Cents ***
REM       
REM  Pay to the order of: Midori Nagayama ******  ****** $1,400.00
REM  ** One Thousand Four Hundred Dollars and Zero Cents *********
REM
REM **************************************************************
REM      PL/SQL Example:
REM         begin
REM            dbms_output.put_line
REM               (dh_util.check_protect(123456789.56));
REM         end;
REM         /
REM      One Hundred Twenty-Three Million Four Hundred 
REM      Fifty-Six Thousand Seven Hundred Eighty-Nine Dollars
REM      and Fifty-Six Cents
REM
REM **************************************************************
REM DH_UTIL Package Specification
REM **************************************************************
create or replace package dh_util is
   function spell (x in number) return varchar2;
   function check_protect (x in number) return varchar2;
   pragma restrict_references(spell,WNDS);
   pragma restrict_references(check_protect,WNDS);
end;
/

REM **************************************************************
REM DH_UTIL Package Body
REM **************************************************************
create or replace package body dh_util is
  result   varchar2(2000);
  working_integer        number;
  working_decimal        varchar2(100);
  working_dec_mag        number;
  working_integer_spell  varchar2(2000);
  working_decimal_spell  varchar2(2000);
  working_fraction_spell varchar2(2000);
  type number_stencil is table of number
       index by binary_integer;
  type varchar2_stencil is table of varchar2(2000)
       index by binary_integer;
  denom varchar2_stencil;
  pad_factor number_stencil;
  hold varchar2_stencil;

--  **************************************************************

--  pbP[WɓꂽO[o֐`FDH_UTIL.SPELL

--  **************************************************************
function spell (x in number) return varchar2 is
--  **************************************************************

--  [J֐̎dlFWORDING

--  **************************************************************
  function wording (x in number) return varchar2 is
  begin
     if x = 0 then
        return 'Zero';
     else
        return to_char(to_date(x,'j'),'Jsp'); -- Numbers-to-words
     end if;
  end wording;

--  **************************************************************

--  [J֐̎dlFINTEGER_TRANSLATION

--  **************************************************************
  function integer_translation (working_x in number)
           return varchar2 is
     x_char varchar2(128);
     denoms_to_do number;
     start_byte   number;
     pointer      binary_integer;
     interim_spelling varchar2(2000);
  begin
     if working_x is null then
        return 'Null';
     elsif working_x = 0 then
        return 'Zero';
     end if;
     x_char := abs(working_x);
     pointer := 3-mod(length(x_char),3);
     x_char := lpad(x_char,length(x_char)+pad_factor(pointer),'0');
     denoms_to_do := length(x_char)/3;
     result := null;
     for i in 1..denoms_to_do loop
         start_byte := ((i-1)*3)+1;
         interim_spelling := wording(substr(x_char,start_byte,3));
         pointer := (denoms_to_do+1)-i;
         if upper(interim_spelling) <> 'ZERO' then
            result := rtrim(ltrim(result||' '||interim_spelling||
               ' '||denom(pointer)));
         end if;
         hold(i) := result;
     end loop;
     return result;
  end integer_translation;

--  **************************************************************

--  O[o֐SPELL̃vV[WZNV

--  **************************************************************
begin
  working_integer_spell := null;
  working_decimal_spell := null;
  working_fraction_spell := null;
  working_integer := trunc(x);
  if abs(x) > abs(working_integer) then
     working_decimal :=
       substr(rtrim(to_char(abs(x)-abs(working_integer),
       '.00000000000000000000000000000000000000000'),
       '0'),3);
  else     
     working_decimal := null;
     working_dec_mag := null;
  end if; 
  working_integer_spell := integer_translation(working_integer);
  if working_decimal is not null then
     working_dec_mag := 10 ** length(working_decimal);
     working_decimal_spell := 
        ' and '||integer_translation(working_decimal);
     working_fraction_spell :=
        integer_translation(working_dec_mag)||'th';
     if working_decimal > 1 then
        working_fraction_spell := working_fraction_spell||'s';
     end if;
     if upper(substr(working_fraction_spell,1,3))='ONE' then
        working_fraction_spell := substr(working_fraction_spell,5);
     end if;
     working_fraction_spell := ' / '||working_fraction_spell;
  end if;
  if working_integer = 0 and working_decimal_spell is not null then
     result := substr(working_decimal_spell,5)||
        working_fraction_spell;
  else
     result := working_integer_spell||
        working_decimal_spell||working_fraction_spell;
  end if;
  if x < 0 then
     result := 'Negative '||result;
  end if;
  result := replace(result,'  ',' ');
  return result;
end spell;

--  **************************************************************

--  O[o֐̏IFSPELL

--  **************************************************************

--  **************************************************************

--  O[o֐̎dlFCHECK_PROTECT

--  **************************************************************
function check_protect (x in number) return varchar2 is
   hold_dollar number;
   hold_cents  number;
   function check_for_single (y in number, currency in varchar2)
      return varchar2 is
   begin
      if y = 1 then
         return 'One '||currency;
      else
         return spell(y) ||' '||currency||'s';
      end if;
   end;
begin
   if x is null then
      return 'Non Negotiable';
   end if;
   hold_dollar := trunc(x);
   hold_cents  := (abs(x) - trunc(abs(x)))*100;
   return check_for_single(hold_dollar,'Dollar')||' and '||
          check_for_single(hold_cents,'Cent');
end check_protect;

--  **************************************************************

--  gFirst-time-onlyhpbP[W̏ANeBreB

--  **************************************************************
begin
   pad_factor(1) := 1;
   pad_factor(2) := 2;
   pad_factor(3) := 0;
   denom(1) := null;
   denom(2) := 'Thousand';
   denom(3) := 'Million';
   denom(4) := 'Billion';
   denom(5) := 'Trillion';
   denom(6) := 'Quadrillion';
   denom(7) := 'Quintillion';
   denom(8) := 'Sextillion';
   denom(9) := 'Septillion';
   denom(10) := 'Octillion';
   denom(11) := 'Nonillion';
   denom(12) := 'Decillion';
   denom(13) := 'Undecillion';
   denom(14) := 'Duodecillion';
   denom(15) := 'Tredecillion';
   denom(16) := 'Quattuordecillion';
   denom(17) := 'Quindecillion';
   denom(18) := 'Sexdecillion';
   denom(19) := 'Septendecillion';
   denom(20) := 'Octodecillion';
   denom(21) := 'Novemdecillion';
   denom(22) := 'Vigintillion';
   denom(23) := 'Unvigintillion';
   denom(24) := 'Duovigintillion';
   denom(25) := 'Trevigintillion';
   denom(26) := 'Quattuorvigintillion';
   denom(27) := 'Quinvigintillion';
   denom(28) := 'Sexvigintillion';
   denom(29) := 'Septenvigintillion';
   denom(30) := 'Octovigintillion';
   denom(31) := 'Novemvigintillion';
   denom(32) := 'Tregintillion';
   denom(33) := 'Untregintillion';
   denom(34) := 'Duotregintillion';
end dh_util;

--  **************************************************************

--  O[o֐̏IFSPELL

--  **************************************************************
/



Chapter 6
-- Available online as curexamp.sql
DECLARE
  /* ⍇̌ʂi[邽߂̏o͕ϐ */
  v_StudentID    students.id%TYPE;
  v_FirstName    students.first_name%TYPE;
  v_LastName     students.last_name%TYPE;

  /* ⍇̒ŎgpoChϐy */
  v_Major        students.major%TYPE := 'Computer Science';

  /* J[\̐錾 */
  CURSOR c_Students IS
    SELECT id, first_name, last_name
      FROM students
      WHERE major = v_Major;
BEGIN
  /* ANeBuZbg̒̍s𒲂ׁÃf[^ɑ΂鑼̏̏sB */
  OPEN c_Students;
  LOOP
    /* ANeBuZbg̒̊esoāAPL/SQL̕ϐɊi[B */
    FETCH c_Students INTO v_StudentID, v_FirstName, v_LastName;

    /* osȂȂA[vIB */
    EXIT WHEN c_Students%NOTFOUND;
  END LOOP;

  /* ⍇Ŏgp\[XB */
  CLOSE c_Students;
END; 



DECLARE
  v_Department   classes.department%TYPE;
  v_Course       classes.course%TYPE;
  CURSOR c_Classes IS
    SELECT * from classes
      WHERE department = v_Department
      AND course = v_Course;



DECLARE
  CURSOR c_Classes IS
    SELECT * from classes
      WHERE department = v_Department
      AND course = v_Course;
  v_Department   classes.department%TYPE;
  v_Course       classes.course%TYPE;



-- Available online as binds.sql
DECLARE
  v_RoomID      classes.room_id%TYPE;
  v_Building    rooms.building%TYPE;
  v_Department  classes.department%TYPE;
  v_Course      classes.course%TYPE;
  CURSOR c_Buildings IS
    SELECT building
      FROM rooms, classes
      WHERE rooms.room_id = classes.room_id
      and department = v_Department
      and course = v_Course;
BEGIN
  -- J[\OPENOɁAoChϐɒlB
  v_Department := 'HIS';
  v_Course := 101;

  -- J[\I[vB
  OPEN c_Buildings;

  -- oChϐɁAlēxBAJ[\͊ɃI[vς
  -- Ȃ̂ŁȂɂe͂ȂB
  v_Department := 'XXX';
  v_Course := -1;
END; 



FETCH c_Buildings INTO v_Building;



-- Available online as badfetch.sql
DECLARE
  v_Department  classes.department%TYPE;
  v_Course      classes.course%TYPE;
  CURSOR c_AllClasses IS
    SELECT *
      FROM classes;
  v_ClassesRecord  c_AllClasses%ROWTYPE;
BEGIN
  OPEN c_AllClasses;

  -- FETCH́A⍇̑IXgɍvPL/SQL̃R[h
  -- 擪sԂĂ邽ߗLłB
  FETCH c_AllClasses INTO v_ClassesRecord;

  -- FETCH͖łB́A⍇̑IXgł
  -- \classes̗̒7ƂԂĂɂ炸A
  -- 2̕ϐɂi[ĂȂ߂łB
  -- PLS-394G[iFETCHINTO̒l̐Ȃj
  -- ԂB
  FETCH c_AllClasses INTO v_Department, v_Course;
END; 



ORA-1001: J[\łB



ORA-1002: tFb`łB



DECLARE
  v_Department   classes.department%TYPE;
  v_Course       classes.course%TYPE;
  CURSOR c_Classes IS
    SELECT *
     FROM classes
      WHERE department = v_Department
      AND course = v_Course;



DECLARE
  CURSOR c_Classes(p_Department classes.department%TYPE,
                   p_Course classes.course%TYPE) IS
  SELECT *
    FROM classes
    WHERE department = p_Department
    AND course = p_Course;



OPEN c_Classes('HIS', 101);



-- Available online as nomatch1.sql
BEGIN
  UPDATE rooms
    SET number_seats = 100
    WHERE room_id = 99980;
  -- OUPDATEǂ̍sɂvȂꍇ́A
  -- \roomsɐVs1s}B
  IF SQL%NOTFOUND THEN
    INSERT INTO rooms (room_id, number_seats)
      VALUES (99980, 100);
  END IF;
END; 



-- Available online as nomatch2.sql
BEGIN
  UPDATE rooms
    SET number_seats = 100
    WHERE room_id = 99980;
  -- OUPDATEǂ̍sɂvȂꍇ́A
  -- \roomsɐVs1s}B
  IF SQL%ROWCOUNT = 0 THEN
    INSERT INTO rooms (room_id, number_seats)
      VALUES (99980, 100);
  END IF;
END; 



ORA-1403: f[^܂B



-- Available online as nodata.sql
DECLARE
  -- i[邽߂̃R[h
  v_RoomData   rooms%ROWTYPE;
BEGIN
  -- -1ƂID̏oB
  SELECT *
    INTO v_RoomData
    FROM rooms
    WHERE room_id = -1;

  -- Onhɐ䂪Ɉڂ邽߁A̕s邱Ƃ͂ȂB
  IF SQL%NOTFOUND THEN
    INSERT INTO temp_table (char_col)
      VALUES ('Not found!');
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    INSERT INTO temp_table (char_col)
      VALUES ('Not found, exception handler');
END;



-- Available online as simple.sql
DECLARE
  -- jŮwɊւi[邽߂̕ϐ錾B
  v_StudentID   students.id%TYPE;
  v_FirstName   students.first_name%TYPE;
  v_LastName    students.last_name%TYPE;

  -- jŮwɊւo߂̃J[\
  CURSOR c_HistoryStudents IS
    SELECT id, first_name, last_name
      FROM students
      WHERE major = 'History';
BEGIN
  -- J[\I[vAANeBuZbgB
  OPEN c_HistoryStudents;
  LOOP
    -- ̊w̏oB
    FETCH c_HistoryStudents INTO v_StudentID, v_FirstName, v_LastName;

    -- osȂȂA[vIB
    EXIT WHEN c_HistoryStudents%NOTFOUND;

    -- osB̏ꍇ́A\registered_students
    -- }邱ƂɂāAj301̊ewo^B
    -- ܂Atemp_tableւ̖OƐ̋L^sB
    INSERT INTO registered_students (student_id, department, course)
      VALUES (v_StudentID, 'HIS', 301);

    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_StudentID, v_FirstName || ' ' || v_LastName);

  END LOOP;

  -- J[\ŎgpĂ\[XB
  CLOSE c_HistoryStudents;

  -- sʂR~bgB
  COMMIT;
END;



-- Available online as exitwhen.sql
DECLARE
  -- jŮwɊւi[邽߂̕ϐ錾B
  v_StudentID   students.id%TYPE;
  v_FirstName   students.first_name%TYPE;
  v_LastName    students.last_name%TYPE;

  -- jŮwɊւo߂̃J[\
  CURSOR c_HistoryStudents IS
    SELECT id, first_name, last_name
      FROM students
      WHERE major = 'History';
BEGIN
  -- J[\I[vAANeBuZbgB
  OPEN c_HistoryStudents;
  LOOP
    -- ̊w̏oB
    FETCH c_HistoryStudents INTO v_StudentID, v_FirstName, v_LastName;

    -- osB̏ꍇ́A\registered_students
    -- }邱ƂɂāAj301̊ewo^B
    -- ܂Atemp_tableւ̖OƐ̋L^sB
    INSERT INTO registered_students (student_id, department, course)
      VALUES (v_StudentID, 'HIS', 301);

    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_StudentID, v_FirstName || ' ' || v_LastName);


    -- osȂȂA[vIB
    EXIT WHEN c_HistoryStudents%NOTFOUND;

  END LOOP;

  -- J[\ŎgpĂ\[XB
  CLOSE c_HistoryStudents;

  -- sʂR~bgB
  COMMIT;
END;



-- Available online as while.sql
DECLARE
  -- jŮwɊւo߂̃J[\
  CURSOR c_HistoryStudents IS
    SELECT id, first_name, last_name
      FROM students
      WHERE major = 'History';

  -- oi[邽߂̃R[h錾
  v_StudentData  c_HistoryStudents%ROWTYPE;
BEGIN
  -- J[\I[vAANeBuZbgB
  OPEN c_HistoryStudents;

  -- 擪soAWHILE[v̏sB
  FETCH c_HistoryStudents INTO v_StudentData;

  -- [v́AosȂȂ܂őB
  WHILE c_HistoryStudents%FOUND LOOP
    -- osB̏ꍇɂ́A\registered_students
    -- }邱ƂɂāAj301̊ewo^B
    -- ܂Atemp_tableւ̖OƐ̋L^sB
    INSERT INTO registered_students (student_id, department, course)
      VALUES (v_StudentData.ID, 'HIS', 301);

    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_StudentData.ID,
              v_StudentData.first_name || ' ' ||
              v_StudentData.last_name);

    -- ̍soB%FOUND̏Ԃ́Ã[vɐiޑO
    -- `FbNB
    FETCH c_HistoryStudents INTO v_StudentData;
  END LOOP;

  -- J[\ŎgpĂ\[XB
  CLOSE c_HistoryStudents;

  -- sʂR~bgB
  COMMIT;
END; 



-- Available online as forloop.sql
DECLARE
  -- jŮwɊւo߂̃J[\
  CURSOR c_HistoryStudents IS
    SELECT id, first_name, last_name
      FROM students
      WHERE major = 'History';
BEGIN
  -- [v̊JnBc_HistoryStudents̈ÖٓIOPENA
  -- ŎsB
  FOR v_StudentData IN c_HistoryStudents LOOP
    -- ÖٓIFETCHAŎsB

    -- osB̏ꍇ́A\registered_students
    -- }邱ƂɂāAj301̊ewo^B
    -- ܂Atemp_tableւ̖OƐ̋L^sB
    INSERT INTO registered_students (student_id, department, course)
      VALUES (v_StudentData.ID, 'HIS', 301);

    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_StudentData.ID,
              v_StudentData.first_name || ' ' ||
              v_StudentData.last_name);

    -- ̃[vɐiޑOɁAc_HistoryStudentsɊւÖٓIȃ`FbN
    -- ŎsB
  END LOOP;
  -- [vI߁Ac_HistoryStudents%NOTFOUNDɊւÖٓICLOSE
  -- ŎsB

  -- sʂR~bgB
  COMMIT;
END;



DECLARE
  -- ̃J[\ł́AUPDATEɗXg`2LqĂB
  CURSOR c_AllStudents IS
    SELECT *
      FROM students
      FOR UPDATE OF first_name, last_name;

  -- ̃J[\ł́A1LqĂȂB
  CURSOR c_LargeClasses IS
    SELECT department, course
      FROM classes
      WHERE max_students > 50
      FOR UPDATE;



ORA-54: \[XrW[@NOWAITw肳Ă܂B



-- Available online as forupdat.sql
DECLARE
  -- ew̑PʐɒǉׂPʐ
  v_NumCredits  classes.num_credits%TYPE;

  -- HIS 101ɓo^ĂwÃJ[\őIB
  CURSOR c_RegisteredStudents IS
    SELECT *
      FROM students
      WHERE id IN (SELECT student_id
                     FROM registered_students
                     WHERE department= 'HIS'
                     AND course = 101)
      FOR UPDATE OF current_credits;

BEGIN
  -- J[\̎o[v̏sB
  FOR v_StudentInfo IN c_RegisteredStudents LOOP
  -- HIS 101̒Pʐ𒲂ׂ
  SELECT num_credits
    INTO v_NumCredits
    FROM classes
    WHERE department = 'HIS'
    AND course = 101;

  -- J[\o΂̍sXVB
  UPDATE students
    SET current_credits = current_credits + v_NumCredits
    WHERE CURRENT OF c_RegisteredStudents;
  END LOOP;

  -- sʂR~bgB
  COMMIT;
END;



ORA-01002: tFb`łB



-- Available online as commit1.sql
DECLARE
  -- ׂĂ̊wo߂̃J[\BYs̃bNsB
  CURSOR c_AllStudents IS
    SELECT *
      FROM students
      FOR UPDATE;

  -- of[^i[邽߂̕ϐ
  v_StudentInfo  c_AllStudents%ROWTYPE;
BEGIN
  -- J[\I[vBɂāAbNB
  OPEN c_AllStudents;

  -- 擪R[hoB
  FETCH c_AllStudents INTO v_StudentInfo;

  -- COMMIT𔭍sBɂ胍bNAJ[\ƂȂB
  COMMIT WORK;

  -- FETCHsƁAORA-1002̃G[ʒmB
  FETCH c_AllStudents INTO v_StudentInfo;
END;



-- Available online as commit2.sql
DECLARE
  -- ew̑PʐɒǉׂPʐ
  v_NumCredits  classes.num_credits%TYPE;

  -- HIS 101ɓo^ĂwÃJ[\őIB
  CURSOR c_RegisteredStudents IS
    SELECT *
      FROM students
      WHERE id IN (SELECT student_id
                     FROM registered_students
                     WHERE department= 'HIS'
                     AND course = 101);

BEGIN
  -- J[\̎o[v̏sB
  FOR v_StudentInfo IN c_RegisteredStudents LOOP
  -- HIS 101̒Pʐ𒲂ׂ
  SELECT num_credits
    INTO v_NumCredits
    FROM classes
    WHERE department = 'HIS'
    AND course = 101;

  -- J[\o΂̍sXVB
  UPDATE students
    SET current_credits = current_credits + v_NumCredits
    WHERE id = v_Studentinfo.id;

  -- J[\FOR UPDATEwŐ錾ĂȂ߁A
  -- [v̒ŃR~bgsłB
  COMMIT;
  END LOOP;
END;



DECLARE
  -- %ROWTYPEgp`
  TYPE t_StudentsRef IS REF CURSOR
    RETURN students%ROWTYPE;

  -- VR[h^`A
  TYPE t_NameRecord IS RECORD (
    first_name  students.first_name%TYPE,
    last_name   students.last_name%TYPE);

  -- ̌^ϐ`A
  v_NameRecord  t_NameRecord;

  -- قǂ̃R[h^gpăJ[\ϐ`B
  TYPE t_NamesRef IS REF CURSOR
    RETURN t_NameRecord;

  -- `ς݂̃R[h%TYPEŎw肷΁Aʂ̌^錾łB
  TYPE t_NamesRef2 IS REF CURSOR
    RETURN v_NameRecord%TYPE;

  -- Ľ^gpāAJ[\ϐ錾B
  v_StudentCV t_StudentsRef;
  v_NameCV    t_NamesRef;



DECLARE
  -- 񖳂̎Qƌ^`B
  -- TYPE t_FlexibleRef IS REF CURSOR;

  -- āǍ^ϐ`B
  v_CursorVar t_FlexibleRef;



EXEC SQL BEGIN DECLARE SECTION;
  SQL_CURSOR v_CursorVar;
EXEC SQL END DECLARE SECTION;

EXEC SQL ALLOCATE :v_CursorVar;



ORA-6504: PL/SQL: ResultSetϐ̌^ԂꂽA܂͖⍇v܂B



DECLARE
  TYPE t_ClassesRef IS REF CURSOR RETURN classes%ROWTYPE;
  v_ClassesCV t_ClassesRef;



OPEN v_ClassesCV FOR
  SELECT * FROM CLASSES;



OPEN v_ClassesCV FOR
  SELECT department, course FROM CLASSES



-- Available online as cursor1.sql
/* CSQL̃wb_[t@CCN[h */
#include <stdio.h>
EXEC SQL INCLUDE SQLCA;

/* SQL̐錾ZNV zXgϐׂ͂āAŐ錾邱 */
EXEC SQL BEGIN DECLARE SECTION;
  /* [UƃpX[hi[邽߂̕ */
  char *v_Username = "example/example";

  /* SQL̃J[\ϐ */
  SQL_CURSOR v_CursorVar;

  /* \̑I𐧌䂷邽߂̐^ϐ */
  int v_Table;

  /* \roomsŎgpo͕ϐ */
  int v_RoomID;
  VARCHAR v_Description[2001];

  /* \classesŎgpo͕ϐ */
  VARCHAR v_Department[4];
  int v_Course;
EXEC SQL END DECLARE SECTION;


/* G[[`BG[o͂AIB */
void handle_error() {
  printf("SQL Error occurred!\n");
  printf("%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
  EXEC SQL ROLLBACK WORK RELEASE;
  exit(1);
}
  
int main() {
  /* [U[̓͒li[邽ߕ */
  char v_Choice[20];

  /* G[̏BSQLG[
     handle_error()[`R[B */
  EXEC SQL WHENEVER SQLERROR DO handle_error();

  /* f[^x[Xɐڑ */
  EXEC SQL CONNECT :v_Username;
  printf("Connected to Oracle.\n");

  /* J[\ϐɗ̈蓖ĂB */
  EXEC SQL ALLOCATE :v_CursorVar;

  /* l̓͂𑣂bZ[Wo͂A[U[̑Ie
     v_ChoiceɊi[B */
  printf("Choose from (C)lasses or (R)ooms.  Enter c or r: ");
  gets(v_Choice);

  /* \肷B */
  if (v_Choice[0] == 'c')
    v_Table = 1;
  else
    v_Table = 2;

  /* ߍPL/SQLubNgpāAJ[\ϐI[vB */
  EXEC SQL EXECUTE
    BEGIN
      IF :v_Table = 1 THEN
        /* \classesp̕ϐI[vB */
        OPEN :v_CursorVar FOR
          SELECT department, course
            FROM classes;
      ELSE
        /* \roomsp̕ϐI[vB */
        OPEN :v_CursorVar FOR
          SELECT room_id, description
            FROM rooms;
      END IF;
    END;
  END-EXEC;

  /* oIA[v𔲂B */
  EXEC SQL WHENEVER NOT FOUND DO BREAK;

  /* o[vJnB */
  for (;;) {
    if (v_Table == 1) {
      /* NXo */
      EXEC SQL FETCH :v_CursorVar
        INTO :v_Department, :v_Course;

      /* NXʂɕ\Bv_Department́AVARCHAR^ł邽߁A
         ۂ̒ɂ́AlentB[hAf[^ɂ.arrtB[hgpB */
      printf("%.*s %d\n", v_Department.len, v_Department.arr,
                          v_Course);
    }
    else {
      /* oB */
      EXEC SQL FETCH :v_CursorVar
        INTO :v_RoomID, v_Description;

      /* ʂɕ\Bv_DescriptiońAVARCHAR^ł邽߁A
         ۂ̒ɂ́AlentB[hAf[^ɂ.arrtB[hgpB */
      printf("%d %.*s\n", v_RoomID, v_Description.len,
                          v_Description.arr);
    }
  }

  /* J[\N[YB */
  EXEC SQL CLOSE :v_CursorVar;

  /* f[^x[XƂ̐ڑB */
  EXEC SQL COMMIT WORK RELEASE;
}



-- Available online as cursor2.sql
CREATE OR REPLACE PROCEDURE ShowCursorVariable
  /* T[o[ł̃J[\ϐ̎gp@ɂĐB
     p_Table'classes'̏ꍇ́A\classes̏񂪁Atemp_table
     }Bp_Table'rooms'̏ꍇ́A\rooms̏񂪁A
     temp_tableɑ} */
  (p_Table IN VARCHAR2) AS

  /* J[\ϐ̌^`B */
  TYPE t_ClassesRooms IS REF CURSOR;

  /* J[\ϐ̂`B */
  v_CursorVar t_ClassesRooms;

  /* o͓ei[邽߂̕ϐ */
  v_Department  classes.department%TYPE;
  v_Course      classes.course%TYPE;
  v_RoomID      rooms.room_id%TYPE;
  v_Description rooms.description%TYPE;
BEGIN
  -- ̓p[^ɏ]āAJ[\ϐI[vB
  IF p_Table = 'classes' THEN
    OPEN v_CursorVar FOR
      SELECT department, course
        FROM classes;
  ELSIF p_table = 'rooms' THEN
    OPEN v_CursorVar FOR
      SELECT room_id, description
        FROM rooms;
  ELSE
    /* ͒lԈĂꍇ́AG[ʒmB */
    RAISE_APPLICATION_ERROR(-20000,
      'Input must be ''classes'' or ''rooms''');
  END IF;

  /* o[vBFETCȞEXIT WHENLqĂ_ɒ
     PL/SQL 2.3ł́AJ[\ϐƂɁAJ[\̑
     gpłB */
  LOOP
    IF p_Table = 'classes' THEN
      FETCH v_CursorVar INTO
        v_Department, v_Course;
      EXIT WHEN v_CursorVar%NOTFOUND;

      INSERT INTO temp_table (num_col, char_col)
        VALUES (v_Course, v_Department);
    ELSE
      FETCH v_CursorVar INTO
        v_RoomID, v_Description;
      EXIT WHEN v_CursorVAR%NOTFOUND;

      INSERT INTO temp_table (num_col, char_col)
        VALUES (v_RoomID, SUBSTR(v_Description, 1, 60));
    END IF;
  END LOOP;

  /* J[\N[YB */
  CLOSE v_CursorVar;

  COMMIT;
END ShowCursorVariable;



Chapter 7
-- Available online as addstud.sql
CREATE OR REPLACE PROCEDURE AddNewStudent (
  p_FirstName  students.first_name%TYPE,
  p_LastName   students.last_name%TYPE,
  p_Major      students.major%TYPE) AS
BEGIN
  -- \studentsɁAVsPs}BVwID
  -- 邽߂student_sequencegpA
  -- current_credits0ƂB
  INSERT INTO students (ID, first_name, last_name,
                        major,  current_credits)
    VALUES (student_sequence.nextval, p_FirstName, p_LastName,
            p_Major, 0);

  COMMIT;
END AddNewStudent;



BEGIN
  AddNewStudent('David', 'Dinsmore', 'Music');
END;



ORA-00955: łɎgpĂIuWFNgłB



-- Available online as callproc.sql
DECLARE
  -- VwϐɊi[B
  v_NewFirstName  students.first_name%TYPE := 'Margaret';
  v_NewLastName   students.last_name%TYPE := 'Mason';
  v_NewMajor      students.major%TYPE := 'History';
BEGIN
  -- Margaret MasonAf[^x[XɒǉB
  AddNewStudent(v_NewFirstName, v_NewLastName, v_NewMajor);
END;



-- Available online as modetest.sql
CREATE OR REPLACE PROCEDURE ModeTest (
  p_InParameter    IN NUMBER,
  p_OutParameter   OUT NUMBER,
  p_InOutParameter IN OUT NUMBER) IS

  v_LocalVariable  NUMBER;
BEGIN
  /* p_InParameterv_LocalVariableɑBIN[h̃p[^
     ɑ΂āA݂ł͂ȂAǂݍ݂sĂ邽߁Ȁ
     LȏłB */
  v_LocalVariable := p_InParameter;  -- L

  /* p_InParameter7BIN[hp[^ɏ݂
     sĂ邽߂ɁȀ͖ȏłB */
  p_InParameter := 7;  -- 

  /* p_OutParameter7BOUT[hp[^ɑ΂
     ǂݍ݂ł͂ȂA݂sĂ邽߁Ȁ͗L
     łB */
  p_OutParameter := 7;  -- L

  /* p_OutParameterv_LocalVariableɑBOUT[h
     p[^ɑ΂ēǂݍ݂sĂ邽߁Ȁ͖
     łB */
  v_LocalVariable := p_outParameter;  -- 

  /* p_InOutParameterv_LocalVariableɑBIN OUT[h
     p[^ɑ΂ēǂݍ݂sĂ邽߁Ȁ͗L
     łB */
  v_LocalVariable := p_InOutParameter;  -- L

  /* p_InOutParameter7BIN OUT[h̃p[^
     ɑ΂ď݂sĂ邽߁Ȁ͗L
     łB */
  p_InOutParameter := 7;  -- L
END ModeTest;



PLS-00363:	:P_INPARAMETER͊蓖ă^[QbgƂĎgpł܂B
PLS-00365:	P_OUTPARAMETEROUTp[^̂ߓǂݍ߂܂B



DECLARE
  v_Variable1 NUMBER;
  v_Variable2 NUMBER;
BEGIN
  ModeTest(12, v_Variable1, v_Variable2);
END;



DECLARE
  v_Variable1 NUMBER;
BEGIN
  ModeTest(12, v_Variable1, 11);
END;



s:4ŃG[܂B
ORA-06550: s: 4A: 28:
PLS-00363: :11͑ƂĖłB
ORA-06550: s: 4A: 3:
PL/SQL: Statement ignored



CREATE OR REPLACE PROCEDURE procedure_name AS
   /*錾ZNV*/
BEGIN
   /*s\ZNV */
EXCEPTION
   /*OZNV*/
END [procedure_name];



-- Available online as part of plength.sql
CREATE OR REPLACE PROCEDURE ParameterLength (
  p_Parameter1 IN OUT VARCHAR2(10),
  p_Parameter2 IN OUT NUMBER(3,2)) AS
BEGIN
  p_Parameter1 := 'abcdefghijklm';
  p_Parameter2 := 12.3;
END ParameterLength;



-- Available online as part of plength.sql
CREATE OR REPLACE PROCEDURE ParameterLength (
  p_Parameter1 IN OUT VARCHAR2,
  p_Parameter2 IN OUT NUMBER) AS
BEGIN
  p_Parameter1 := 'abcdefghijklmno';
  p_Parameter2 := 12.3;
END ParameterLength;



-- Available online as part of plength.sql
DECLARE
  v_Variable1 VARCHAR2(40);
  v_Variable2 NUMBER(3,4);
BEGIN
  ParameterLength(v_Variable1, v_Variable2);
END;



-- Available online as part of plength.sql
DECLARE
  v_Variable1 VARCHAR2(10);
  v_Variable2 NUMBER(3,4);
BEGIN
  ParameterLength(v_Variable1, v_Variable2);
END;



ORA-06502: PL/SQL: l܂͐lG[܂B



-- Available online as part of plength.sql
CREATE OR REPLACE PROCEDURE ParameterLength (
  p_Parameter1 IN OUT VARCHAR2,
  p_Parameter2 IN OUT students.current_credits%TYPE) AS
BEGIN
  p_Parameter2 := 12345;
END ParameterLength;



-- Available online as part of plength.sql
DECLARE
  v_Variable1 VARCHAR2(1);
  v_Variable2 NUMBER; -- w肵Ȃv_Variable2錾B
BEGIN
  -- 12345i[ł̈悪p[^ɂĂA
  -- p[^ɑ΂鐧񂪎gp邽߁A
  -- vV[WR[łORA-6502ԂB
  ParameterLength(v_Variable1, v_Variable2);
END;



-- Available online as part of callme.sql
CREATE OR REPLACE PROCEDURE CallMe (
  p_ParameterA VARCHAR2,
  p_ParameterB NUMBER,
  p_ParameterC BOOLEAN,
  p_ParameterD DATE) AS
BEGIN
  @NULL;
END CallMe;



-- Available online as part of callme.sql
DECLARE
  v_Variable1 VARCHAR2(10);
  v_Variable2 NUMBER(7,6);
  v_Variable3 BOOLEAN;
  v_Variable4 DATE;
BEGIN
  CallMe(v_Variable1, v_Variable2, v_Variable3, v_Variable4);
END;



-- Available online as part of callme.sql
DECLARE
  v_Variable1 VARCHAR2(10);
  v_Variable2 NUMBER(7,6);
  v_Variable3 BOOLEAN;
  v_Variable4 DATE;
BEGIN
  CallMe(p_ParameterA => v_Variable1, 
         p_ParameterB => v_Variable2,
         p_ParameterC => v_Variable3,
         p_ParameterD => v_Variable4);
END;



-- Available online as part of callme.sql
DECLARE
  v_Variable1 VARCHAR2(10);
  v_Variable2 NUMBER(7,6);
  v_Variable3 BOOLEAN;
  v_Variable4 DATE;
BEGIN
  CallMe(p_ParameterB => v_Variable2, 
         p_ParameterC => v_Variable3,
         p_ParameterD => v_Variable4,
         p_ParameterA => v_Variable1);
END;



-- Available online as part of callme.sql
DECLARE
  v_Variable1 VARCHAR2(10);
  v_Variable2 NUMBER(7,6);
  v_Variable3 BOOLEAN;
  v_Variable4 DATE;
BEGIN
  -- 擪2̃p[^͈ʒu\L@Ŏw肵Ac2̃p[^
  -- O\L@Ŏw肵ĂB
  CallMe(v_Variable1, v_Variable2, 
         p_ParameterC => v_Variable3,
         p_ParameterD => v_Variable4);
END;



-- Available online as default.sql
CREATE OR REPLACE PROCEDURE AddNewStudent (
  p_FirstName  students.first_name%TYPE,
  p_LastName   students.last_name%TYPE,
  p_Major      students.major%TYPE DEFAULT 'Economics') AS
BEGIN
  -- \studentsɁAVsPs}
  -- student_sequencegpĐVwID𐶐A
  -- current_credits0ݒ肷
  INSERT INTO students VALUES (student_sequence.nextval, 
    p_FirstName, p_LastName, p_Major, 0);

  COMMIT;
END AddNewStudent;



BEGIN
  AddNewStudent('Barbara', 'Blues');
END;



BEGIN
  AddNewStudent(p_FirstName => 'Barbara',
                p_LastName => 'Blues');
END;



CREATE OR REPLACE PROCEDURE DefaultTest (
  p_ParameterA NUMBER DEFAULT 10,
  p_ParameterB VARCHAR2 DEFAULT 'abcdef',
  p_ParameterC DATE DEFAULT sysdate) AS
BEGIN
  ...
END DefaultTest;



BEGIN
  DefaultTest(p_ParameterA => 7, p_ParameterC => '30-DEC-95');
END;



BEGIN
  /* p_ParameterBp_ParameterC̗ɁA
     ftHglꍇ */
  DefaultTest(7);
END;



-- Available online as almostfl.sql
CREATE OR REPLACE FUNCTION AlmostFull (
  p_Department classes.department%TYPE,
  p_Course     classes.course%TYPE)
  RETURN BOOLEAN IS

  v_CurrentStudents NUMBER;
  v_MaxStudents     NUMBER;
  v_ReturnValue     BOOLEAN;
  v_FullPercent     CONSTANT NUMBER := 90;
BEGIN
  -- vꂽwȂ݂̌̊wƒiőlj擾B
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = p_Department
    AND course = p_Course;

  -- NX̒ɑ΂w̗v_FullPercent̃p[Ze[W
  -- 𒴂ĂꍇTRUEԂAłȂꍇFALSEԂB
  IF (v_CurrentStudents / v_MaxStudents * 100) > v_FullPercent THEN
    v_ReturnValue := TRUE;
  ELSE
    v_ReturnValue := FALSE;
  END IF;

  RETURN v_ReturnValue;
END AlmostFull;



-- Available online as callfunc.sql
DECLARE
  CURSOR c_Classes IS
    SELECT department, course
      FROM classes;
BEGIN
  FOR v_ClassRecord IN c_Classes LOOP
    -- Ȑɗ]T܂ȂNXׂ
    -- temp_tableɋL^B
    IF AlmostFull(v_ClassRecord.department, v_ClassRecord.course) 
    THEN
      INSERT INTO temp_table (char_col) VALUES
        (v_ClassRecord.department || ' ' || v_ClassRecord.course 
         || ' is almost full!');
    END IF;
  END LOOP;
END;



-- Available online as clasinfo.sql
CREATE OR REPLACE FUNCTION ClassInfo (
  /* NXt̏ꍇɂ'Full'A
     NX80%𒴂Ăꍇɂ'Some Room'A
     NX60%𒴂Ăꍇɂ'More Room'A
     NX݋60%ȉ̏ꍇɂ'Lots of Room'A
     o^wȂꍇɂ'Empty'ԂB */
  p_Department classes.department%TYPE,
  p_Course     classes.course%TYPE)
  RETURN VARCHAR2 IS

  v_CurrentStudents NUMBER;
  v_MaxStudents     NUMBER;
  v_PercentFull     NUMBER;
BEGIN
  -- vꂽwȂ݂̌̊wƒiő吔j擾B
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = p_Department
    AND course = p_Course;

  -- ݂̍݋\p[Ze[WvZB
  v_PercentFull := v_CurrentStudents / v_MaxStudents * 100;

  IF v_PercentFull = 100 THEN
    RETURN 'Full';
  ELSIF v_PercentFull > 80 THEN
    RETURN 'Some Room';
  ELSIF v_PercentFull > 60 THEN
    RETURN 'More Room';
  ELSIF v_PercentFull > 0 THEN
    RETURN 'Lots of Room';
  ELSE
    RETURN 'Empty';
  END IF;
END ClassInfo; 



-- Available online as part of error.sql
CREATE OR REPLACE PROCEDURE RaiseError (
  /* OOUT[h̕ϐ̓ɂĐB
     p_RaiseTRUȄꍇ́AG[ʒmB
     p_RaiseFALSȄꍇ́A{vV[W͐ɏIB */
  p_Raise IN BOOLEAN := TRUE,
  p_ParameterA OUT NUMBER) AS
BEGIN
  p_ParameterA := 7;

  IF p_Raise THEN
    /* p_ParameterA7A̖OƁA
       p_ParameterAɊYp[^7Ԃ邱ƂȂA
       䂪ɖ߂B */
    RAISE DUP_VAL_ON_INDEX;
  ELSE
    /* G[Ȃꍇ́APɃ^[B̏ꍇ́AY
       p[^7ԂB */
    RETURN;
  END IF;
END RaiseError;



-- Available online as part of error.sql
DECLARE
  v_TempVar NUMBER := 1;
BEGIN
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_TempVar, 'Initial value');
  RaiseError(FALSE, v_TempVar);

  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_TempVar, 'Value after successful call');

  v_TempVar := 2;
  INSERT INTO temp_table (num_col, char_col)
    VALUES (v_TempVar, 'Value before 2nd call');
  RaiseError(TRUE, v_TempVar);
EXCEPTION
  WHEN OTHERS THEN
    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_TempVar, 'Value after unsuccessful call');
END;



SQL> SELECT * FROM temp_table;

  NUM_COL CHAR_COL
--------- --------------------------------
        1 Initial value
        7 Value after successful call
        2 Value before 2nd call
        2 Value after unsuccessful call



DROP TABLE AddNewStudent;



CREATE OR REPLACE PROCEDURE Simple AS
  v_Counter NUMBER;
BEGIN
  v_Counter := 7;
END Simple;



CREATE OR REPLACE PROCEDURE Simple AS
  v_Counter NUMBER;
BEGIN
  v_Counter := 7
END Simple;



PLS-905: IuWFNg:<O>͖łB



-- Available online as local.sql
DECLARE
  CURSOR c_AllStudents IS
    SELECT first_name, last_name
      FROM students;

  v_FormattedName VARCHAR2(50);

  /* ̊֐ł́AOƐ󔒂PŘAgĕԂB */
  FUNCTION FormatName(p_FirstName IN VARCHAR2,
                      p_LastName IN VARCHAR2)
    RETURN VARCHAR2 IS
  BEGIN
    RETURN p_FirstName || ' ' || p_LastName;
  END FormatName;

-- CubN̊Jn
BEGIN
  FOR v_StudentRecord IN c_AllStudents LOOP
    v_FormattedName := 
      FormatName(v_StudentRecord.first_name, 
                 v_StudentRecord.last_name);  
    INSERT INTO temp_table (char_col)
      VALUES (v_FormattedName);
  END LOOP;

  COMMIT;
END;



-- Available online as local2.sql
DECLARE
  /* FormatName܂錾B̂悤ȂƂsƁARpCG[
     ɂȂBȂȂA[JȃTuvÓÂׂ̂Đ錾
     Ő錾Ȃ΂ȂȂ߂łB /*
  FUNCTION FormatName(p_FirstName IN VARCHAR2,
                      p_LastName IN VARCHAR2)
    RETURN VARCHAR2 IS
  BEGIN
    RETURN p_FirstName || ' ' || p_LastName;
  END FormatName;

  CURSOR c_AllStudents IS
    SELECT first_name, last_name
      FROM students;

  v_FormattedName VARCHAR2(50);
-- CubN̊JnB
BEGIN
  NULL;
END;



-- Available online as mutual.sql
DECLARE
  v_TempVal BINARY_INTEGER := 5;

  -- [JvV[WABvV[WBR[Ă_ɒӁB
  PROCEDURE A(p_Counter IN OUT BINARY_INTEGER) IS
  BEGIN
    IF p_Counter > 0 THEN
      B(p_Counter);
      p_Counter := p_Counter - 1;
    END IF;
  END A;
  -- [JvV[WBBvV[WAR[Ă_ɒӁB
  PROCEDURE B(p_Counter IN OUT BINARY_INTEGER) IS
  BEGIN
    p_Counter := p_Counter - 1;
    A(p_Counter);
  END B;
BEGIN
  B(v_TempVal);
END;



-- Available online as forward.sql
DECLARE
  v_TempVal BINARY_INTEGER := 5;

  -- vV[WB̑O錾
  PROCEDURE B(p_Counter IN OUT BINARY_INTEGER);

  PROCEDURE A(p_Counter IN OUT BINARY_INTEGER) IS
  BEGIN
    IF p_Counter > 0 THEN
      B(p_Counter);
      p_Counter := p_Counter - 1;
    END IF;
  END A;

  PROCEDURE B(p_Counter IN OUT BINARY_INTEGER) IS
  BEGIN
    p_Counter := p_Counter - 1;
    A(p_Counter);
  END B;
BEGIN
  B(v_TempVal);
END;



-- Available online as rfclass.sql
CREATE OR REPLACE PROCEDURE RecordFullClasses AS
  CURSOR c_Classes IS
    SELECT department, course
      FROM classes;
BEGIN
  FOR v_ClassRecord IN c_Classes LOOP
    -- Ȑɗ]T܂ȂNXׂtemp_tableɋL^B
    IF AlmostFull(v_ClassRecord.department,
    THEN
v_ClassRecord.course) 
      INSERT INTO temp_table (char_col) VALUES
        (v_ClassRecord.department || ' ' || v_ClassRecord.course ||
         ' is almost full!');
    END IF;
  END LOOP;
END RecordFullClasses;



ALTER TABLE classes ADD (
  student_rating  NUMBER(2)); -- Փx\li1`10jB



P2(...)@DBLINK 



-- Available online as rfclass.sql
CREATE OR REPLACE PROCEDURE RecordFullClasses AS
  CURSOR c_Classes IS
    SELECT department, course
      FROM classes;
BEGIN
  FOR v_ClassRecord IN c_Classes LOOP
    -- Ȑɗ]T܂ȂNXA
    -- ׂtemp_tableɋL^B
    IF AlmostFull(v_ClassRecord.department, v_ClassRecord.course) THEN
      INSERT INTO temp_table (char_col) VALUES
        (v_ClassRecord.department || ' ' || v_ClassRecord.course ||
         ' is almost full!');
    END IF;
  END LOOP;
END RecordFullClasses;



GRANT EXECUTE on RecordFullClasses TO UserB;



BEGIN
  UserA.RecordFullClasses;
END;



CREATE OR REPLACE PROCEDURE RecordFullClasses AS
  CURSOR c_Classes IS
    SELECT department, course
      FROM UserA.classes;
BEGIN
  FOR v_ClassRecord IN c_Classes LOOP
    -- Ȑɗ]T܂ȂNXA
    -- ׂtemp_tableɋL^B
    IF UserA.AlmostFull(v_ClassRecord.department, 
                        v_ClassRecord.course) THEN
      INSERT INTO temp_table (char_col) VALUES
        (v_ClassRecord.department || ' ' || v_ClassRecord.course ||
         ' is almost full!');
    END IF;
  END LOOP;
END RecordFullClasses;



GRANT SELECT ON classes TO UserB;
GRANT EXECUTE ON AlmostFull TO UserB;



CREATE ROLE UserA_Role;
GRANT SELECT ON classes TO UserA_Role;
GRANT EXECUTE ON AlmostFull TO UserA_Role;
GRANT UserA_Role to UserB;



PLS-201:	ʎq: CLASSES͐錾Ă܂B
PLS-201:	ʎq: ALMOSTFULL͐錾Ă܂B



Chapter 8
-- Available online as part of clpack.sql
CREATE OR REPLACE PACKAGE ClassPackage AS
  -- w肳ꂽNXɐVw1lǉB
  PROCEDURE AddStudent(p_StudentID  IN students.id%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE);

  -- w肳ꂽNXAw肳ꂽw폜B
  PROCEDURE RemoveStudent(p_StudentID  IN students.id%TYPE,
                          p_Department IN classes.department%TYPE, 
                          p_Course     IN classes.course%TYPE);

  -- RemoveStudentʒmO
  e_StudentNotRegistered EXCEPTION;

  -- ẘi[Ɏgp\̌^
  TYPE t_StudentIDTable IS TABLE OF students.id%TYPE
    INDEX BY BINARY_INTEGER;

  -- w肳ꂽNXɌݏĂwi[ꂽPL/SQL\ԂB
  PROCEDURE ClassList(p_Department  IN  classes.department%TYPE,
                      p_Course      IN  classes.course%TYPE,
                      p_IDs         OUT t_StudentIDTable,
                      p_NumStudents IN OUT BINARY_INTEGER);
END ClassPackage;



-- Available online as part of clpack.sql
CREATE OR REPLACE PACKAGE BODY ClassPackage AS
  -- w肳ꂽNXɐVw1lǉB
  PROCEDURE AddStudent(p_StudentID  IN students.id%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE) IS
  BEGIN
    INSERT INTO registered_students (student_id, department, course)
      VALUES (p_StudentID, p_Department, p_Course);
    COMMIT;
  END AddStudent;


  -- w肳ꂽNXAw肳ꂽw폜B
  PROCEDURE RemoveStudent(p_StudentID  IN students.id%TYPE,
                          p_Department IN classes.department%TYPE, 
                          p_Course     IN classes.course%TYPE) IS
  BEGIN
    DELETE FROM registered_students
      WHERE student_id = p_StudentID
      AND department = p_Department
      AND course = p_Course;

    -- DELETEǂA`FbNB
    -- vsȂꍇ́AG[ʒmB
    IF SQL%NOTFOUND THEN
      RAISE e_StudentNotRegistered;
    END IF;

    COMMIT;
  END RemoveStudent;


  -- w肳ꂽNXɌݏĂwi[ꂽPL/SQL\
  -- ԂB
  PROCEDURE ClassList(p_Department  IN  classes.department%TYPE,
                      p_Course      IN  classes.course%TYPE,
                      p_IDs         OUT t_StudentIDTable,
                      p_NumStudents IN OUT BINARY_INTEGER) IS

    v_StudentID  registered_students.student_id%TYPE;

    -- o^ς݂̊wo߂̃[JȃJ[\
    CURSOR c_RegisteredStudents IS
      SELECT student_id
        FROM registered_students
        WHERE department = p_Department
        AND course = p_Course;
  BEGIN
    /* p_NumStudentśA\̍ƂĎgpB
       ܂A0n߁Ao[vs邽т+1ɂB
       [v̏Iɂ́AošɂȂ邽߁A
       p_IDsɕԂꂽšɓȂB */
    p_NumStudents := 0;

    OPEN c_RegisteredStudents;
    LOOP
      FETCH c_RegisteredStudents INTO v_StudentID;
      EXIT WHEN c_RegisteredStudents%NOTFOUND;

      p_NumStudents := p_NumStudents + 1;
      p_IDs(p_NumStudents) := v_StudentID;
    END LOOP;
  END ClassList;
END ClassPackage;



CREATE OR REPLACE PACKAGE PackageA AS
  FUNCTION FunctionA(p_Parameter1 IN NUMBER,
                     p_Parameter2 IN DATE)
    RETURN VARCHAR2;
END PackageA;

CREATE OR REPLACE PACKAGE BODY PackageA AS
  FUNCTION FunctionA(p_Parameter1 IN CHAR)
    RETURN VARCHAR2;
END PackageA;



PLS-00328: 錾ZNV:FUNCTIONAɃTuvO{̂`Ȃ΂Ȃ܂B
PLS-00323: TuvO܂̓J[\FUNCTIONA̓pbP[WdlZNVŐ錾Ă			     ApbP[W{̂ł`Ȃ΂Ȃ܂B



BEGIN
  ClassPackage.RemoveStudent(10006, 'HIS', 101);
END;



-- Available online as cllist.sql
DECLARE
  v_HistoryStudents ClassPackage.t_StudentIDTable;
  v_NumStudents     BINARY_INTEGER := 20;
BEGIN
  -- j101̐擪20̊wAPL/SQL\Ɋi[B
  ClassPackage.ClassList('HIS', 101, v_HistoryStudents,
                         v_NumStudents);

  -- ̊wAtemp_tableɑ}B
  FOR v_LoopCounter IN 1..v_NumStudents LOOP
    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_HistoryStudents(v_LoopCounter), 
              'In History 101');
  END LOOP;
END;



-- Available online as overload.sql
CREATE OR REPLACE PACKAGE ClassPackage AS
  -- w肳ꂽNXɁAVw1lǉB
  PROCEDURE AddStudent(p_StudentID  IN students.id%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE);

  -- IDԍł͂ȂAw肷邱Ƃɂ
  -- Vw1lǉB
  PROCEDURE AddStudent(p_FirstName IN students.first_name%TYPE,
                       p_LastName  IN students.last_name%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE);
  
END ClassPackage;

CREATE OR REPLACE PACKAGE BODY ClassPackage AS
  -- w肳ꂽNXɁAVw1lǉB
  PROCEDURE AddStudent(p_StudentID  IN students.id%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE) IS
  BEGIN
    INSERT INTO registered_students (student_id, department, course)
      VALUES (p_StudentID, p_Department, p_Course);
    COMMIT;
  END AddStudent;

  -- IDł͂ȂOw肷邱ƂɂāAVw1lǉB
  PROCEDURE AddStudent(p_FirstName IN students.first_name%TYPE,
                       p_LastName  IN students.last_name%TYPE,
                       p_Department IN classes.department%TYPE, 
                       p_Course     IN classes.course%TYPE) IS
    v_StudentID students.ID%TYPE;
  BEGIN
    /* ܂A\studentsID擾KvB */
    SELECT ID
      INTO v_StudentID
      FROM students
      WHERE first_name = p_FirstName
      AND last_name = p_LastName;

    -- ID擾łAIDɂĊwǉłB
    INSERT INTO registered_students (student_id, department, course)
      VALUES (v_StudentID, p_Department, p_Course);
    COMMIT;
  END AddStudent;
  
END ClassPackage;



BEGIN
  ClassPackage.AddStudent(10000, 'MUS', 410);
END;



BEGIN
  ClassPackage.AddStudent('Barbara', 'Blues', 'MUS', 410);
END;



-- Available online as random.sql
CREATE OR REPLACE PACKAGE Random AS
/* ̔BCrand()֐ƓASYgpB */

  -- V[h̕ύXɎgpAV[hł΁A
  -- V[PXŐB
  PROCEDURE ChangeSeed(p_NewSeed IN NUMBER);

  -- 132767͈̔͂ɂ鐮̗ԂB
  FUNCTION Rand RETURN NUMBER;

  -- RandƓlł邪AvV[W^̃C^tF[XĂB
  PROCEDURE GetRand(p_RandomNumber OUT NUMBER);

  -- 1p_MaxVal͈̔͂ɂ鐮̗ԂB
  FUNCTION RandMax(p_MaxVal IN NUMBER) RETURN NUMBER;

  -- RandMaxƓlł邪AvV[W^̃C^tF[XĂB
  PROCEDURE GetRandMax(p_RandomNumber OUT NUMBER,
                       p_MaxVal IN NUMBER);
END Random;
/

CREATE OR REPLACE PACKAGE BODY Random AS

  /* ̐ľvZɎgp */
  v_Multiplier  CONSTANT NUMBER := 22695477;
  v_Increment   CONSTANT NUMBER := 1;

  /* A̗𔭐邽߂̃V[h */
  v_Seed        number := 1;

  PROCEDURE ChangeSeed(p_NewSeed IN NUMBER) IS
  BEGIN
    v_Seed := p_NewSeed;
  END ChangeSeed;

  FUNCTION Rand RETURN NUMBER IS
  BEGIN
    v_Seed := MOD(v_Multiplier * v_Seed + v_Increment,
                  (2 ** 32));
    RETURN BITAND(v_Seed/(2 ** 16), 32767);
  END Rand;

  PROCEDURE GetRand(p_RandomNumber OUT NUMBER) IS
  BEGIN
    -- PRandR[AlԂB
    p_RandomNumber := Rand;
  END GetRand;

  FUNCTION RandMax(p_MaxVal IN NUMBER) RETURN NUMBER IS
  BEGIN
    RETURN MOD(Rand, p_MaxVal) + 1;
  END RandMax;

  PROCEDURE GetRandMax(p_RandomNumber OUT NUMBER,
                       p_MaxVal IN NUMBER) IS
  BEGIN
    -- PRandMaxR[AlԂB
    p_RandomNumber := RandMax(p_MaxVal);
  END GetRandMax;

BEGIN
  /* pbP[W̏BV[h̒l݂̎ibPʁjŏB */
  ChangeSeed(TO_NUMBER(TO_CHAR(SYSDATE, 'SSSSS')));
END Random;



-- Available online as depend.sql
SQL> -- ܂ȒPȕ\쐬B
SQL> CREATE TABLE simple_table (f1 NUMBER);

Table created.

SQL> 
SQL> -- ɁA̕\QƂpbP[WvV[W쐬B
SQL> CREATE OR REPLACE PACKAGE Dependee AS
  2    PROCEDURE Example(p_Val IN NUMBER);
  3  END Dependee;
  4  /

Package created.

SQL> 
SQL> CREATE OR REPLACE PACKAGE BODY Dependee AS
  2    PROCEDURE Example(p_Val IN NUMBER) IS
  3    BEGIN
  4     INSERT INTO simple_table VALUES (p_Val);
  5    END Example;
  6  END Dependee;
  7  /

Package body created.

SQL> 
SQL> -- ɁADependeeQƂvV[W쐬B
SQL> CREATE OR REPLACE PROCEDURE Depender(p_Val IN NUMBER) AS
  2  BEGIN
  3    Dependee.Example(p_Val + 1);
  4  END Depender;
  5  /

Procedure created.

SQL> 
SQL> -- user_objects⍇āAׂẴIuWFNgLǂmFB
SQL> SELECT object_name, object_type, status
  2    FROM user_objects
  3    WHERE object_name IN ('DEPENDER', 'DEPENDEE', 'SIMPLE_TABLE');

OBJECT_NAME                    OBJECT_TYPE   STATUS
------------------------------ ------------- -------
SIMPLE_TABLE                   TABLE         VALID
DEPENDEE                       PACKAGE       VALID
DEPENDEE                       PACKAGE BODY  VALID
DEPENDER                       PROCEDURE     VALID

SQL> 
SQL> -- pbP[W{݂̂̂ύXBwb_[ɕύXȂƂɒӁB
SQL> CREATE OR REPLACE PACKAGE BODY Dependee AS
  2    PROCEDURE Example(p_Val IN NUMBER) IS
  3    BEGIN
  4     INSERT INTO simple_table VALUES (p_Val - 1);
  5    END Example;
  6  END Dependee;
  7  /

Package body created.

SQL> 
SQL> -- user_objectsDepender܂Lł邱Ƃ\B
SQL> SELECT object_name, object_type, status
  2    FROM user_objects
  3    WHERE object_name IN ('DEPENDER', 'DEPENDEE', 'SIMPLE_TABLE');

OBJECT_NAME                    OBJECT_TYPE   STATUS
------------------------------ ------------- -------
SIMPLE_TABLE                   TABLE         VALID
DEPENDEE                       PACKAGE       VALID
DEPENDEE                       PACKAGE BODY  VALID
DEPENDER                       PROCEDURE     VALID

SQL> 
SQL> -- ̕\폜ĂAɂȂ̂̓pbP[W{̂B
SQL> DROP TABLE simple_table;

Table dropped.

SQL> SELECT object_name, object_type, status
  2    FROM user_objects
  3    WHERE object_name IN ('DEPENDER', 'DEPENDEE', 'SIMPLE_TABLE');

OBJECT_NAME                    OBJECT_TYPE   STATUS
------------------------------ ------------- -------
DEPENDEE                       PACKAGE       VALID
DEPENDEE                       PACKAGE BODY  INVALID
DEPENDER                       PROCEDURE     VALID 



-- Available online as fullname.sql
CREATE OR REPLACE FUNCTION FullName (
  p_StudentID  students.ID%TYPE)
  RETURN VARCHAR2 IS

  v_Result  VARCHAR2(100);
BEGIN
  SELECT first_name || ' ' || last_name
    INTO v_Result
    FROM students
    WHERE ID = p_StudentID;

  RETURN v_Result;
END FullName;



SQL> SELECT ID, FullName(ID) "Full Name"
  2    FROM students;

       ID Full Name
--------- -------------------------------
    10000 Scott Smith
    10001 Margaret Mason
    10002 Joanne Junebug
    10003 Manish Murgratroid
    10004 Patrick Poll
    10005 Timothy Taller
    10006 Barbara Blues
    10007 David Dinsmore
    10008 Ester Elegant
    10009 Rose Riznit
    10010 Rita Razmataz

11 rows selected.
SQL> INSERT INTO temp_table (char_col)
  2    VALUES (FullName(10010));

1 row created.



-- Available online as studops.sql
CREATE OR REPLACE PACKAGE StudentOps AS
  FUNCTION FullName(p_StudentID IN students.ID%TYPE)
    RETURN VARCHAR2;
  PRAGMA RESTRICT_REFERENCES(FullName, WNDS, WNPS, RNPS);

  /* jŮwԂB */
  FUNCTION NumHistoryMajors
    RETURN NUMBER;
  PRAGMA RESTRICT_REFERENCES(NumHistoryMajors, WNDS, WNPS, RNPS);
END StudentOps;
/

CREATE OR REPLACE PACKAGE BODY StudentOps AS

  -- jŮwi[邽߂̃pbP[Wϐ
  v_NumHist NUMBER;

  FUNCTION FullName(p_StudentID IN students.ID%TYPE)
    RETURN VARCHAR2 IS
    v_Result  VARCHAR2(100);
  BEGIN
    SELECT first_name || ' ' || last_name
      INTO v_Result
      FROM students
      WHERE ID = p_StudentID;

    RETURN v_Result;
  END FullName;

  FUNCTION NumHistoryMajors RETURN NUMBER IS
    v_Result NUMBER;
  BEGIN
    IF v_NumHist IS NULL THEN
      /* ړÎ̂擾B */
      SELECT COUNT(*)
        INTO v_Result
        FROM students
        WHERE major = 'History';
      /* 擾̂AŎgpł悤ɕۑB */
      v_NumHist := v_Result;
    ELSE
      v_Result := v_NumHist;
    END IF;

    RETURN v_Result;
  END NumHistoryMajors;
END StudentOps;



CREATE OR REPLACE PACKAGE StudentOps AS
  PRAGMA RESTRICT_REFERENCES (StudentOps, WNDS, WNPS, RNPS);
  ...
END StudentOps;



CREATE OR REPLACE PACKAGE TestPackage AS
  FUNCTION F(p_ParameterOne IN NUMBER) RETURN VARCHAR2;
  FUNCTION F RETURN DATE;
  PRAGMA RESTRICT_REFERENCES(F, WNDS, RNDS);
END TestPackage;



SELECT FullName(p_StudentID => 10000) FROM dual;



-- Available online as export.sql
CREATE OR REPLACE PACKAGE Export AS
  /* 1̃IuWFNgGNX|[gBp[^͎̂悤ɎgpF
   * p_SchemaF		GNX|[gIuWFNg̏L҂w肷B
   * p_ObjTypeF		IuWFNg̃^Cvw肷BLĺA'PACKAGE', 'PACKAGE 		   * 					BODY', 'PROCEDURE', 'FUNCTION'܂'TRIGGER'BNULL		   * 					w肷ƁAIuWFNg^Cvall_objectsIČ肳	   * 					B
   * p_BothTypesF	TRUȄꍇAp_ObjType='PACKAGE'ł΁ApbP[WƃpbP[W	   * 					{fB̗GNX|[gB
   * p_FileDirF		o̓t@C̍쐬fBNg
   * p_FileNameF	o̓t@C̖O
   * p_ModeF			o̓t@C̃[hiǉ'A'܂͏݂'W'j
   */ 
  PROCEDURE OneObj(p_Schema IN VARCHAR2,
                   p_ObjName IN VARCHAR2,
                   p_ObjType IN VARCHAR2 DEFAULT NULL,
                   p_BothTypes IN BOOLEAN DEFAULT TRUE, 
                   p_FileDir IN VARCHAR2,
                   p_FileName IN VARCHAR2,
                   p_Mode IN VARCHAR2);
 
  /* ̃^Cvׂ̂ẴIuWFNgGNX|[gBp[^͎̂悤Ɏgp		     BF
   * p_SchemaF		GNX|[gIuWFNg̏L҂w肷B
   * p_ObjTypeF		IuWFNg̃^Cvw肷BLĺA'PACKAGE', 'PACKAGE 		   * 					BODY', 'PROCEDURE', 'FUNCTION'܂'TRIGGER'Bw肷		   * 					ƁÃ^Cvp_SchemaɂďL邷ׂẴIuWFNg	   *  					GNX|[gB  
   * p_FileDirF		o̓t@C̍쐬fBNg
   * p_FileNameF	o̓t@C̖O
   * p_ModeF			o̓t@C̃[hiǉ'A'܂͏݂'W'j
   */
  PROCEDURE AllObjs(p_Schema IN VARCHAR2,
                    p_ObjType IN VARCHAR2 DEFAULT NULL,
                    p_FileDir IN VARCHAR2,
                    p_FileName IN VARCHAR2,
                    p_Mode IN VARCHAR2);
END Export;
CREATE OR REPLACE PACKAGE BODY Export AS
    /*	̓pbP[W̔nԔnIvV[WłBOutputObj́Ap_SchemaAp_ObjName	     *	p_ObjTypeɂĎw肳ꂽ1̃IuWFNgAp_FileHandleɂĎw		     *	ꂽt@Cɏo͂B݂sł悤ɁAt@C͂łɁi'W'܂		     *	'A'[hŁjJĂȂ΂ȂȂB 
    */
  PROCEDURE OutputObj(p_FileHandle IN OUT UTL_FILE.FILE_TYPE,
                      p_Schema IN VARCHAR2,
                      p_ObjName IN VARCHAR2,
                      p_ObjType IN VARCHAR2) IS

    /*	̕ϐ́AgK[eLXg̎oɎgpBall_triggersLONG^			ăgK[{fBi[̂ŁA`NPʂLONG^tFb`ɂDBMS_SQL		gpȂ΂ȂȂB*/
    v_SQLStmt VARCHAR2(200) :=
      'SELECT description, trigger_body
         FROM all_triggers
         WHERE owner = :v_owner
         AND trigger_name = :v_name';
    v_Cursor         INTEGER;
    v_NumRows        INTEGER;
    v_Dummy          INTEGER;
    v_Description    all_triggers.description%TYPE;
    v_BodyChunk      VARCHAR2(100);
    v_ChunkSize      NUMBER := 100;
    v_CurPos         NUMBER := 0;
    v_ReturnedLength NUMBER := 0;
    /*	̕ϐ́Ã^CṽIuWFNg̃\[XôɎgpB					      all_source̓\[X̊esʁXɊi[̂ŁAłDBMS_SQL͕svB
     */
    v_TextLine all_source.text%TYPE;
    CURSOR c_ObjCur IS
      SELECT text
        FROM all_source
        WHERE owner = p_Schema
        AND name = p_ObjName
        AND type = p_ObjType
        ORDER BY line;

  BEGIN
    -- ܂A'CREATE OR REPLACE't@CɏށB
    UTL_FILE.PUT(p_FileHandle, 'CREATE OR REPLACE ');
    
    IF (p_ObjType = 'TRIGGER') THEN
      BEGIN
        -- IuWFNg^CvȉꍇTRIGGERjt@Cɏo͂B
        UTL_FILE.PUT(p_FileHandle, 'TRIGGER ');
        
        -- J[\I[vĕ͂B
        v_Cursor := DBMS_SQL.OPEN_CURSOR;
        DBMS_SQL.PARSE(v_Cursor, v_SQLStmt, DBMS_SQL.V7);
        
        -- ͕ϐv[Xz_[ɃoChB
        DBMS_SQL.BIND_VARIABLE(v_Cursor, ':v_owner', p_Schema);
        DBMS_SQL.BIND_VARIABLE(v_Cursor, ':v_name', p_Objname);
        
        -- o͕ϐ`BgK[{fBeLXgDEFINE_COLUMN_LONGgp                			        -- Ă邱ƂɒӁB
        DBMS_SQL.DEFINE_COLUMN(v_Cursor, 1, v_Description, 2000);
        DBMS_SQL.DEFINE_COLUMN_LONG(v_Cursor, 2);
        
        -- sāAstFb`BgK[Ƃɍs1Ȃ̂ŁA
        -- [vătFb`Kv͂ȂB
      
        per trigger. 
        v_Dummy := DBMS_SQL.EXECUTE(v_Cursor);
        v_NumRows := DBMS_SQL.FETCH_ROWS(v_Cursor);
        
        -- gK[Lq̂߂̒loāAt@Cɏo͂B
        -- \ɂ͌㑱sĂ̂ŁAUTL_FILE.PUT_LINEł͂ȂA					        -- UTL_FILE.PUTgpł邱ƂɒӁB

        UTL_FILE.PUT(p_FileHandle, v_Description);
        
        -- gK[{fBŜo܂Ń[vB
        -- [vJԂтv_ChunkSizeoB
        LOOP
          DBMS_SQL.COLUMN_VALUE_LONG(v_Cursor, 2, v_ChunkSize,
                                     v_CurPos, v_BodyChunk, 
                                     v_ReturnedLength);
                                     
          IF v_ReturnedLength < v_ChunkSize THEN
            -- ōŌ̃`NoƂɂȂBȂA\ɂ͉šɗ]	            -- NULLi[Ă̂ŁA܂͂NULL폜Kv                        	            -- B
            v_BodyChunk := SUBSTR(v_BodyChunk, 1, LENGTH(v_BodyChunk) - 1);
            
            -- g~O`No͂āA[voB
            UTL_FILE.PUT(p_FileHandle, v_BodyChunk);
            EXIT;
          ELSE
            -- LONG̒`N1oBt@Cɏo͂āA	            
            -- ̃[vsł悤Ɍ݂̈ʒuXVB
            UTL_FILE.PUT(p_FileHandle, v_BodyChunk);
            v_CurPos := v_CurPos + v_ReturnedLength;
          END IF;
        END LOOP;
        
        -- ÎŃJ[\N[YB
        DBMS_SQL.CLOSE_CURSOR(v_Cursor);
      EXCEPTION
        WHEN OTHERS THEN
          -- ALLG[̏ꍇA܂J[\N[YĂAR[ŏł	          -- ɍēxOĂяoB
          DBMS_SQL.CLOSE_CURSOR(v_Cursor);
          RAISE;
        END;
    ELSE
      -- ܂ŗAgK[͏o͂ȂBall_sourcẽ\[Xs[vāAes      		      -- o͂邾łBŏ̍s̓IuWFNg̃^CvƖOA'IS'܂'AS'      	      -- 邱ƂɒӁB
      OPEN c_ObjCur;
      LOOP
        FETCH c_ObjCur INTO v_TextLine;
        EXIT WHEN c_ObjCur%NOTFOUND;
        
        -- esɂ͂łɌ㑱s܂܂Ă̂ŁAUTL_FILE.PUT_LINEł͂ȂA		        -- UTL_FILE.PUTgp邱ƂłB
        UTL_FILE.PUT(p_FileHandle, v_TextLine);
      END LOOP;
      CLOSE c_ObjCur;
    END IF;
    -- Ō'/'o͂B
    UTL_FILE.PUT_LINE(p_FileHandle, '/');
  END OutputObj;  
  
  PROCEDURE OneObj(p_Schema IN VARCHAR2,
                   
                   p_ObjName IN VARCHAR2,
                   p_ObjType IN VARCHAR2 DEFAULT NULL,
                   p_BothTypes IN BOOLEAN DEFAULT TRUE,
                   p_FileDir IN VARCHAR2,
                   p_FileName IN VARCHAR2,
                   p_Mode IN VARCHAR2) IS
    v_FileHandle UTL_FILE.FILE_TYPE;
    v_ObjType all_objects.object_type%TYPE;
  BEGIN
    -- ̓p[^؂B
    IF p_BothTypes AND (p_ObjType != 'PACKAGE') THEN
      RAISE_APPLICATION_ERROR(-20000,
        'Export.OneObj: BothTypes set but type != PACKAGE');
    ELSIF p_ObjType IS NOT NULL AND p_ObjType NOT IN
          ('PACKAGE', 'PACKAGE BODY', 'PROCEDURE', 'FUNCTION', 
        'TRIGGER') THEN RAISE_APPLICATION_ERROR(-20001,
        'Export.OneObj: Illegal value ' || p_ObjType || ' for object type');
    ELSIF p_FileDir IS NULL OR p_FileName IS NULL or p_Mode IS NULL THEN
      RAISE_APPLICATION_ERROR(-20002,
        'Export.OneObj: Directory, Filename and Mode must be non-NULL');
    ELSIF p_Mode NOT IN ('A', 'a', 'W', 'w') THEN
      RAISE_APPLICATION_ERROR(-20003,
        'Export.OneObj: Mode ' || p_Mode || ' not ''A'' or ''W''');
    END IF;
    
    -- K؂ȃIuWFNg^CvoāÃIuWFNg݂邩ǂ
    -- mFB
    BEGIN
      IF p_ObjType IS NULL THEN
        -- IuWFNg^Cv̎w肪ȂB^Cvw肹ɁAIuWFNg
        -- ݂邩ǂmFB
        SELECT object_type
          INTO v_ObjType
          FROM all_objects
          WHERE owner = UPPER(p_Schema)
          AND object_name = UPPER(p_Objname)
          AND object_type IN ('PROCEDURE', 'FUNCTION', 'PACKAGE',
                              'PACKAGE BODY', 'TRIGGER');
      ELSIF p_BothTypes THEN
        -- BothTypesw肳ĂB܂pbP[Wwb_[݂邩ǂ
        -- `FbNB
        SELECT object_type
          INTO v_ObjType
          FROM all_objects
          WHERE owner = UPPER(p_Schema)
          AND object_name = UPPER(p_Objname)
          AND object_type = 'PACKAGE';
        
        -- x̓pbP[W{fB`FbNB
        
        BEGIN
          SELECT object_type
            INTO v_ObjType
            FROM all_objects
            WHERE owner = UPPER(p_Schema)
            AND object_name = UPPER(p_Objname)
            AND object_type = 'PACKAGE BODY';
        EXCEPTION
          WHEN NO_DATA_FOUND THEN
            RAISE_APPLICATION_ERROR(-20006,
              'Export.ObjObj: BothTypes set but package body ' ||
              p_Schema || '.' || p_Objname || ' not found');
        END;
      ELSE
        -- IuWFNg^Cvw肳ĂBBothTypes͎w肳ĂȂB
        -- IuWFNg^CvgpăIuWFNg݂邩ǂmFB
        SELECT object_type
          INTO v_ObjType
          FROM all_objects
          WHERE owner = UPPER(p_Schema)
          AND object_name = UPPER(p_Objname)
          AND object_type = p_ObjType;
      END IF;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        RAISE_APPLICATION_ERROR(-20004,
          'Export.OneObj: Object ' || p_Schema || '.' || p_Objname || 
          ' not found');
      WHEN TOO_MANY_ROWS THEN
        RAISE_APPLICATION_ERROR(-20005,
          'Export.OneObj: More than one match for ' || p_Schema || '.' ||
          p_Objname);
    END;

    -- ܂ŗAIuWFNg݂邱Ƃ͂킩Ă̂ŁA
    -- t@CI[vď݂sB[h'A'ł΁A
    -- ܂󔒂2sށB
    v_FileHandle := UTL_FILE.FOPEN(p_FileDir, p_FileName, p_Mode);
    IF p_Mode IN ('A', 'a') THEN
      UTL_FILE.NEW_LINE(v_FileHandle, 2);
    END IF;
    
    -- IuWFNgo͂B  
    IF p_ObjType = 'PACKAGE' AND p_BothTypes THEN
      OutputObj(v_FileHandle, p_Schema, p_ObjName, 'PACKAGE');
      UTL_FILE.NEW_LINE(v_FileHandle, 2);
      OutputObj(v_FileHandle, p_Schema, p_ObjName, 'PACKAGE BODY');
    ELSE
      OutputObj(v_FileHandle, p_Schema, p_ObjName, v_ObjType);
    END IF;
    -- o̓t@CN[YB    
    UTL_FILE.FCLOSE(v_FileHandle);
  EXCEPTION
    -- UTL_FILEOLɏāAt@CK؂ɃN[Yꂽǂ
    -- mFB
    WHEN UTL_FILE.INVALID_PATH THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.OneObj: Invalid Path');
    WHEN UTL_FILE.INVALID_OPERATION THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.OneObj: Invalid Operation');
    WHEN UTL_FILE.INVALID_FILEHANDLE THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.OneObj: Invalid File Handle');
    WHEN UTL_FILE.WRITE_ERROR THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.OneObj: Write Error');
    WHEN UTL_FILE.INTERNAL_ERROR THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.OneObj: Internal Error');
    WHEN OTHERS THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE;
  END OneObj;
  
  PROCEDURE AllObjs(p_Schema IN VARCHAR2,
                    p_ObjType IN VARCHAR2 DEFAULT NULL,
                    p_FileDir IN VARCHAR2,
                    p_FileName IN VARCHAR2,
                    p_Mode IN VARCHAR2) IS
    v_FileHandle UTL_FILE.FILE_TYPE;
    v_ObjName all_objects.object_name%TYPE;
    v_ObjType all_objects.object_type%TYPE;
    v_ObjectFound BOOLEAN := FALSE;
    
    -- ⍇ɃJ[\ϐgBɂ2̂̂B
    TYPE t_AllObjs IS REF CURSOR;
    c_AllObjsCur t_AllObjs;
    
  BEGIN
    -- ̓p[^؂B
    IF p_ObjType IS NOT NULL AND p_ObjType NOT IN
            ('PACKAGE', 'PACKAGE BODY', 'PROCEDURE', 'FUNCTION',
             'TRIGGER') THEN
      RAISE_APPLICATION_ERROR(-20001,
        'Export.AllObjs: Illegal value ' || p_ObjType || ' for object type');
    ELSIF p_FileDir IS NULL OR p_FileName IS NULL or p_Mode IS NULL THEN
      RAISE_APPLICATION_ERROR(-20002,
        'Export.AllObjs: Directory, Filename and Mode must be non-NULL');
    ELSIF p_Mode NOT IN ('A', 'a', 'W', 'w') THEN
      RAISE_APPLICATION_ERROR(-20003,
        'Export.AllObjs: Mode ' || p_Mode || ' not ''A'' or ''W''');
    END IF;

    -- IuWFNg^Cv̎w肪Ȃ΁AJ[\I[vp_Schemaɂ
    -- L邷ׂẴIuWFNg̖⍇sBIuWFNg^Cv̎w肪
    -- ΁AJ[\I[vẴ^CṽIuWFNg̖⍇sB
    IF p_ObjType IS NULL THEN
      OPEN c_AllObjsCur FOR
        SELECT object_name, object_type
          FROM all_objects
          WHERE owner = UPPER(p_Schema)
          AND object_type in ('PACKAGE', 'PACKAGE BODY', 
                              'PROCEDURE', 'FUNCTION', 'TRIGGER');
    ELSE
      OPEN c_AllObjsCur FOR
        SELECT object_name, object_type
          FROM all_objects
          WHERE owner = UPPER(p_Schema)
          AND object_type = p_ObjType;
    END IF;
    
    -- IɓK邷ׂẴIuWFNg[vāAꂼ̃IuWFNg̊Ԃ
    -- 󔒂2s}ďo͂B
    LOOP
      FETCH c_AllObjsCur INTO v_ObjName, v_ObjType;
      EXIT WHEN c_AllObjsCur%NOTFOUND;

      IF NOT v_ObjectFound THEN
        -- ̓p[^ɓKIuWFNgȂƂ1邱Ƃ킩B
        -- t@CI[vāA[h'A'ł΂܂󔒂2sށB
        v_ObjectFound := TRUE;
        v_FileHandle := UTL_FILE.FOPEN(p_FileDir, p_FileName, p_Mode);
        IF p_Mode IN ('A', 'a') THEN
          UTL_FILE.NEW_LINE(v_FileHandle, 2);
        END IF;
      END IF;
      
      OutputObj(v_FileHandle, p_Schema, v_ObjName, v_ObjType);
      UTL_FILE.NEW_LINE(v_FileHandle, 2);
    END LOOP;
    
    -- IuWFNg`FbNāAJ[\ƃt@CnhN[Y
    -- B
    CLOSE c_AllObjsCur;
    IF NOT v_ObjectFound THEN
      RAISE_APPLICATION_ERROR(-20004,
          'Export.AllObjs: No objects found');
    END IF;
    UTL_FILE.FCLOSE(v_FileHandle);
  EXCEPTION
    -- UTL_FILEOLɏāAt@CK؂ɃN[Yꂽǂ
    -- mFB
    WHEN UTL_FILE.INVALID_PATH THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.AllObjs: Invalid Path');
    WHEN UTL_FILE.INVALID_OPERATION THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.AllObjs: Invalid Operation');
    WHEN UTL_FILE.INVALID_FILEHANDLE THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.AllObjs: Invalid File Handle');
    WHEN UTL_FILE.WRITE_ERROR THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE_APPLICATION_ERROR(-20010,
                              'Export.AllObjs: Write Error');
    WHEN OTHERS THEN
      UTL_FILE.FCLOSE(v_FileHandle);
      RAISE;
  END AllObjs;
END Export;



BEGIN
  Export.OneObj('EXAMPLE', 'ADDNEWSTUDENT', 'PROCEDURE', FALSE,
                'c:\temp', 'addstud.sql', 'W'); 
END;



CREATE OR REPLACE PROCEDURE AddNewStudent (
  p_FirstName  students.first_name%TYPE,
  p_LastName   students.last_name%TYPE,
  p_Major      students.major%TYPE) AS
BEGIN
  -- student\ɐVs}Bstudent_sequencegpĐVwID
  -- 쐬Acurrent_creditsɂ0gpB
  INSERT INTO students (ID, first_name, last_name,
                        major, current_credits)
    VALUES (student_sequence.nextval, p_FirstName, p_LastName,
            p_Major, 0);
  COMMIT;
END AddNewStudent;
/



Chapter 9
-- Available online as part of tables.sql
CREATE TABLE major_stats (
  major          VARCHAR2(30),
  total_credits  NUMBER,
  total_students NUMBER);



-- Available online as updateMS.sql
CREATE OR REPLACE TRIGGER UpdateMajorStats
  /* \major_stats\studentsɕύX邽тɍXVA
     ŐV̏ԂɈێB */
  AFTER INSERT OR DELETE OR UPDATE ON students
DECLARE
  CURSOR c_Statistics IS
    SELECT major, COUNT(*) total_students,
           SUM(current_credits) total_credits
      FROM students
      GROUP BY major;
BEGIN
  /* eU[vŒׁAUɑΉĂmajor_stats̒
     vXVBYs݂Ȃꍇ͍쐬B */
  FOR v_StatsRecord in c_Statistics LOOP
    UPDATE major_stats
      SET total_credits = v_StatsRecord.total_credits,
          total_students = v_StatsRecord.total_students
      WHERE major = v_StatsRecord.major;
    /* Ys݂Ă邩A`FbNB */
    IF SQL%NOTFOUND THEN
      INSERT INTO major_stats (major, total_credits, total_students)
        VALUES (v_StatsRecord.major, v_StatsRecord.total_credits,
                v_StatsRecord.total_students);
    END IF;
  END LOOP;
END UpdateMajorStats;



-- Available online as samename.sql
SQL> CREATE OR REPLACE TRIGGER major_stats
  2    BEFORE INSERT ON major_stats
  3  BEGIN
  4    INSERT INTO temp_table (char_col)
  5      VALUES ('Trigger fired!');
  6  END major_stats;
  7  /

Trigger created.

SQL> CREATE OR REPLACE PROCEDURE major_stats AS
  2  BEGIN
  3    INSERT INTO temp_table (char_col)
  4      VALUES ('Procedure called!');
  5  END major_stats;
  6  /
CREATE OR REPLACE PROCEDURE major_stats AS
*
ERROR at line 1:
ORA-00955: łɎgpĂIuWFNgłB



-- Available online as part of instead.sql
CREATE VIEW room_summary AS
  SELECT building, sum(number_seats) total_seats
    FROM rooms
  GROUP BY building;



SQL> DELETE FROM room_summary where building = 'Building 7';
DELETE FROM room_summary where building = 'Building 7'
            *
ERROR at line 1:
ORA-01732: ̃r[ɑ΂鑀삪łB



-- Available online as part of instead.sql
CREATE TRIGGER room_summary_delete
  INSTEAD OF DELETE ON room_summary
  FOR EACH ROW
BEGIN
  -- room_summarŷ1sɈvroomŝׂĂ̍s폜B
  DELETE FROM rooms
    WHERE building = :old.building;
END room_summary_delete;



SQL> SELECT trigger_type, table_name, triggering_event
  2    FROM user_triggers
  3    WHERE trigger_name = 'UPDATEMAJORSTATS';

TRIGGER_TYPE     TABLE_NAME     TRIGGERING_EVENT
---------------- -------------- --------------------------
AFTER STATEMENT  STUDENTS       INSERT OR UPDATE OR DELETE



SQL> ALTER TRIGGER UpdateMajorStats DISABLE
Trigger altered.

SQL> ALTER TRIGGER UpdateMajorStats ENABLE;
Trigger altered.



SQL> ALTER TABLE students
  2    ENABLE ALL TRIGGERS;
Table altered.

SQL> ALTER TABLE students
  2    DISABLE ALL TRIGGERS;
Table altered.



-- Available online as order.sql
CREATE SEQUENCE trigger_seq
  START WITH 1
  INCREMENT BY 1;

CREATE OR REPLACE TRIGGER classes_BStatement
  BEFORE UPDATE ON classes 
BEGIN
  INSERT INTO temp_table (num_col, char_col)
    VALUES (trigger_seq.NEXTVAL, 'Before Statement trigger');
END classes_BStatement;

CREATE OR REPLACE TRIGGER classes_AStatement
  AFTER UPDATE ON classes
BEGIN
  INSERT INTO temp_table (num_col, char_col)
    VALUES (trigger_seq.NEXTVAL, 'After Statement trigger');
END classes_AStatement;

CREATE OR REPLACE TRIGGER classes_BRow
  BEFORE UPDATE ON classes
  FOR EACH ROW
BEGIN
  INSERT INTO temp_table (num_col, char_col)
    VALUES (trigger_seq.NEXTVAL, 'Before Row trigger');
END classes_BRow;

CREATE OR REPLACE TRIGGER classes_ARow
  AFTER UPDATE ON classes
  FOR EACH ROW
BEGIN
  INSERT INTO temp_table (num_col, char_col)
    VALUES (trigger_seq.NEXTVAL, 'After Row trigger');
END classes_ARow;



UPDATE classes
  SET num_credits = 4
  WHERE department IN ('HIS', 'CS');



-- Available online as part of order.sql
SQL> SELECT * FROM temp_table
  2    ORDER BY num_col;

  NUM_COL CHAR_COL
--------- -------------------------
        1 Before Statement trigger
        2 Before Row trigger
        3 After Row trigger
        4 Before Row trigger
        5 After Row trigger
        6 Before Row trigger
        7 After Row trigger
        8 Before Row trigger
        9 After Row trigger
       10 After Statement trigger



-- Available online as studID.sql
CREATE OR REPLACE TRIGGER GenerateStudentID
  BEFORE INSERT OR UPDATE ON students
  FOR EACH ROW
BEGIN
  /* student_sequence琶̒lAstudents
     IDtB[hɊi[BID́Astudents̗ł邽߁A
     :new.ID́ALȎQƂłB */
  SELECT student_sequence.nextval
    INTO :new.ID
    FROM dual;
END GenerateStudentID;



I INSERT INTO students (first_name, last_name)
  VALUES ('Lolita', 'Lazarus');



INSERT INTO students (ID, first_name, last_name)
  VALUES (-7, 'Lolita', 'Lazarus');



CREATE OR REPLACE TRIGGER CheckCredits
  BEFORE INSERT OR UPDATE OF current_credits ON students
  FOR EACH ROW
  WHEN (new.current_credits > 20)
BEGIN
  /* ɂ́AgK[̖{̂LqB */
END;



CREATE OR REPLACE TRIGGER CheckCredits
  BEFORE INSERT OR UPDATE OF current_credits ON students
  FOR EACH ROW
BEGIN
  IF :new.current_credits > 20 THEN
    /* ɂ́AgK[̖{̂LqB */
  END IF;
END;



-- Available online as part of tables.sql
CREATE TABLE RS_audit (
  old_student_id NUMBER(5),
  old_department CHAR(3),
  old_course     NUMBER(3),
  old_grade      CHAR(1),
  new_student_id NUMBER(5),
  new_department CHAR(3),
  new_course     NUMBER(3),
  new_grade      CHAR(1),
  changed_by     VARCHAR2(8),
  timestamp      DATE
  );



-- Available online as RSchange.sql
CREATE OR REPLACE TRIGGER LogRSChanges
  BEFORE INSERT OR DELETE OR UPDATE ON registered_students
  FOR EACH ROW
DECLARE
  v_ChangeType CHAR(1);
BEGIN
  /* INSERT̈Ӗ'I'ADELETËӖ'D'AUPDATËӖ'U'gpB*/
  IF INSERTING THEN
    v_ChangeType := 'I';
  ELSIF UPDATING THEN
    v_ChangeType := 'U';
  ELSE
    v_ChangeType := 'D';
  END IF;

  /* registered_studentsɎsꂽύXeׂāARS_auditɋL^
     ^CX^v𐶐邽߂SYSDATEA
     ݂̃[U[̃[U[IDԂ߂USERgpB */
  INSERT INTO RS_audit
    (change_type, changed_by, timestamp,
     old_student_id, old_department, old_course, old_grade, 
     new_student_id, new_department, new_course, new_grade)
  VALUES
    (v_ChangeType, USER, SYSDATE,
     :old.student_id, :old.department, :old.course, :old.grade,
     :new.student_id, :new.department, :new.course, :new.grade);
END LogRSChanges;*/



-- Available online as part of tables.sql
CREATE TABLE registered_students (
  student_id NUMBER(5) NOT NULL,
  department CHAR(3)   NOT NULL,
  course     NUMBER(3) NOT NULL,
  grade      CHAR(1),
  CONSTRAINT rs_grade
    CHECK (grade IN ('A', 'B', 'C', 'D', 'E')),
  CONSTRAINT rs_student_id
    FOREIGN KEY (student_id) REFERENCES students (id),
  CONSTRAINT rs_department_course
    FOREIGN KEY (department, course) 
    REFERENCES classes (department, course)
  );



-- Available online as RSinsert.sql
CREATE OR REPLACE TRIGGER CascadeRSInserts
  /* registered_students, students, classesƂ\𓯊B  */
  BEFORE INSERT ON registered_students
  FOR EACH ROW
DECLARE
  v_Credits classes.num_credits%TYPE;
BEGIN
  -- YNX̒Pʐ𒲂ׂB
  SELECT num_credits
    INTO v_Credits
    FROM classes
    WHERE department = :new.department
    AND course = :new.course;

  -- Yw݂̌̒PʐύXB
  UPDATE students
    SET current_credits = current_credits + v_Credits
    WHERE ID = :new.student_id;

  -- YNX̊w1𑫂B
  UPDATE classes
    SET current_students = current_students + 1
    WHERE department = :new.department
    AND course = :new.course;
END CascadeRSInserts;



-- Available online as limMajor.sql
CREATE OR REPLACE TRIGGER LimitMajors
  /* eŮw5ɐB
     ̐l𒴂ARAISE_APPLICATION_ERRORɂ
     G[ʒmB */
  BEFORE INSERT OR UPDATE OF major ON students
  FOR EACH ROW
DECLARE
  v_MaxStudents CONSTANT NUMBER := 5;
  v_CurrentStudents NUMBER;
BEGIN
  -- YǓ݂̊w𒲂ׂB
  SELECT COUNT(*)
    INTO v_CurrentStudents
    FROM students
    WHERE major = :new.major;

  -- ǉł]TȂꍇ́AG[ʒmB
  IF v_CurrentStudents + 1 > v_MaxStudents THEN
    RAISE_APPLICATION_ERROR(-20000, 
      'Too many students in major ' || :new.major);
  END IF;
END LimitMajors;



SQL> UPDATE students
  2    SET major = 'History'
  3    WHERE ID = 10003;
UPDATE students
 *s:1ŃG[܂B
ORA-04091: \EXAMPLE.STUDENTS͕ύXȂ̂ŃgK[͂̕\Ǎ/C邱Ƃł܂B
ORA-06512: "EXAMPLE.LIMITMAJORS", s: 6
ORA-04088: gK[: EXAMPLE.LIMITMAJORS̎sɃG[܂B



-- Available online as mutating.sql
CREATE OR REPLACE PACKAGE StudentData AS
  TYPE t_Majors IS TABLE OF students.major%TYPE
    INDEX BY BINARY_INTEGER;
  TYPE t_IDs IS TABLE OF students.ID%TYPE
    INDEX BY BINARY_INTEGER;

  v_StudentMajors t_Majors;
  v_StudentIDs    t_IDs;
  v_NumEntries    BINARY_INTEGER := 0;
END StudentData;
/

CREATE OR REPLACE TRIGGER RLimitMajors
  BEFORE INSERT OR UPDATE OF major ON students
  FOR EACH ROW
BEGIN
  /* StudentDataɁAVf[^L^BORA-4091ƂG[
     o͂̂邽߂ɁAstudentsɂ͕ύXȂB */
  StudentData.v_NumEntries := StudentData.v_NumEntries + 1;
  StudentData.v_StudentMajors(StudentData.v_NumEntries) := 
    :new.major;
  StudentData.v_StudentIDs(StudentData.v_NumEntries) := :new.id;
END RLimitMajors;

CREATE OR REPLACE TRIGGER SLimitMajors
  AFTER INSERT OR UPDATE OF major ON students
DECLARE
  v_MaxStudents     CONSTANT NUMBER := 5;
  v_CurrentStudents NUMBER;
  v_StudentID       students.ID%TYPE;
  v_Major           students.major%TYPE;
BEGIN
  /* }܂͍XVꂽew[vŒ
     ܂͈͓̔ɂ邩؂B */
  FOR v_LoopIndex IN 1..StudentData.v_NumEntries LOOP
    v_StudentID := StudentData.v_StudentIDs(v_LoopIndex);
    v_Major := StudentData.v_StudentMajors(v_LoopIndex);

    -- YǓ݂̊w𒲂ׂB
    SELECT COUNT(*)
      INTO v_CurrentStudents
      FROM students
      WHERE major = v_Major;

    -- ǉł]TȂꍇ́AG[ʒmB
    IF v_CurrentStudents > v_MaxStudents THEN
      RAISE_APPLICATION_ERROR(-20000, 
        'Too many students for major ' || v_Major ||
        ' because of student ' || v_StudentID);
    END IF;
  END LOOP;

  -- ̎sŐVf[^gp悤AJE^ZbgB
  StudentData.v_NumEntries := 0;
END SLimitMajors;



SQL> UPDATE students
  2    SET major = 'History'
  3    WHERE ID = 10003;
1 row updated.

SQL> UPDATE students
  2    SET major = 'History'
  3    WHERE ID = 10002;
1 row updated.

SQL> UPDATE students
  2    SET major = 'History'
  3    WHERE ID = 10009;
UPDATE students
 *
s:1ŃG[܂B
ORA-20000: 10009̂߂ɗjŮwxz܂B
ORA-06512: "EXAMPLE.SLIMITMAJORS", s: 19
ORA-04088: gK[: EXAMPLE.SLIMITMAJORS̎sɃG[܂B



SQL> exec update_cascade.on_table('dept')



SQL> SET feedback off
SQL> SPOOL tmp.sql
SQL> SET serveroutput on SIZE 1000000
SQL> exec update_cascade.on_table(p_table_name => 'dept',
                                  p_use_dbms_output => TRUE)
SQL> SPOOL off



SQL> UPDATE dept SET deptno = deptno + 1;
UPDATE dept SET deptno = deptno + 1
       *
ERROR at line 1:
ORA-02292: (UCDEMO.SYS_C00815)Ɉᔽ܂B
	     qR[h܂B



SQL> exec update_cascade.on_table('dept');
PL/SQL procedure successfully completed.

SQL> SELECT * FROM dept;
   DEPTNO DNAME          LOC
--------- -------------- -------------
       10 ACCOUNTING     NEW YORK
       20 RESEARCH       DALLAS
       30 SALES          CHICAGO
       40 OPERATIONS     BOSTON

SQL> SELECT empno, deptno FROM emp WHERE deptno = 10;
    EMPNO    DEPTNO
--------- ---------
     7839        10
     7782        10
     7934        10

SQL> UPDATE dept SET deptno = deptno + 1;
4 rows updated.

SQL> SELECT * FROM dept;
   DEPTNO DNAME          LOC
--------- -------------- -------------
       11 ACCOUNTING     NEW YORK
       21 RESEARCH       DALLAS
       31 SALES          CHICAGO
       41 OPERATIONS     BOSTON

SQL> SELECT empno, deptno FROM emp WHERE deptno IN (10, 11);
    EMPNO    DEPTNO
--------- ---------
     7839        11
     7782        11
     7934        11



CREATE TABLE emp (
  EMPNO NUMBER(4) primary key,
  ENAME VARCHAR2(10),
  JOB VARCHAR2(9),
  MGR NUMBER(4) references emp,
  HIREDATE DATE,
  SAL NUMBER(7,2),
  COMM NUMBER(7,2),
  DEPTNO NUMBER(2) references dept);



UPDATE emp SET empno = empno + 1;



UPDATE emp
  SET mgr = <new value>
  WHERE mgr = <old value>



SQL> @unindex
STAT TABLE_NAME               COLUMNS              COLUMNS
---- ------------------------ -------------------- ----------
**** EMP                      MGR
ok   EMP                      DEPTNO               DEPTNO
ok   PROJECTS                 EMPNO                EMPNO, PROJ_NO
ok   T2                       A                    A, B
ok   T3                       A, B                 A, B, C



SQL> @generate
prompt Update Cascade on table: DEPT
execute update_cascade.on_table( 'DEPT' )

prompt Update Cascade on table: EMP
execute update_cascade.on_table( 'EMP' )

prompt Update Cascade on table: T1
execute update_cascade.on_table( 'T1' )

prompt Update Cascade on table: T2
execute update_cascade.on_table( 'T2' )



create or replace package "uDEPTp"
as
  -- ̍XVɂďs̐ŴRowcntgpB
  -- Rowcnt́ABEFORE UPDATEgK[uDEPTp.reset[`̒ŃZbgB
  -- p_preserve_rowids = TRUȄꍇɁAgK[xN̂h߂
  -- 'inTrigger'ϐgpB
rowCnt		number default 0;
inTrigger boolean default FALSE;

  -- L[̗vfƂɕ\̌^錾Ǎɂ̌^̔z񂪐錾B
  -- ́Ai1jrtHAC[WAi2jAt^[C[WAi3jO2̔z[
  -- 邽߂Ɏgpzێ邽߂łB

  type C1_type is table of "DEPT"."DEPTNO"%type
    index by binary_integer;

  empty_C1 C1_type;
  old_C1   C1_type;
  new_C1   C1_type;

  -- Reset́ABEFORE UPDATEgK[ɂċNArowcntϐZbg
  -- ǑĂяozɂ郋[`B
  procedure reset;

  -- Do_cascadéA̒SƂȂ郋[`łBAFTER UPDATEgK[N
  -- ۂ̃JXP[hsB
  procedure do_cascade;

  -- Add_entrýArowcnt𑝕ĎL[̃rtHAC[WуAt^[C[W
  -- WB܂A:newϐ:oldϐɃANZXĎL[ɉꂽXV
  -- uvB
  procedure add_entry
    (
    p_old_C1 in "DEPT"."DEPTNO"%type,
    p_new_C1 in out "DEPT"."DEPTNO"%type
    );
end "uDEPTp";



create or replace package body "uDEPTp"
as
  procedure reset is
  begin
    -- ̍śAp_preserve_rowids = TRUȄꍇɁAׂẴ[`ɑ݂B
    -- gK[xN̂hB
    if ( inTrigger ) then return; end if;

    rowCnt := 0;
    old_C1 := empty_C1;
    new_C1 := empty_C1;
  end reset;

  procedure add_entry
  (
    p_old_C1 in "DEPT"."DEPTNO"%type,
    p_new_C1 in out "DEPT"."DEPTNO"%type
  ) is
  begin
    if ( inTrigger ) then return; end if;
    -- ̃R[h́APL/SQL\ɃrtHAC[WƃAt^[C[WۑāA
    -- V̗ɐݒ肷邱ƂŎL[XVuvB
    if (
       p_old_C1 <> p_new_C1
       ) then
      rowCnt := rowCnt + 1;
      old_C1( rowCnt ) := p_old_C1;
      new_C1( rowCnt ) := p_new_C1;
      p_new_C1 := p_old_C1;
    end if;
  end add_entry;

  procedure do_cascade is
  begin
    if ( inTrigger ) then return; end if;
    inTrigger := TRUE;
    -- XVꂽsƂɃN[sāAJXP[hƍ폜sB
    for i in 1 .. rowCnt loop
      -- ̑}́AVL[őO̒l܂Ȃes̃N[𐶐B
      insert into DEPT ("DEPTNO", "DNAME", "LOC")
        select new_C1(i), "DNAME", "LOC"
          from "DEPT" a
            where ( "DEPTNO" ) =
              ( select old_C1(i) from dual );

      -- ̃R[ĥ́Ap_preserve_rowidstruȅꍇŁAO
      -- L[ƐVL[ւBāA̐erowidێB
      update "DEPT" set
        (  "DEPTNO" ) =
        ( select
            decode( "DEPTNO", old_c1(i), new_c1(i), old_c1(i) )
          from dual )
        where (  "DEPTNO" ) =
              ( select  new_C1(i)
                  from dual )
           OR (  "DEPTNO" ) =
              ( select  old_C1(i)
                  from dual );

      -- ׂĂ̎q\ɑ΂čXṼJXP[hsB
      update "EMP" set
      (  "DEPTNO" ) =
      ( select   new_C1(i)
          from dual )
      where (  "DEPTNO" ) =
            ( select   old_C1(i)
                from dual );

      -- O̎L[l폜B
      delete from "DEPT"
       where (  "DEPTNO" ) =
             ( select  old_C1(i)
                 from dual);
    end loop;
    inTrigger := FALSE;
    reset;
  exception
    when others then
      inTrigger := FALSE;
      reset;
      raise;
  end do_cascade;
end "uDEPTp";



create or replace trigger "uc$DEPT_bu"
before update of
    "DEPTNO"
on "DEPT"
begin "uDEPTp".reset; end;



create or replace trigger "uc$DEPT_bufer"
before update of
    "DEPTNO"
on "DEPT"
for each row
begin
   "uDEPTp".add_entry(
       :old."DEPTNO"
      ,:new."DEPTNO"
      );
end;



create or replace trigger "uc$DEPT_au"
after update of
    "DEPTNO"
on "DEPT"
begin "uDEPTp".do_cascade; end;



Chapter 10
PLS-00201: ʎqSSTUDENTS錾Ă܂B



DECLARE
  v_NumStudents NUMBER;
BEGIN
  SELECT COUNT(*)
    INTO v_NumStudents
    FROM sstudents;
END;



ORA-00001: Ӑ: i%S.%SjɔĂ܂B



ORA-06502: PL/SQL: l܂͐lG[܂B 



int x, y, z;
f(x); /* ֐R[BƂxnB */
if <G[ꍇ>
  handle_error(...);
y = 1 / z;
if <G[ꍇ>
  handle_error(...);
z = x + y;
if <G[ꍇ>
  handle_error(...);



DECLARE
  x NUMBER;
  y NUMBER;
  z NUMBER;
BEGIN
  f(x);
  y := 1 / z;
  z := x + y;
EXCEPTION
  WHEN OTHERS THEN
    /* ׂẴG[邽߂̃nh */
    handle_error(...);
END;



DECLARE
  e_TooManyStudents EXCEPTION;



DECLARE
  TYPE t_NumberTableType IS TABLE OF NUMBER
    INDEX BY BINARY_INTEGER;
  v_NumberTable t_NumberTableType;
  v_TempVar NUMBER;
BEGIN  
  v_TempVar := v_NumberTable(1);
END;



INSERT INTO students (id, first_name, last_name)
  VALUES ('X', 'SCOTT', 'Smith');



DECLARE
  v_TempVar VARCHAR2(3);
BEGIN
  v_TempVar := 'ABCD';
END;

DECLARE
  v_TempVar NUMBER(2);
BEGIN
  SELECT id
    INTO v_TempVar
    FROM students
    WHERE last_name = 'Smith';
END;



-- Available online as handle.sql
DECLARE
  e_TooManyStudents EXCEPTION;  -- G[̏O
  v_CurrentStudents NUMBER(3);  -- HIS-101Ɍݓo^ς݂̊w
  v_MaxStudents NUMBER(3);      -- HIS-101ɓo^łw̍ő吔
BEGIN
  /* ݓo^ς݂̊wƁAo^łw̍ő吔𒲂ׂB */
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = 'HIS' AND course = 101;
  /* YNX̊w`FbNB */
  IF v_CurrentStudents > v_MaxStudents THEN
    /* o^Ώۂ̊wꍇ --OʒmB */
    RAISE e_TooManyStudents;
  END IF;
END;



BEGIN
  INSERT INTO students (id, first_name, last_name)
    VALUES (10001, 'John', 'Smith');
  INSERT INTO students (id, first_name, last_name)
    VALUES (10001, 'Susan', 'Ryan');
END;



ORA-00001: Ӑ: i%S.%SjɔĂ܂B



DECLARE
  e_TooManyStudents EXCEPTION;  -- G[̏O
  v_CurrentStudents NUMBER(3);  -- HIS-101Ɍݓo^ς݂̊w
  v_MaxStudents NUMBER(3);      -- HIS-101ɓo^łw̍ő吔
BEGIN
  /* ݓo^ς݂̊wƁAo^łw̍ő吔𒲂ׂB */
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = 'HIS' AND course = 101;
  /* YNX̊w`FbNB */
  IF v_CurrentStudents > v_MaxStudents THEN
    /* o^Ώۂ̊wꍇ -- OʒmB */
    RAISE e_TooManyStudents;
  END IF;
EXCEPTION
  WHEN e_TooManyStudents THEN
    /* HIS-101ɓo^ׂwꍇɎsnhB
       󋵂邽߂̃ObZ[W}B */
    INSERT INTO log_table (info) VALUES ('History 101 has ' || 
     v_CurrentStudents ||
      'students: max allowed is ' || v_MaxStudents);
END;



EXCEPTION
  WHEN NO_DATA_FOUND OR TOO_MANY_ROWS THEN
    INSERT INTO log_table (info) VALUES ('A select error occurred.');
END;



-- Available online as others.sql
DECLARE
  e_TooManyStudents EXCEPTION;  -- G[̏O
  v_CurrentStudents NUMBER(3);  -- HIS-101Ɍݓo^ς݂̊w
  v_MaxStudents NUMBER(3);      -- HIS-101ɓo^łw̍ő吔
BEGIN
  /* ݓo^ς݂̊wƁAo^łw̍ő吔𒲂ׂB */
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = 'HIS' AND course = 101;
  /* YNX̊w`FbNB */
  IF v_CurrentStudents > v_MaxStudents THEN
    /* o^Ώۂ̊wꍇ -- OʒmB */
    RAISE e_TooManyStudents;
  END IF;
EXCEPTION
  WHEN e_TooManyStudents THEN
    /* HIS-101ɓo^ׂwꍇɎsnhB
       󋵂邽߂̃ObZ[W}B */
    INSERT INTO log_table (info) VALUES ('History 101 has ' ||
     v_CurrentStudents ||
      'students: max allowed is ' || v_MaxStudents);
  WHEN OTHERS THEN
    /* ׂ̑̂ẴG[ɑ΂ĎsnhB */
    INSERT INTO log_table (info) VALUES ('Another error occurred');
END;



-- Available online as sqlrrm.sql
DECLARE
  e_TooManyStudents EXCEPTION;  -- G[̏O
  v_CurrentStudents NUMBER(3);  -- HIS-101Ɍݓo^ς݂̊w
  v_MaxStudents NUMBER(3);      -- HIS-101ɓo^łw̍ő吔
  v_ErrorCode NUMBER;           -- G[bZ[W̃R[hi[p̕ϐ
  v_ErrorText VARCHAR2(200);    -- G[bZ[W̃eLXgi[p̕ϐ

BEGIN
  /* ݓo^ς݂̊wƁAo^łw̍ő吔𒲂ׂB */
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE department = 'HIS' AND course = 101;
  /* YNX̊w`FbNB */
  IF v_CurrentStudents > v_MaxStudents THEN
    /* o^Ώۂ̊wꍇ -- OʒmB */
    RAISE e_TooManyStudents;
  END IF;
EXCEPTION
  WHEN e_TooManyStudents THEN
    /* HIS-101ɓo^ׂwꍇɎsnhB
       󋵂邽߂̃ObZ[W}B */
    INSERT INTO log_table (info) VALUES ('History 101 has ' ||
     v_CurrentStudents ||
      'students: max allowed is ' || v_MaxStudents);
  WHEN OTHERS THEN
    /* ׂ̑̂ẴG[ɑ΂Ďsnh */
    v_ErrorCode := SQLCODE;
    v_ErrorText := SUBSTR(SQLERRM, 1, 200);  -- Note the use of SUBSTR
    here.
    INSERT INTO log_table (code, message, info) VALUES
      (v_ErrorCode, v_ErrorText, 'Oracle error occurred');
END;



v_ErrorText := SQLERRM;



ORA-00000: ɏI܂B



User-Defined Exception 



ORA-01403: f[^܂B



ORA-00000: ɏI܂B



-- Available online as sqlerrmz.sql
DECLARE
  v_ErrorText   log_table.message%TYPE;  -- G[bZ[W̃eLXgi[pϐ
BEGIN
  /* SQLERRM(0) */
  v_ErrorText := SUBSTR(SQLERRM(0), 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (0, v_ErrorText, 'SQLERRM(0)');

  /* SQLERRM(100) */
  v_ErrorText := SUBSTR(SQLERRM(100), 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (100, v_ErrorText, 'SQLERRM(100)');

  /* SQLERRM(10) */
  v_ErrorText := SUBSTR(SQLERRM(10), 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (10, v_ErrorText, 'SQLERRM(10)');

  /* SQLERRM Ȃ */
  v_ErrorText := SUBSTR(SQLERRM, 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (NULL, v_ErrorText, 'SQLERRM with no argument');

  /* SQLERRM(-1) */
  v_ErrorText := SUBSTR(SQLERRM(-1), 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (-1, v_ErrorText, 'SQLERRM(-1)');

  /* SQLERRM(-54) */
  v_ErrorText := SUBSTR(SQLERRM(-54), 1, 200);
  INSERT INTO log_table (code, message, info)
    VALUES (-54, v_ErrorText, 'SQLERRM(-54)');

END;



-- Available online as pragma.sql
DECLARE
  e_MissingNull EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_MissingNull, -1400);
BEGIN
  INSERT INTO students (id) VALUES (NULL);
EXCEPTION
  WHEN e_MissingNull then
    INSERT INTO log_table (info) VALUES ('ORA-1400 occurred');
END;



-- Available online as register.sql
CREATE OR REPLACE PROCEDURE Register (
  /* p_Departmentp_CourseƂp[^Ŏw肳ꂽNX
     p[^p_StudentIDŎw肳ꂽwo^BAwNX
     ۂɓo^ClassPackage.AddStudentR[OɁAYNX
     ݂ƁÃNX̊wɗ]T邩ǂA{vV[W
     `FbNB */
  p_StudentID IN students.id%TYPE,
  p_Department IN classes.department%TYPE,
  p_Course IN classes.course%TYPE) AS

  v_CurrentStudents NUMBER;  -- YNX݂̌̊w
  v_MaxStudents NUMBER;      -- YNXɓo^łw̍ő吔

BEGIN
  /* ݂̓o^ς݂̊wƁAo^łw̍ő吔𒲂ׂB */
  SELECT current_students, max_students
    INTO v_CurrentStudents, v_MaxStudents
    FROM classes
    WHERE course = p_Course
    AND department = p_Department;

  /* Ywǉł]T邩A`FbNB */
  IF v_CurrentStudents + 1 > v_MaxStudents THEN
    RAISE_APPLICATION_ERROR(-20000, 'Can''t add more students to ' ||
      p_Department || ' ' || p_Course);
  END IF;

  /* YwAYNXɒǉB */
  ClassPackage.AddStudent(p_StudentID, p_Department, p_Course);

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    /* {vV[WɓnꂽNX̏́A݂ĂȂBR[
       vOɂ̂Ƃ邽߂ɁAG[ʒmB */
    RAISE_APPLICATION_ERROR(-20001, p_Department || ' ' || p_Course ||
      ' doesn''t exist!');
END Register;



ORA-20000: Can't add more students to HIS 101



ORA-1403: f[^܂B 



DECLARE
  -- ÕubN̊JnB
  ...
BEGIN
  ...
  DECLARE
    -- ̃ubN1̊JnB̃ubŃAÕubNɈ͂܂ĂB
  ...
  BEGIN
    ...
  END;
  ...
  BEGIN
    -- ̃ubN2̊JnB̃ubNAÕubNɈ͂܂ĂB
    -- ̃ubNɂ́A錾ZNVȂ_ɒӁB
    ...
  END;
  ...
  -- ÕubN̏IB
END;



BEGIN
  -- ÕubN̊JnB
  -- vV[WR[B̃vV[ẂAÓíjubNɂ
  -- ͂܂邱ƂɂȂB
  F(...);
END;



v_Number NUMBER(3) := 'ABC';



DECLARE
  ...
BEGIN
  ...
  DECLARE
    e_UserDefinedException EXCEPTION;
  BEGIN
    RAISE e_UserDefinedException;
  END;
EXCEPTION
  /* ́Ae_UserDefinedException̗L͈͊OłB̂߁A
   e_UserDefinedExceptiońAnhOTHERSłłȂB */
  WHEN OTHERS THEN
    /* G[̏ */
END;



CREATE OR REPLACE PACKAGE Globals
  /* ̃pbP[Wł́AO[oȐ錾LqBŐ錾
     IuWFNǵACgp΁A̔Cӂ̃ubN
     vV[WQƂłB̃pbP[Wɂ́ApbP[W
     ̖{̂Ȃ_ɒӂ邱ƁB */

  /* [U[`̗O */
  e_UserDefinedException EXCEPTION;
END Globals;



DECLARE
  ...
BEGIN
  ...
  BEGIN
    /* e_UserDefinedExceptionpbP[WŏC
   Ȃ΂ȂȂ_ɒӁB */
    RAISE Globals.e_UserDefinedException;
  END;
EXCEPTION
  /* e_UserDefinedExceptiońAłQƂł邽߁A
   Iɏ邱ƂłB */
  WHEN Globals.e_UserDefinedException THEN
    /* G[̏ */
END;



DECLARE
  v_ErrorNumber NUMBER;       -- G[ԍi[邽߂̕ϐB
  v_ErrorText VARCHAR2(200);  -- G[bZ[W̃eLXgi[邽߂̕ϐB
BEGIN
  /* PL/SQLł̒ʏ̏ */
  ...
EXCEPTION
  WHEN OTHERS THEN
    /* ɏIł悤AOׂăMOB */
    v_ErrorNumber := SQLCODE;
    v_ErrorText := SUBSTR(SQLERRM, 1, 200);
    INSERT INTO log_table (code, message, info) VALUES
      (v_ErrorNumber, v_ErrorText, 'Oracle error occurred
      at ' ||
      TO_CHAR(SYSDATE, 'DD-MON-YY HH24:MI:SS'));
END;



BEGIN
  SELECT ...
  SELECT ...
  SELECT ...
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- ǂSELECTOʒmꂽH
END;



DECLARE
  v_SelectCounter NUMBER := 1;  -- SELECT̔ԍi[邽߂̕ϐB
BEGIN
  SELECT ...
  v_SelectCounter := 2;
  SELECT ...
  v_SelectCounter := 3;
  SELECT ...
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    INSERT INTO log_table (info) VALUES ('No data found in select 
                                         ' || v_SelectCounter);
END;



BEGIN
  BEGIN
    SELECT ...
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      INSERT INTO log_table (info) VALUES ('No data found 
                                            in select 1');
  END;
  BEGIN
    SELECT ...
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      INSERT INTO log_table (info) VALUES ('No data found 
                                            in select 2');
  END;
  BEGIN
    SELECT ...
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      INSERT INTO log_table (info) VALUES ('No data found 
                                            in select 3');
  END;
END;



-- Available online as abc1.sql
CREATE OR REPLACE PROCEDURE C AS
  v_CallStack VARCHAR2(2000);
BEGIN
    v_CallStack := DBMS_UTILITY.FORMAT_CALL_STACK;
    INSERT INTO temp_table (char_col) VALUES (v_CallStack);
    INSERT INTO temp_table (num_col)
      VALUES (-1);
END C;
CREATE OR REPLACE PROCEDURE B AS
BEGIN
  C;
END B;
CREATE OR REPLACE PROCEDURE A AS
BEGIN
  B;
END A;



----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
 16998f0         4  procedure EXAMPLE.C
 1699ca0         3  procedure EXAMPLE.B
 169f918         3  procedure EXAMPLE.A
 1667ef0         1  anonymous block



-- Available online as e_tables.sql
CREATE TABLE errors (
  module       VARCHAR2(50),
  seq_number   NUMBER,
  error_number NUMBER,
  error_mesg   VARCHAR2(100),
  error_stack  VARCHAR2(2000),
  call_stack   VARCHAR2(2000),
  timestamp    DATE,
  PRIMARY KEY (module, seq_number));

CREATE TABLE call_stacks (
  module        VARCHAR2(50),
  seq_number    NUMBER,
  call_order    NUMBER,
  object_handle VARCHAR2(10),
  line_num      NUMBER,
  object_name   VARCHAR2(80),
  PRIMARY KEY (module, seq_number, call_order),
  FOREIGN KEY (module, seq_number) REFERENCES errors ON DELETE CASCADE);

DROP TABLE error_stacks;
CREATE TABLE error_stacks (
  module        VARCHAR2(50),
  seq_number    NUMBER,
  error_order   NUMBER,
  facility      CHAR(3),
  error_number  NUMBER(5),
  error_mesg    VARCHAR2(100),
  PRIMARY KEY (module, seq_number, error_order),
  FOREIGN KEY (module, seq_number) REFERENCES errors ON DELETE CASCADE);


CREATE SEQUENCE error_seq
  START WITH 1
  INCREMENT BY 1;



-- Available online as e.pkg.sql
CREATE OR REPLACE PACKAGE ErrorPkg AS
  /*	DBMS_UTILITY.FORMAT_ERROR_STACKDBMS_UTILITY.FORMAT_CALL_STACK			gpėpG[nhpbP[WB̃pbP[ẂAڍׂȃR[X^bN
	G[X^bNꂼcall_stack\error_stack\Ɋi[Aerror\
	ʓIȃG[i[B*/

  -- G[̃Gg|CgBG[OꏊallOnhHandelAll
  -- R[BTRUEɐݒł̂́AvV[W̃lXg̍ŏʃxŁÃx
  -- łFALSEɐݒ肷Bgp@ɂẮAerror_readme.txtQƁB
  PROCEDURE HandleAll(p_Top BOOLEAN);

  -- iDBMS_OUTPUTgpāj̃W[ƃV[PXԍɂăG[ƃR[
  -- X^bN\B
  PROCEDURE PrintStacks(p_Module IN errors.module%TYPE,
                        p_SeqNum IN errors.seq_number%TYPE);

  -- G[ƃR[X^bNāAerrors\call_stack\Ɋi[BG[
  -- i[ĂV[PXԍԂB
  -- p_CommitFlagTRUȄꍇA}R~bgB
  -- StoreStacksgpɂ́AG[ĂȂ΂ȂȂBāA
  -- HandelAllp_Top = TRUEŃR[ĂȂ΂ȂȂB
  PROCEDURE StoreStacks(p_Module IN errors.module%TYPE,
                        p_SeqNum OUT errors.seq_number%TYPE,
                        p_CommitFlag BOOLEAN DEFAULT FALSE);
END ErrorPkg;


CREATE OR REPLACE PACKAGE BODY ErrorPkg AS

  v_NewLine     CONSTANT CHAR(1) := CHR(10);

  v_Handled     BOOLEAN := FALSE;
  v_ErrorStack  VARCHAR2(2000);
  v_CallStack   VARCHAR2(2000);

  PROCEDURE HandleAll(p_Top BOOLEAN) IS
  BEGIN
    IF p_Top THEN
      v_Handled := FALSE;
    ELSIF NOT v_Handled THEN
      v_Handled := TRUE;
      v_ErrorStack := DBMS_UTILITY.FORMAT_ERROR_STACK;
      v_CallStack := DBMS_UTILITY.FORMAT_CALL_STACK;
    END IF;      
  END HandleAll;

  PROCEDURE PrintStacks(p_Module IN errors.module%TYPE,
                        p_SeqNum IN errors.seq_number%TYPE) IS
    v_TimeStamp errors.timestamp%TYPE;
    v_ErrorMsg  errors.error_mesg%TYPE;

    CURSOR c_CallCur IS
      SELECT object_handle, line_num, object_name
        FROM call_stacks
        WHERE module = p_Module
        AND seq_number = p_SeqNum
        ORDER BY call_order;

    CURSOR c_ErrorCur IS
      SELECT facility, error_number, error_mesg
        FROM error_stacks
        WHERE module = p_Module
        AND seq_number = p_SeqNum
        ORDER BY error_order;
  BEGIN
    SELECT timestamp, error_mesg
      INTO v_TimeStamp, v_ErrorMsg
      FROM errors
      WHERE module = p_Module
      AND seq_number = p_SeqNum;

    -- ʓIȃG[o͂B
    DBMS_OUTPUT.PUT(TO_CHAR(v_TimeStamp, 'DD-MON-YY HH24:MI:SS'));
    DBMS_OUTPUT.PUT('  Module: ' || p_Module);
    DBMS_OUTPUT.PUT('  Error #' || p_SeqNum || ':  ');
    DBMS_OUTPUT.PUT_LINE(v_ErrorMsg);
    -- R[X^bNo͂B
    DBMS_OUTPUT.PUT_LINE('Complete Call Stack:');
    DBMS_OUTPUT.PUT_LINE('  Object Handle  Line Number  Object Name');
    DBMS_OUTPUT.PUT_LINE('  -------------  -----------  -----------');
    FOR v_CallRec in c_CallCur LOOP
      DBMS_OUTPUT.PUT(RPAD('  ' || v_CallRec.object_handle, 15));
      DBMS_OUTPUT.PUT(RPAD('  ' || TO_CHAR(v_CallRec.line_num), 13));
      DBMS_OUTPUT.PUT_LINE('  ' || v_CallRec.object_name);
    END LOOP;

    -- G[X^bNo͂B
    DBMS_OUTPUT.PUT_LINE('Complete Error Stack:');
    FOR v_ErrorRec in c_ErrorCur LOOP
      DBMS_OUTPUT.PUT('  ' || v_ErrorRec.facility || '-');
      DBMS_OUTPUT.PUT(TO_CHAR(v_ErrorRec.error_number) || ': ');
      DBMS_OUTPUT.PUT_LINE(v_ErrorRec.error_mesg);
    END LOOP;
    
  END PrintStacks;

  PROCEDURE StoreStacks(p_Module IN errors.module%TYPE,
                        p_SeqNum OUT errors.seq_number%TYPE,
                        p_CommitFlag BOOLEAN DEFAULT FALSE) IS
    v_SeqNum     NUMBER;

    v_Index      NUMBER;
    v_Length     NUMBER;
    v_End        NUMBER;

    v_Call       VARCHAR2(100);
    v_CallOrder  NUMBER := 1;
    v_Handle     call_stacks.object_handle%TYPE;
    v_LineNum    call_stacks.line_num%TYPE;
    v_ObjectName call_stacks.object_name%TYPE;

    v_Error      VARCHAR2(120);
    v_ErrorOrder NUMBER := 1;
    v_Facility   error_stacks.facility%TYPE;
    v_ErrNum     error_stacks.error_number%TYPE;
    v_ErrMsg     error_stacks.error_mesg%TYPE;

    v_FirstErrNum errors.error_number%TYPE;
    v_FirstErrMsg errors.error_mesg%TYPE;
  BEGIN
   -- ܂G[V[PXԍlB
    SELECT error_seq.nextval
      INTO v_SeqNum
      FROM dual;

    p_SeqNum := v_SeqNum;

   -- wb_[̍ŏ̕error\ɑ}B
    INSERT INTO errors
      (module, seq_number, error_stack, call_stack, timestamp)
    VALUES
      (p_Module, v_SeqNum, v_ErrorStack, v_CallStack, SYSDATE);

   -- G[X^bNĂꂼ̃G[oBɂ́AG[X^bN
   -- 𑖍B܂̐擪ɂJnB
    v_Index := 1;
   -- sTȂ當[vĂBśÃX^bN̊eG[̍Ō
   -- ȂB
    WHILE v_Index <  LENGTH(v_ErrorStack) LOOP
      -- v_End͉s̈ʒuB
      v_End := INSTR(v_ErrorStack, v_NewLine, v_Index);

      -- ܂AG[݂͌̍Ɖs̊Ԃɂ邱Ƃ킩B
      v_Error := SUBSTR(v_ErrorStack, v_Index, v_End - v_Index);

      -- ݂̃G[XLbvāÃ[vJnB
      v_Index := v_Index + LENGTH(v_Error) + 1;

      -- G['facility-number: mesg'ɂ悤Bes[Xo
      -- }KvB

      -- ܂Afacility̓G[̍ŏ3B
      v_Facility := SUBSTR(v_Error, 1, 3); 

      -- facilityƃ_bVL폜i4jB
      v_Error := SUBSTR(v_Error, 5);
      -- ŃG[ԍlB
      v_ErrNum := TO_NUMBER(SUBSTR(v_Error, 1, INSTR(v_Error, ':') - 1));

      -- G[ԍARAXy[X폜i7jB
      v_Error := SUBSTR(v_Error, 8);

      -- ĉG[bZ[WłB
      v_ErrMsg := v_Error;

      -- G[}āAōŏ̃G[ԍƃbZ[WĂ܂B
      INSERT INTO error_stacks
        (module, seq_number, error_order, facility, error_number, error_mesg)
      VALUES
        (p_Module, p_SeqNum, v_ErrorOrder, v_Facility, v_ErrNum, v_ErrMsg);

      IF v_ErrorOrder = 1 THEN
        v_FirstErrNum := v_ErrNum;
        v_FirstErrMsg := v_Facility || '-' || TO_NUMBER(v_ErrNum) ||
                         ': ' || v_ErrMsg;
      END IF;

      v_ErrorOrder := v_ErrorOrder + 1;
    END LOOP;
 
    -- errors\bZ[WƃR[hōXVB
    UPDATE errors
      SET error_number = v_FirstErrNum,
          error_mesg = v_FirstErrMsg
      WHERE module = p_Module
      AND seq_number = v_SeqNum;

   -- ŃR[X^bNĂꂼ̃R[oBɂ́A
   -- R[X^bN𑖍B܂X^bN̍ŏ̃R[̌ɂ
   -- JnB́AŏɌ'name'ƉšłB
    v_Index := INSTR(v_CallStack, 'name') + 5;

   -- sTȂ當[vĂBśÃX^bN̊eR[
   -- ŌɂȂB
    WHILE v_Index <  LENGTH(v_CallStack) LOOP
     -- v_End͉s̈ʒuB
      v_End := INSTR(v_CallStack, v_NewLine, v_Index);

     -- ܂AR[݂͌̍Ɖs̊Ԃɂ邱Ƃ킩B
      v_Call := SUBSTR(v_CallStack, v_Index, v_End - v_Index);

     -- ݂̃R[XLbvāÃ[vJnB
      v_Index := v_Index + LENGTH(v_Call) + 1;

     -- R[̒ɂ̓IuWFNgnhAɍsԍAăIuWFNgXy[X
     -- ؂ēĂB}ɂ́A𕪂Ȃ΂ȂȂB

     -- ܂AR[󔒃Xy[X폜B
      v_Call := LTRIM(v_Call);

     -- ܂AIuWFNgnhlB
      v_Handle := SUBSTR(v_Call, 1, INSTR(v_Call, ' '));

     -- ɁAIuWFNgnh폜āAR[󔒃Xy[X폜B
      v_Call := SUBSTR(v_Call, LENGTH(v_Handle) + 1);
      v_Call := LTRIM(v_Call);

     -- x͍sԍlB
      v_LineNum := TO_NUMBER(SUBSTR(v_Call, 1, INSTR(v_Call, ' ')));

     -- sԍAɋ󔒃Xy[X폜B
      v_Call := SUBSTR(v_Call, LENGTH(v_LineNum) + 1);
      v_Call := LTRIM(v_Call);

     -- ĉIuWFNgB
      v_ObjectName := v_Call;

     -- ErrorPkg̃R[ȊÔׂẴR[}B
      IF v_CallOrder > 1 THEN
        INSERT INTO call_stacks
          (module, seq_number, call_order, object_handle, line_num, object_name)
        VALUES
          (p_Module, v_SeqNum, v_CallOrder, v_Handle, v_LineNum, v_ObjectName);
      END IF;

      v_Callorder := v_CallOrder + 1;

    END LOOP;

    IF p_CommitFlag THEN 
      commit; 
    END IF;
  END StoreStacks;
END ErrorPkg;



-- Available online as abc2.sql
CREATE OR REPLACE TRIGGER temp_insert
  BEFORE INSERT ON temp_table
BEGIN
  RAISE ZERO_DIVIDE;
END ttt_insert;

CREATE OR REPLACE PROCEDURE C AS
BEGIN
  INSERT INTO temp_table (num_col) VALUES (7);
EXCEPTION
  WHEN OTHERS THEN
    ErrorPkg.HandleAll(FALSE);
    RAISE;
END C;

CREATE OR REPLACE PROCEDURE B AS
BEGIN
  C;
EXCEPTION
  WHEN OTHERS THEN
    ErrorPkg.HandleAll(FALSE);
    RAISE;
END B;

CREATE OR REPLACE PROCEDURE A AS
  v_ErrorSeq NUMBER;
BEGIN
  B;
EXCEPTION
  WHEN OTHERS THEN
    ErrorPkg.HandleAll(TRUE);
    ErrorPkg.StoreStacks('Error Test', v_ErrorSeq, TRUE);
    ErrorPkg.PrintStacks('Error Test', v_ErrorSeq);
END A;



WHEN OTHERS THEN
  ErrorPkg.HandleAll(FALSE);
RAISE;



SQL> SET SERVEROUTPUT ON SIZE 1000000 FORMAT TRUNCATED
SQL> EXEC A;
18-JAN-97 22:14:49  Module: Error Test  Error #7:  ORA-1476: divisor is equal to zero
Complete Call Stack:
  Object Handle  Line Number  Object Name
  -------------  -----------  -----------
  16998f0        6            procedure EXAMPLE.C
  1699ca0        3            procedure EXAMPLE.B
  169f918        4            procedure EXAMPLE.A
  16570e0        1            anonymous block
Complete Error Stack:
  ORA-1476: [łB
  ORA-6512: "EXAMPLE.TEMP_INSERT", s: 2
  ORA-4088: gK[EXAMPLE.TEMP_INSERT̎sɃG[܂B

PL/SQL procedure successfully completed.




Chapter 11
Oracle8 Enterprise Edition Release 8.0.3.0.0 - Production
With the Partitioning and Objects options
PL/SQL Release 8.0.3.0.0 - Production



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE StudentObj AS OBJECT(
  ID               NUMBER(5),
  first_name       VARCHAR2(20),
  last_name        VARCHAR2(20),
  major            VARCHAR2(30),
  current_credits  NUMBER(3)
  );



DECLARE
  v_Student StudentObj;



FUNCTION StudentObj(ID IN NUMBER,
                    first_name IN VARCHAR2,
                    last_name IN VARCHAR2,
                    major IN VARCHAR2,
                    current_credits IN NUMBER)
  RETURN StudentObj;



-- Available online as objinit.sql
DECLARE
  -- ݒ肵ăIuWFNgCX^X쐬B
  v_Student StudentObj :=
    StudentObj(10020, 'Chuck', 'Choltry', NULL, 0);       
BEGIN
  -- majoriUj'Music'iyjɕύXBhbg\L@gpđ
  -- QƂ邱ƂɒځB
  v_Student.major := 'Music';
END;



DECLARE
  v_Student StudentObj; 
BEGIN
  v_Student.ID := 10020; 
END;



-- Available online as aname.sql
CREATE OR REPLACE PROCEDURE AssignName(
  p_Student IN OUT StudentObj,
  p_FirstName IN StudentObj.first_name%TYPE,
  p_LastName IN StudentObj.last_name%TYPE) AS
BEGIN
  IF p_Student IS NULL THEN
    RAISE_APPLICATION_ERROR(-20000, 'Student is NULL');
  ELSE
    p_Student.first_name := p_FirstName;
    p_Student.last_name := p_LastName;
  END IF;
END AssignName;



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE StudentObj AS OBJECT (
  ID               NUMBER(5),
  first_name       VARCHAR2(20),
  last_name        VARCHAR2(20),
  major            VARCHAR2(30),
  current_credits  NUMBER(3),

  -- Xy[Xŋ؂ĎԂB
  MEMBER FUNCTION FormattedName
    RETURN VARCHAR2,
  PRAGMA RESTRICT_REFERENCES(FormattedName,
    RNDS, WNDS, RNPS, WNPS),

  -- MajoriUjp_NewMajorŎw肳ꂽlɍXVB
  MEMBER PROCEDURE ChangeMajor(p_NewMajor IN VARCHAR2),
  PRAGMA RESTRICT_REFERENCES(ChangeMajor,
    RNDS, WNDS, RNPS, WNPS),

  -- p_CompletedClass̒Pʐ݂̒lɉāA
  -- current_creditXVB
  MEMBER PROCEDURE UpdateCredits(p_CompletedClass IN ClassObj),
  PRAGMA RESTRICT_REFERENCES(UpdateCredits,
    RNDS, WNDS, RNPS, WNPS)
);



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE BODY StudentObj AS
  MEMBER FUNCTION FormattedName
    RETURN VARCHAR2 IS
  BEGIN
    RETURN SELF.first_name || ' ' || SELF.last_name;
  END FormattedName;

  MEMBER PROCEDURE ChangeMajor(p_NewMajor IN VARCHAR2) IS
  BEGIN
    major := p_NewMajor;
  END ChangeMajor;

  MEMBER PROCEDURE UpdateCredits(p_CompletedClass IN ClassObj)
    IS
  BEGIN
    current_credits := 
      current_credits + p_CompletedClass.num_credits;
  END UpdateCredits;
END;



-- Available online as mcall.sql
DECLARE
  v_Student1 StudentObj :=
    StudentObj(10020, 'Chuck', 'Choltry', NULL, 0);      
  v_Student2 StudentObj :=
    StudentObj(10021, 'Denise', 'Davenport', NULL, 0);
BEGIN
  -- 2l̊w̐UύXB
  v_Student1.ChangeMajor('Economics');
  v_Student2.ChangeMajor('Computer Science');

  -- Student1̖Oo͂B̃R[ɂ̓JbRgpĂȂ_ɒӁB
  DBMS_OUTPUT.PUT_LINE(v_Student1.FormattedName);

  -- Student2̖Oo͂B̃R[ɂ͋̃JbRgpĂB
  DBMS_OUTPUT.PUT_LINE(v_Student2.FormattedName());
END;



MEMBER PROCEDURE ChangeMajor(p_NewMajor IN VARCHAR2) IS
  BEGIN
    major := p_NewMajor;
  END ChangeMajor;



MEMBER PROCEDURE ChangeMajor(p_NewMajor IN VARCHAR2) IS
  BEGIN
    SELF.major := p_NewMajor;
  END ChangeMajor;



-- Available online as prcnttyp.sql
DECLARE
  -- ܂R[h^AɃR[hƃIuWFNg^̕ϐ錾B
  TYPE t_Rec IS RECORD ( 
    f1 NUMBER, 
    f2 VARCHAR2(10)); 
  v_Student StudentObj;
  v_Rec     t_Rec;

  -- ̐錾%TYPEϐɓKpĂ̂ŁALłB
  v_ID v_Student.ID%TYPE;
  -- ̐錾%TYPEIuWFNg^ɓKpĂ̂ŁAPLS-206G[ɂȂB
  v_ID2 StudentObj.ID%TYPE;    

  -- ̐錾́A%TYPEϐɓKpĂ̂ŁALłB
  v_F1 v_Rec.f1%TYPE;
  -- ̐錾ł%TYPER[h^ɓKpĂ̂ŁAPLS-206G[ɂȂB
  v_F2 t_Rec.f2%TYPE;      
BEGIN
  NULL;
END;



PLS-206F%TYPE͕ϐAAtB[h܂͑ɓKpȂ΂Ȃ܂B



-- Available online as part of error.sql
CREATE OR REPLACE TYPE ErrorObj AS OBJECT (
  attribute NUMBER,
  MEMBER PROCEDURE RaiseError(p_RaiseIt IN BOOLEAN,
                              p_OutParam IN OUT NUMBER),
  MEMBER PROCEDURE Print(p_Comment IN VARCHAR2 DEFAULT NULL)
);

CREATE OR REPLACE TYPE BODY ErrorObj AS
  MEMBER PROCEDURE RaiseError(p_RaiseIt IN BOOLEAN,
                              p_OutParam IN OUT NUMBER) IS
  BEGIN
    -- INlāAOUTlɂ1B
    SELF.attribute := p_outParam;
    p_OutParam := p_OutParam + 1;
    IF p_RaiseIt THEN
      RAISE NO_DATA_FOUND;
    END IF;
  END RaiseError;

  MEMBER PROCEDURE Print (p_Comment IN VARCHAR2 DEFAULT NULL) IS
  BEGIN
    -- RgƑlo͂B
    IF p_Comment IS NOT NULL THEN
      DBMS_OUTPUT.PUT(p_Comment || ', ');
    END IF;
    DBMS_OUTPUT.PUT_LINE('attribute = ' || attribute);
  END Print;
END;



-- Available online as part of error.sql
DECLARE
  v_Test ErrorObj := ErrorObj(1);
  v_NumVal NUMBER := 10;
BEGIN
  -- ܂v_NumValo͂B
  v_Test.Print('After initialization, v_NumVal = ' || v_NumVal);
  -- p[^Ƒ悤Falsew肵RaiseErrorR[B
  v_Test.RaiseError(FALSE, v_NumVal);
  v_Test.Print('After call with no exception, v_NumVal = ' ||
               v_NumVal);
  -- p[^ƑȂ悤TRUEw肵RaiseErrorR[B
  v_Test.RaiseError(TRUE, v_NumVal);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    v_Test.Print('After call with exception, v_NumVal = ' ||
                 v_NumVal);
END;



After initialization, v_NumVal = 10, attribute = 1
After call with no exception, v_NumVal = 11, attribute = 10
After call with exception, v_NumVal = 11, attribute = 10



ALTER TYPE StudentObj COMPILE BODY;



-- Available online as alter.sql
SQL> /* 2̑2̃\bhȒPȃIuWFNg^쐬B*/
SQL> CREATE OR REPLACE TYPE DummyObj AS OBJECT (
  2    f1 NUMBER,
  3    f2 NUMBER,
  4    MEMBER PROCEDURE Method1(x IN VARCHAR2),
  5    MEMBER FUNCTION Method2 RETURN DATE
  6  );
  7  /

Type created.

SQL> /* ^{̂쐬B*/
SQL> CREATE OR REPLACE TYPE BODY DummyObj AS
  2    MEMBER PROCEDURE Method1(x IN VARCHAR2) IS
  3    BEGIN
  4      NULL;
  5    END Method1;
  6  
  6    MEMBER FUNCTION Method2 RETURN DATE IS
  7    BEGIN
  8      RETURN SYSDATE;
  9    END Method2;
 10  END;
 11  /

Type body created.

SQL> SELECT object_name, object_type, status
  2    FROM user_objects
  3    WHERE object_name = 'DUMMYOBJ';

OBJECT_NAME          OBJECT_TYPE     STATUS
-------------------- --------------- -------
DUMMYOBJ             TYPE            VALID
DUMMYOBJ             TYPE BODY       VALID

SQL> /* ^ύXĐV\bhǉBŌ^{͖̂ɂȂB*/
SQL> ALTER TYPE DummyObj REPLACE AS OBJECT (
  2    f1 NUMBER,
  3    f2 NUMBER,
  4    MEMBER PROCEDURE Method1(x IN VARCHAR2),
  5    MEMBER FUNCTION Method2 RETURN DATE,
  6    MEMBER PROCEDURE Method3
  7  );

Type altered.

SQL> SELECT object_name, object_type, status
  2    FROM user_objects
  3    WHERE object_name = 'DUMMYOBJ';

OBJECT_NAME          OBJECT_TYPE     STATUS
-------------------- --------------- -------
DUMMYOBJ             TYPE            VALID
DUMMYOBJ             TYPE BODY       INVALID



-- Available online as odepend.sql
CREATE OR REPLACE TYPE Obj1 AS OBJECT ( 
  f1 NUMBER,
  f2 VARCHAR2(10),
  f3 DATE
);

CREATE OR REPLACE TYPE Obj2 AS OBJECT ( 
  f1 DATE,
  f2 CHAR(1)
);

CREATE OR REPLACE TYPE Obj3 AS OBJECT ( 
  a Obj1, 
  b Obj2 
);



SQL> DROP TYPE Obj1;
DROP TYPE Obj1
*
ERROR at line 1:
ORA-02303: ˑ^\^́A폜܂͒uł܂B

SQL> DROP TYPE Obj3;
Type dropped.

SQL> DROP TYPE Obj1;
Type dropped.



-- Available online as part of tables8.sql
-- ܂IuWFNg^̎dlƖ{̂쐬B
CREATE OR REPLACE TYPE RoomObj AS OBJECT (
  ID           NUMBER(5),
  building     VARCHAR2(15),
  room_number  NUMBER(4),
  number_seats NUMBER(4),
  description  VARCHAR2(50),
  MEMBER PROCEDURE Print
);

CREATE OR REPLACE TYPE BODY RoomObj AS
  MEMBER PROCEDURE Print IS
  BEGIN
    DBMS_OUTPUT.PUT('Room ID:' || ID || ' is located in ');
    DBMS_OUTPUT.PUT(building || ', room ' || room_number); 
    DBMS_OUTPUT.PUT(', and has ' || number_seats || ' seats.');
    DBMS_OUTPUT.NEW_LINE;
  END Print;
END;

-- ɃIuWFNg\쐬B
CREATE TABLE rooms OF RoomObj;



-- Available online as part of tables8.sql
INSERT INTO rooms VALUES
  (RoomObj(99999, 'Building 7', 310, 1000,
           'Large Lecture Hall'));
INSERT INTO rooms VALUES
  (RoomObj(99998, 'Building 6', 101, 500,
           'Small Lecture Hall'));
INSERT INTO rooms VALUES
  (RoomObj(99997, 'Building 6', 150, 50,
           'Discussion Room A'));
INSERT INTO rooms VALUES
  (RoomObj(99996, 'Building 6', 160, 50,
           'Discussion Room B'));



INSERT INTO rooms VALUES
  (99999, 'Building 7', 310, 1000, 'Large Lecture Hall');



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE AddressObj AS OBJECT (
  line1    VARCHAR2(40),
  line2    VARCHAR2(40),
  city     VARCHAR2(30),
  state    CHAR(2),
  zipcode  NUMBER(5)
);
CREATE TABLE students (
  student StudentObj,
  address AddressObj
);



-- Available online as part of tables8.sql
INSERT INTO students VALUES
  (StudentObj(student_sequence.NEXTVAL, 'Scott', 'Smith',
              'Computer Science', 0),
   AddressObj('100 Main St', NULL, 'East Brunswick', 'CA',
              91234));     
INSERT INTO students VALUES
  (StudentObj(student_sequence.NEXTVAL, 'Margaret', 'Mason',
             'History', 0),
   AddressObj('350 Sorority Row', 'Apt# 2B', 'East Brunswick',
              'CA', 91234));
INSERT INTO students VALUES
  (StudentObj(student_sequence.NEXTVAL, 'Joanne', 'Junebug',
              'Computer Science', 0),
   NULL);



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE ClassObj AS OBJECT (
  department       CHAR(3),
  course           NUMBER(3),
  description      VARCHAR2(2000),
  max_students     NUMBER(3),
  current_students NUMBER(3),
  num_credits      NUMBER(1),
  room             REF RoomObj
);



-- Available online as update.sql
DECLARE
  v_NewRoom RoomObj :=
    RoomObj(99990, 'Building 7', 200, 50, 'Discussion Room F');
  v_RoomRef REF RoomObj;
BEGIN
  -- ̕RETURNINǴAV}roomւ̎QƂv_RoomRefɓB
  INSERT INTO rooms r VALUES (v_NewRoom)
    RETURNING REF(r) INTO  v_RoomRef;

  UPDATE classes
    SET room = v_RoomRef
    WHERE department = 'NUT' and course = 307;
END;



DELETE FROM students s
  WHERE s.student.major = 'History';



-- Available online as part of colsel.sql
DECLARE
  v_Student StudentObj;
  v_Address AddressObj;

  CURSOR c_Students IS
    SELECT student, address
      FROM students;
BEGIN
  -- ׂĂ̊wIDo͂B
  OPEN c_Students;

  LOOP
    FETCH c_Students INTO v_Student, v_Address;
    EXIT WHEN c_Students%NOTFOUND;

    DBMS_OUTPUT.PUT_LINE('Student ID: ' || v_Student.ID); 
  END LOOP;

  CLOSE c_Students;
END;



SELECT student
  FROM students
  WHERE students.student.id = 10009;



-- Available online as part of colsel.sql
DECLARE
  v_Student StudentObj;
BEGIN
  -- PLS-327ĂяoB
  SELECT student
    INTO v_Student
    FROM students
    WHERE students.student.ID = 10009;
END;



-- Available online as part of colsel.sql
DECLARE
  v_Student StudentObj;
BEGIN
  -- \GCAX̂ŁAɎsꂽB
  SELECT student
    INTO v_Student
    FROM students s
    WHERE s.student.ID = 10009;       
END;



-- Available online as valueop.sql
DECLARE
  v_RoomID      rooms.id%TYPE;
  v_Building    rooms.building%TYPE;
  v_RoomNumber  rooms.room_number%TYPE;
  v_NumberSeats rooms.number_seats%TYPE;
  v_Description rooms.description%TYPE;
  v_RoomObj     RoomObj;
BEGIN
  -- VALUEgpȂSELECTsB̓[Vi⍇
  -- SłB
  SELECT *
    INTO v_RoomID, v_Building, v_RoomNumber, v_NumberSeats,
         v_Description
    FROM rooms r
    WHERE ID = 99993;

  -- VALUEgpSELECTsB̏ꍇ́ARoomObjoB
  SELECT VALUE(r)
    INTO v_RoomObj
    FROM rooms r
    WHERE ID = 99993;
END;



-- Available online as part of refop.sql
DECLARE
  v_RoomRef REF RoomObj;
BEGIN
  -- room̂̂ł͂ȂAroomɑ΂QƂIB
  SELECT REF(r)
    INTO v_RoomRef
    FROM rooms r
    WHERE ID = 99993;
END;



-- Available online as refop.sql
DECLARE
  v_RoomRef REF RoomObj;
  v_Room    RoomObj;
BEGIN
  -- room̂̂ł͂ȂAroomɑ΂QƂIB
  SELECT REF(r)
    INTO v_RoomRef
    FROM rooms r
    WHERE ID = 99993;

  -- v_RoomRefQƉăIuWFNglAIuWFNgXVB
  -- ŕԂ郍[JIuWFNǵAroom\Ɋi[ꂽIuWFNgƂ
  -- قȂB
  SELECT DEREF(v_RoomRef)
    INTO v_Room
    FROM dual;

  -- Ń[JIuWFNgXVB
  v_Room.room_number := 201;
END;



BEGIN
  -- ׂĂ̂Ԃ牺REFNULLɐݒ肷B
  UPDATE classes
    SET room = NULL
    WHERE room IS DANGLING;
END;



-- Available online as return.sql
DECLARE
  v_ClassRef REF ClassObj;
BEGIN
  INSERT INTO CLASSES c VALUES
    (ClassObj('HIS', 101, 'History 101', 30, 0, 4, NULL))
    RETURNING REF(c) INTO v_ClassRef;    
END;



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE RoomObj AS OBJECT (
  ID NUMBER(5),
  ...
  -- MAP֐gprooms\[gB
  MAP MEMBER FUNCTION ReturnID RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY RoomObj AS 
  ...
  MAP MEMBER FUNCTION ReturnID RETURN NUMBER IS
  BEGIN
    RETURN SELF.ID;
  END ReturnID;
END RoomObj;



SQL> SELECT VALUE(r)
  2    FROM rooms r
  3    ORDER BY 1;

VALUE(R)(ID, BUILDING, ROOM_NUMBER, NUMBER_SEATS, DESCRIPTION)
----------------------------------------------------------------
ROOMOBJ(99991, 'Building 7', 310, 50, 'Discussion Room E')
ROOMOBJ(99992, 'Building 7', 300, 75, 'Discussion Room D')
ROOMOBJ(99993, 'Music Building', 200, 1000, 'Concert Room')
ROOMOBJ(99994, 'Music Building', 100, 10, 'Music Practice Room')
ROOMOBJ(99995, 'Building 6', 170, 50, 'Discussion Room C')
ROOMOBJ(99996, 'Building 6', 160, 50, 'Discussion Room B')
ROOMOBJ(99997, 'Building 6', 150, 50, 'Discussion Room A')
ROOMOBJ(99998, 'Building 6', 101, 500, 'Small Lecture Hall')
ROOMOBJ(99999, 'Building 7', 310, 1000, 'Large Lecture Hall')



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE StudentObj AS OBJECT (
  ID               NUMBER(5),
  first_name       VARCHAR2(20),
  last_name        VARCHAR2(20),
  major            VARCHAR2(30),
  current_credits  NUMBER(3),

  ...
  -- ORDER֐gpĊw\[gB
  ORDER MEMBER FUNCTION CompareStudent(p_Student IN StudentObj)
    RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY StudentObj AS
  ...
  ORDER MEMBER FUNCTION CompareStudent(p_Student IN StudentObj)
    RETURN NUMBER IS
  BEGIN
    IF p_Student.last_name = SELF.last_name THEN
      IF p_Student.first_name < SELF.first_name THEN
        RETURN 1;
      ELSIF p_Student.first_name > SELF.first_name THEN
        RETURN -1;
      ELSE
        RETURN 0;
      END IF;
    ELSE
      IF p_Student.last_name < SELF.last_name THEN
        RETURN 1;
      ELSIF p_Student.last_name > SELF.last_name THEN
        RETURN -1;
      ELSE
        RETURN 0;
      END IF;
    END IF;
  END CompareStudent;
END;



SQL> SELECT student
  2    FROM students
  3    ORDER BY student DESC;

STUDENT(ID, FIRST_NAME, LAST_NAME, MAJOR, CURRENT_CREDITS)
----------------------------------------------------------------
STUDENTOBJ(10005, 'Timothy', 'Taller', 'History', 0)
STUDENTOBJ(10000, 'Scott', 'Smith', 'Computer Science', 0)
STUDENTOBJ(10009, 'Rose', 'Riznit', 'Music', 0)
STUDENTOBJ(10010, 'Rita', 'Razmataz', 'Nutrition', 0)
STUDENTOBJ(10004, 'Patrick', 'Poll', 'History', 0)
STUDENTOBJ(10003, 'Manish', 'Murgratroid', 'Economics', 0)
STUDENTOBJ(10001, 'Margaret', 'Mason', 'History', 0)
STUDENTOBJ(10002, 'Joanne', 'Junebug', 'Computer Science', 0)
STUDENTOBJ(10008, 'Ester', 'Elegant', 'Nutrition', 0)
STUDENTOBJ(10007, 'David', 'Dinsmore', 'Music', 0)
STUDENTOBJ(10006, 'Barbara', 'Blues', 'Economics', 0)



Chapter 12
-- Available online as part of nested.sql
DECLARE
  --IuWFNg^ɊÂĕ\̌^`B
  TYPE t_ClassesTab IS TABLE OF ClassObj;

  -- %ROWTYPEɊÂ\
  TYPE t_StudentsTab IS TABLE OF students%ROWTYPE;

  --Ľ^̕ϐB
  v_ClassList t_ClassesTab;
  v_StudentList t_StudentsTab;



-- Available online as part of nested.sql
BEGIN
  -- ̑sƁAV_ClassListAg~bNNULLȂ̂ŁA 
  -- COLLECTION_IS_NULLĂяoB
  v_ClassList(1) := ClassObj('HIS', 101, 'History 101', 30, 0, 4, NULL);
END;



-- Available online as tconstr.sql
DECLARE
  TYPE t_NumbersTab IS TABLE OF NUMBER;

  -- 1̗vf\쐬B
  v_Tab1 t_NumbersTab := t_NumbersTab(-1);

  -- 5̗vf\쐬B
  v_Primes t_NumbersTab := t_NumbersTab(1, 2, 3, 5, 7);

  --vfȂ\쐬B
  v_Tab2 t_NumbersTab := t_NumbersTab();
BEGIN
  -- v_Tab1(1)ɑBŁAłv_Tab1(1)
  --Ă-1ɏꂽluB
  v_Tab1(1) := 12345;
END;



--vfȂ\쐬B
  v_Tab2 t_NumbersTab := t_NumbersTab();



-- Available online as nulltab.sql
DECLARE
  TYPE t_WordsTab IS TABLE OF VARCHAR2(50);

  -- NULL\쐬B
  v_Tab1 t_WordsTab;

  --ꎩgNULLł1̗vf\쐬B
  v_Tab2 t_WordsTab := t_WordsTab();
BEGIN
  IF v_Tab1 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('v_Tab1 is NULL');
  ELSE
    DBMS_OUTPUT.PUT_LINE('v_Tab1 is not NULL');
  END IF;

  IF v_Tab2 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('v_Tab2 is NULL');
  ELSE
    DBMS_OUTPUT.PUT_LINE('v_Tab2 is not NULL');
  END IF;
END;



v_Tab1 is NULL
v_Tab2 is not NULL



-- Available online as tassign.sql
DECLARE
  TYPE t_NumbersTab IS TABLE OF NUMBER;
  v_Numbers t_NumbersTab := t_NumbersTab(1, 2, 3);
BEGIN
  -- v_Numbers3̗vf悤ɏĂB 
  --āAȉׂ̑͂ėLB
  v_Numbers(1) := 7;  
  v_Numbers(2) := -1;

  --ȂORA-6533ɂȂB
  v_Numbers(4) := 4;
END;



-- Available online as part of tables8.sql
CREATE TYPE BookObj AS OBJECT (
  title          VARCHAR2(40),
  author         VARCHAR2(40),
  catalog_number NUMBER(4)
);

CREATE TYPE BookList AS TABLE OF BookObj;

CREATE TABLE course_material (
  department       CHAR(3),
  course           NUMBER(3),
  required_reading BookList)
  NESTED TABLE required_reading STORE AS required_tab;



-- Available online as tinsert.sql
DECLARE
  v_Books Booklist := 
    BookList(BookObj('A History of the World', 'Smith', 2001)); 
BEGIN
  --V쐬ꂽ2̗vflXg\gpINSERTsB
  INSERT INTO course_material VALUES (  
  'CS', 101,
    BookList(BookObj('Oracle8 PL/SQL Programming',
                     'Urman', 1000),
             BookObj('Oracle8: A Beginner''s Guide',
                     'Abbey, Corey', 1001),
             BookObj('Tuning Oracle',
                     'Corey, Abbey, Dechichio', 1002)));

  --Oɏꂽ1̗vflXg\gpINSERTsB
  INSERT INTO course_material VALUES (
    'HIS', 301, v_Books);
END;



-- Available online as tupdate.sql
DECLARE
  v_Books Booklist :=
    BookList(BookObj('A History of the World', 'Smith', 2001),
             BookObj('Another World History', 'Jones', 2002));
BEGIN
  UPDATE course_material
    SET required_reading = v_Books
    WHERE department = 'HIS'
    AND course = 301;
END;



-- Available online as tdelete.sql
BEGIN
  --ׂĂhistoryijjR[X̕K{ۑ}폜B
  DELETE FROM course_material  
    WHERE department = 'HIS';
END;



-- Available online as tselect.sql
DECLARE
  v_Books course_material.required_reading%TYPE;
  v_Course course_material.course%TYPE;
  v_Department course_material.department%TYPE;

  CURSOR c_AllBooks IS
    SELECT required_reading, course, department 
      FROM course_material;
BEGIN
  --ׂẴR[X[vāAiDBMS_OUTPUTgpājK{ۑ}
  --ڂo͂B
  OPEN c_AllBooks;

  LOOP
    -- required_readingɊi[ꂽlXg\܂߂āA 
    --̍ŝׂĂ̗tFb`B
    FETCH c_AllBooks INTO v_Books, v_Course, v_Department;
    EXIT WHEN c_AllBooks%NOTFOUND;

    DBMS_OUTPUT.PUT('Required reading for ' || v_Department || ' ');
    DBMS_OUTPUT.PUT_LINE(v_Course || ':');

    --Iꂽ\ׂĂ[vāAeso͂B
    FOR v_Index IN 1..v_Books.COUNT LOOP
      DBMS_OUTPUT.PUT_LINE('  ' || v_Books(v_Index).title);
    END LOOP;
  END LOOP;

  CLOSE c_AllBooks;
END;



Required reading for CS  101:
  Oracle8 PL/SQL Programming
  Oracle8: A Beginner's Guide
  Tuning Oracle
Required reading for HIS 301:
  A History of the World
  Another World History



UPDATE THE(SELECT required_reading
             FROM course_material
             WHERE department = 'CS' AND course = 101)
  SET catalog_number = catalog_number + 10;



DECLARE
  TYPE t_BookList IS VARRAY(25) OF BookObj; 
  TYPE t_Numbers IS VARRAY(10) OF NUMBER(3) NOT NULL;
  TYPE t_Students IS VARRAY(100) OF students%ROWTYPE;



-- Available online as vconstr.sql
DECLARE
  -- VARRAY^`B
  TYPE t_Numbers IS VARRAY(20) OF NUMBER(3);

  -- NULLϒz錾B
  v_NullList t_Numbers;

  --̉ϒzɂ2̗vfB
  v_List1 t_Numbers := t_Numbers(1, 2);

  --̉ϒzɂ́AꎩgNULL̗vf1B
  v_List2 t_Numbers := t_Numbers(NULL);
BEGIN
  IF v_NullList IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('v_NullList is NULL');
  END IF;

  IF v_List2(1) IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('v_List2(1) is NULL');
  END IF;
END;



v_NullList is NULL
v_List2(1) is NULL



-- Available online as vassign.sql
DECLARE
  TYPE t_Strings IS VARRAY(5) OF VARCHAR2(10);

  -- 3̗vfϒz錾B 
  --̌^̍őTCY͗vf5B
  v_List t_Strings := t_Strings('Scott', 'David', 'Urman');
BEGIN
  --TuXNvg13܂ł̊ԂȂ̂ŁȂ͗LB
  v_List(2) := 'DAVID';

  --TuXNvg͈͊OȂ̂ŁAORA-6533ɂȂB
  v_List(4) := '!!!';
END;



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE BookList2 AS VARRAY(10) OF BookObj;

CREATE TABLE checked_out (
  student_id number(5),
  books BookList2
);



-- Available online as checkout.sql
CREATE OR REPLACE PROCEDURE CheckOut(
  p_StudentID IN NUMBER,
  p_NewBook IN BookObj) AS

  v_Books BookList2;
  v_Found BOOLEAN := FALSE;
  v_Book BookObj;
BEGIN
  --܂Åw؂o݂̐}XglB
  BEGIN
    SELECT books
      INTO v_Books
      FROM checked_out
      WHERE student_id = p_StudentID;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      --w͉}؂oĂȂB
      v_Books := BookList2(NULL);
  END;

  --܂]T邩ǂmFB
  FOR v_Counter IN 1..v_Books.COUNT LOOP
    v_Book := v_Books(v_Counter);

    IF v_Book.catalog_number = p_NewBook.catalog_number THEN
      RAISE_APPLICATION_ERROR(-20001, 'Book is already checked                                  out');
    END IF;
  END LOOP;

  --܂]T邩ǂmFB
  IF v_Books.COUNT = v_Books.LIMIT THEN
    RAISE_APPLICATION_ERROR(-20001, 'Cannot check out any more                                books');
  END IF;

  --Xgɐ}ǉāA{؂oB
  v_Books.EXTEND;
  v_Books(v_Books.COUNT) := p_NewBook;

  --Ăуf[^x[Xɖ߂B
  UPDATE checked_out
    SET books = v_Books
    WHERE student_id = p_StudentID;
  IF SQL%NOTFOUND THEN
    INSERT INTO checked_out (student_id, books)
      VALUES (p_StudentID, v_Books);
  END IF;
END CheckOut;



-- Available online as co.sql
DECLARE
  v_RequiredBooks BookList;
  v_Book BookObj;

BEGIN
  SELECT required_reading
    INTO v_RequiredBooks
    FROM course_material
    WHERE department = 'CS' 
    AND course = 101;

  FOR v_Counter IN 1..v_RequiredBooks.COUNT LOOP
    v_Book := v_RequiredBooks(v_Counter);
    CheckOut(1005, v_Book);           
  END LOOP;
END;



-- Available online as part of tables8.sql
CREATE OR REPLACE TYPE NumTab AS TABLE OF NUMBER;
CREATE OR REPLACE TYPE NumVar AS VARRAY(25) OF NUMBER;



-- Available online as exists.sql
DECLARE
  v_Table NumTab := NumTab(-7, 14.3, 3.14159, NULL, 0);
  v_Count BINARY_INTEGER := 1;
BEGIN
  -- v_Table[vāAvfo͂AEXISTSgpă[v̍ŌB
  LOOP
    IF v_Table.EXISTS(v_Count) THEN
      DBMS_OUTPUT.PUT_LINE('v_Table(' || v_Count || '): ' || 
                           v_Table(v_Count));
      v_Count := v_Count + 1;
    ELSE
      EXIT;
    END IF;
  END LOOP;
END;



v_Table(1): -7
v_Table(2): 14.3
v_Table(3): 3.14159
v_Table(4):
v_Table(5): 0



-- Available online as count.sql
DECLARE
  v_Table NumTab := NumTab(1, 2, 3);
  v_Varray NumVar := NumVar(-1, -2, -3, -4);    
BEGIN
  DBMS_OUTPUT.PUT_LINE('Table Count: ' || v_Table.COUNT);
  DBMS_OUTPUT.PUT_LINE('Varray Count: ' || v_Varray.COUNT);
END;



Table Count: 3
Varray Count: 4



-- Available online as limit.sql
DECLARE
  v_Table NumTab := NumTab(1, 2, 3);
  v_Varray NumVar := NumVar(1234, 4321);
BEGIN
  --RNV̏Ɨvfo͂B
  DBMS_OUTPUT.PUT_LINE('Varray limit: ' || v_Varray.LIMIT);
  DBMS_OUTPUT.PUT_LINE('Varray count: ' || v_Varray.COUNT);
  IF v_Table.LIMIT IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('Table limit is NULL');
  ELSE
    DBMS_OUTPUT.PUT_LINE('Table limit: ' || v_Table.LIMIT);
  END IF;
  DBMS_OUTPUT.PUT_LINE('Table count: ' || v_Table.COUNT);  
END;



Varray limit: 25
Varray count: 2
Table limit is NULL
Table count: 3



-- Available online as loops.sql
DECLARE
  TYPE t_CharTab IS TABLE OF CHAR(1);
  v_Characters t_CharTab := t_CharTab('M', 'a', 'd', 'a', 'm',
               ',', ' ', 'I', '''', 'm', ' ', 'A', 'd', 'a', 'm');

  v_Index INTEGER;
BEGIN
  -- \Ƀ[vB
  v_Index := v_Characters.FIRST;
  WHILE v_Index <= v_Characters.LAST LOOP
    DBMS_OUTPUT.PUT(v_Characters(v_Index));
    v_Index := v_Characters.NEXT(v_Index);
  END LOOP;
  DBMS_OUTPUT.NEW_LINE;

  -- \tɃ[vB
  v_Index := v_Characters.LAST;
  WHILE v_Index >= v_Characters.FIRST LOOP
    DBMS_OUTPUT.PUT(v_Characters(v_Index));
    v_Index := v_Characters.PRIOR(v_Index);
  END LOOP;
  DBMS_OUTPUT.NEW_LINE;
END;



-- Available online as extend.sql
DECLARE
  v_Numbers NumTab := NumTab(1, 2, 3, 4, 5);
BEGIN
  -- v_Numberɂ͗vf5܂܂ĂȂ̂ŁȂ
  -- SUBSCRIPT_BEYOND_COUNTĂяoB
  v_Numbers(26) := -7;  
EXCEPTION  
  WHEN SUBSCRIPT_BEYOND_COUNT THEN  
    DBMS_OUTPUT.PUT_LINE('ORA-6533 raised');  

    -- v_Number30̗vfǉ΁A̖łB
    v_Numbers.EXTEND(30);

    --ősB
    v_Numbers(26) := -7;
END;



-- Available online as extdel.sql
DECLARE
  --\5̗vfɏB
  v_Numbers NumTab := NumTab(-2, -1, 0, 1, 2);

  -- \o͂郍[JvV[WB
  PROCEDURE Print(p_Table IN NumTab) IS
    v_Index INTEGER;
  BEGIN
    v_Index := p_Table.FIRST;
    WHILE v_Index <= p_Table.LAST LOOP
      DBMS_OUTPUT.PUT('Element ' || v_Index || ': ');
      DBMS_OUTPUT.PUT_LINE(p_Table(v_Index));
      v_Index := p_Table.NEXT(v_Index);
    END LOOP;
  END Print;

BEGIN
  DBMS_OUTPUT.PUT_LINE('At initialization, v_Numbers contains');
  Print(v_Numbers);

  -- vf3폜B'0'͍폜邪Av[Xz_͎cB
  v_Numbers.DELETE(3);

  DBMS_OUTPUT.PUT_LINE('After delete, v_Numbers contains');
  Print(v_Numbers);

  -- vf1̃Rs[2\ɒǉBŗvf67ǉB
  v_Numbers.EXTEND(2, 1);

  DBMS_OUTPUT.PUT_LINE('After extend, v_Numbers contains');
  Print(v_Numbers);

  DBMS_OUTPUT.PUT_LINE('v_Numbers.COUNT = ' || v_Numbers.COUNT);
  DBMS_OUTPUT.PUT_LINE('v_Numbers.LAST = ' || v_Numbers.LAST);
END;



At initialization, v_Numbers contains
Element 1: -2
Element 2: -1
Element 3: 0
Element 4: 1
Element 5: 2
After delete, v_Numbers contains
Element 1: -2
Element 2: -1
Element 4: 1
Element 5: 2
After extend, v_Numbers contains
Element 1: -2
Element 2: -1
Element 4: 1
Element 5: 2
Element 6: -2
Element 7: -2
v_Numbers.COUNT = 6
v_Numbers.LAST = 7



-- Available online as trim.sql
DECLARE
  -- \7̗vfɏB
  v_Numbers NumTab := NumTab(-3, -2, -1, 0, 1, 2, 3);

  --\o͂郍[JvV[WB
  PROCEDURE Print(p_Table IN NumTab) IS
    v_Index INTEGER;
  BEGIN
    v_Index := p_Table.FIRST;
    WHILE v_Index <= p_Table.LAST LOOP
      DBMS_OUTPUT.PUT('Element ' || v_Index || ': ');
      DBMS_OUTPUT.PUT_LINE(p_Table(v_Index));
      v_Index := p_Table.NEXT(v_Index);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('COUNT = ' || p_Table.COUNT);            
    DBMS_OUTPUT.PUT_LINE('LAST = ' || p_Table.LAST);            
  END Print;

BEGIN
  DBMS_OUTPUT.PUT_LINE('At initialization, v_Numbers contains');
  Print(v_Numbers);

  -- vf6폜B
  v_Numbers.DELETE(6);
  DBMS_OUTPUT.PUT_LINE('After delete , v_Numbers contains');
  Print(v_Numbers);

  --Ō̗vf3폜Bŗvf23폜邪A
  -- ėvf1i͋́jX|bg폜B
  v_Numbers.TRIM(3);
  DBMS_OUTPUT.PUT_LINE('After trim, v_Numbers contains');  
  Print(v_Numbers);
END;



At initialization, v_Numbers contains
Element 1: -3
Element 2: -2
Element 3: -1
Element 4: 0
Element 5: 1
Element 6: 2
Element 7: 3
COUNT = 7
LAST = 7
After delete , v_Numbers contains
Element 1: -3
Element 2: -2
Element 3: -1
Element 4: 0
Element 5: 1
Element 7: 3
COUNT = 6
LAST = 7
After trim, v_Numbers contains
Element 1: -3
Element 2: -2
Element 3: -1
Element 4: 0
COUNT = 4
LAST = 4



-- Available online as delete.sql
DECLARE
  -- \10̗vfɏB
  v_Numbers NumTab := NumTab(10, 20, 30, 40, 50, 60, 70, 80, 
                             90, 100);

  -- \o͂郍[JvV[WB
  PROCEDURE Print(p_Table IN NumTab) IS
    v_Index INTEGER;
  BEGIN
    v_Index := p_Table.FIRST;
    WHILE v_Index <= p_Table.LAST LOOP
      DBMS_OUTPUT.PUT('Element ' || v_Index || ': ');
      DBMS_OUTPUT.PUT_LINE(p_Table(v_Index));
      v_Index := p_Table.NEXT(v_Index);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('COUNT = ' || p_Table.COUNT);
    DBMS_OUTPUT.PUT_LINE('LAST = ' || p_Table.LAST);
  END Print;
BEGIN
  DBMS_OUTPUT.PUT_LINE('At initialization, v_Numbers contains');
  Print(v_Numbers);

  -- vf6폜B
  DBMS_OUTPUT.PUT_LINE('After delete(6), v_Numbers contains');                v_Numbers.DELETE(6);
  Print(v_Numbers);

  -- vf7vf9폜B
  DBMS_OUTPUT.PUT_LINE('After delete(7,9), v_Numbers contains'); 
  v_Numbers.DELETE(7,9); 
  Print(v_Numbers);
END;



At initialization, v_Numbers contains
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Element 5: 50
Element 6: 60
Element 7: 70
Element 8: 80
Element 9: 90
Element 10: 100
COUNT = 10
LAST = 10
After delete(6), v_Numbers contains
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Element 5: 50
Element 7: 70
Element 8: 80
Element 9: 90
Element 10: 100
COUNT = 9
LAST = 10
After delete(7,9), v_Numbers contains
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Element 5: 50
Element 10: 100
COUNT = 6
LAST = 10



Chapter 13
SQL> VARIABLE v_Num NUMBER
SQL> variable v_Char char(3)
SQL> vaRIAbLe v_Varchar VarCHAR2(5)



SQL> EXECUTE Register(10006, 'CS', 102)



BEGIN Register(10006, 'CS', 102); END;



-- Available online as call_reg.sql
VARIABLE v_Count NUMBER

BEGIN
  Register(&student_id, 'CS', 102);
  SELECT COUNT(*)
    INTO :v_Count
    FROM registered_students
    WHERE department = 'CS'
    AND course = 102;
END;
/

PRINT v_Count



SQL> @call_reg



x: vV[W쐬܂ARpCG[܂B



EXEC SQL BEGIN DECLARE SECTION;



EXEC SQL END DECLARE SECTION;



/* Available online as call_reg.pc */
EXEC SQL BEGIN DECLARE SECTION;
  /* C̕ϐ̐錾 */
  VARCHAR v_Department[4]; /* [^VARCHAŔAPro*Cł
                              gpłȂ߁A.arrlen
                              Ƃ2̃tB[h
                              R[h^ɕϊB */
  int v_Course;            /* v_Course͐ */
  int v_StudentID;         /* v_StudentID */
EXEC SQL END DECLARE SECTION;

  /* zXgϐBł̓zXgϐɒl𒼐ڑĂ邾
     ł邪AzXgϐ̒l̓t@Cǂݍ񂾂A[U[ɓ͂
     肷邱ƂłBVARCHAR^ϐ̏ꍇ́AY镶.arr
     tB[hɃRs[A̒̕(̏ꍇ́A3).lentB[h
     ɑB */
  strcpy(v_Department.arr, "ECN");
  v_Department.len = 3;
  v_Course = 101;
  v_StudentID = 10006;

  /* PL/SQLubN̊JnBEXEC SQL EXECUTEEND-EXEC;
     ƂL[[hɒӁB̃vbŃAvRpĈ߂
     ̃L[[hɂċ؂ĂB */
  EXEC SQL EXECUTE
    BEGIN
       Register(:v_Department, :v_Course, :v_StudentID);
    END;
  END-EXEC; 



PLS-00201: ʎq: <O>͐錾Ă܂B



EXEC SQL EXECUTE 



END-EXEC;



/* Available online as part of indicator.pc */
EXEC SQL BEGIN DECLARE SECTION;
  char v_Grade;    /* v_Grade1 */
  short i_Grade;  /* Wϐshort(2oCg̐)Ƃ
                     錾Ă_ɒ */
EXEC SQL END DECLARE SECTION;

EXEC SQL EXECUTE
  BEGIN
    SELECT grade
      INTO :v_Grade INDICATOR :i_Grade
      FROM registered_students
      WHERE student_id = 10006
      AND department = 'ECN'
      AND course = 101;
  END;
END-EXEC;

  if (i_Grade != 0)
    printf("No grade recorded for this student\n");
  else
    printf("The grade recorded is %c\n", v_Grade); 



/* Available online as part of indicator.pc */
EXEC SQL EXECUTE
  BEGIN
    SELECT grade
      INTO :v_Grade:i_Grade
      FROM registered_students
      WHERE student_id = 10006
      AND department = 'ECN'
      AND course = 101;
  END;
END-EXEC;



/* Available online as error.pc */
EXEC SQL INCLUDE SQLCA; /* ̕ł́A\SQLCACN[hĂ 
                           ̍\̂̒̈ÃtB[h́AG[
                           ɎgpB */
EXEC SQL EXECUTE
  BEGIN
    RecordFullClasses;
  END;
END-EXEC;
/* sqlca.sqlcodeɂ́AɏIƃ[AُI
   YG[R[hi[BG[ꍇA
   sqlca.sqlerrm.sqlerrmcɂ̓G[bZ[W̃eLXgA
   sqlca.sqlerrm.sqlerrmlɂ͂̃bZ[Wi[B */
if (sqlca.sqlcode != 0) {
  printf("Error during execution of RecordFullClasses.\n");
  printf("%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
  }
else
  printf("Execution successful.\n"); 



SQLCHECK=SEMANTICS USERID=example/example 



char *plsql_block = 
  "BEGIN \
     Register(:v_StudentID, :v_Department, :v_Course); \
   END;";
int return_val;
Cda_Def cda;

return_val = oparse(&cda, plsql_block, -1, 1, 2);



/* Available online as oci.c */
/* Wwb_[t@COCĨwb_[CN[h */
#include <stdio.h>
#include <oratypes.h>
#include <ocidfn.h>
#include <ociapr.h>

/* ̕ŎgpLDA, HDA CDA錾 */
Lda_Def lda;
ub1 HDA[512];
Cda_Def cda;

/* ͂Ɏgpϐ錾 */
char v_Department[4] = "ECN";
int v_Course = 101;
int v_StudentID = 10006;

/* Register̃R[̃ubN܂܂Ă镶
   ׂĈP̕ɂ邽߂ɁALW^[
   obNXbVŒuĂ_ɒӁB
   vbN̍\vfƂĕKvł邽߁A
   ̃Z~RɓĂB */
char *plsqlBlock =
  "BEGIN \
       Register(:v_StudentID, :v_Department, :v_Course); \
   END;";

/* f[^x[Xɐڑ邽߂̃[U[ƃpX[h */
char *username = "example";
char *password = "example";  


/* G[񍐗p̊֐BoerhmsgpăG[Ŝ擾A
   ʂɏo͂B */
void print_error(Lda_Def *lda, Cda_Def *cda) {
  int v_ReturnChars;
  char v_Buffer[1000];

  v_ReturnChars = oerhms(lda, cda->rc, (text *) v_Buffer,
                         (sword) sizeof(v_Buffer));
  printf("Oracle error occurred!\n");
  printf("%s\n", v_Buffer);
}


main() {
  /* f[^x[Xւ̐ڑ */
  if (orlon(&lda, HDA, (text *) username, -1,
            (text *) password, -1, 0)) {
    print_error(&lda, &lda);
    exit(-1);
  }
  printf("Connected to Oracle\n");

  /* ɎgpJ[\I[v */
  if (oopen(&cda, &lda, (text *) 0, -1, -1,
            (text *) 0, -1)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* PL/SQLubN̉ */
  if (oparse(&cda, (text *) plsqlBlock,
             (sb4) -1, 1, (ub4) 2)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* ^Cv5STRINGgpāAw(department)oCh */
  if (obndrv(&cda, (text *) ":v_Department", -1,
             (ub1 *) v_Department, sizeof(v_Department),
             5, -1, (sb2 *) 0, 0, -1, -1)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* ^Cv3INTEGERgpāAw(course)oCh */
  if (obndrv(&cda, (text *) ":v_Course", -1,
            (ub1 *) &v_Course, sizeof(v_Course),
            3, -1, (sb2 *) 0, 0, -1, -1)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* ^Cv3INTEGERgpāAwIDoCh */
  if (obndrv(&cda, (text *) ":v_StudentID", -1,
             (ub1 *) &v_StudentID, sizeof(v_StudentID),
             3, -1, (sb2 *) 0, 0, -1, -1)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* ̎s */
  if (oexec(&cda)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* sʂR~bg */
  if (ocom(&lda)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* J[\N[Y */
  if (oclose(&cda)) {
    print_error(&lda, &cda);
    exit(-1);
  }

  /* f[^x[X̃OIt */
  if (ologof(&lda)) {
    print_error(&lda, &cda);
    exit(-1);
  }
} 



WRAP INAME=register.sql
WRAP INAME=register
WRAP INAME=register.sql ONAME=register.plb 



CREATE [OR REPLACE] PROCEDURE
CREATE [OR REPLACE] PACKAGE
CREATE [OR REPLACE] PACKAGE BODY
CREATE [OR REPLACE] FUNCTION 



CREATE OR REPLACE PROCEDURE Register(...) AS
  ...
BEGIN
  ...
END Register;



CREATE OR REPLACE PROCEDURE Register WRAPPED
  012ba779f...



CREATE OR REPLACE PROCEDURE CountStudents
  (p_Major IN students.major%TYPE,
   p_TotalNumber OUT NUMBER) AS
BEGIN
  SELECT COUNT(*)
    INTO p_TotalNumber
    FROM student
    WHERE major = p_Major;
END CountStudents;
/



PLS-00201:    ʎq: student͐錾Ă܂B



Chapter 14
-- Available online as avgrade1.sql
CREATE OR REPLACE FUNCTION AverageGrade (
/* w肳ꂽNX̕ϐт𒲂ׂBт́A\registered_students
   ̒AE1Ŋi[ĂB{t@NVAϐт
   1ŕԂBo^ĂwNXɂȂꍇ́AG[ʒm
   B */
  p_Department IN VARCHAR2,
  p_Course IN NUMBER) RETURN VARCHAR2 AS

  v_AverageGrade VARCHAR2(1);
  v_NumericGrade NUMBER;
  v_NumberStudents NUMBER;

  CURSOR c_Grades IS
    SELECT grade
      FROM registered_students
      WHERE department = p_Department
      AND course = p_Course;
BEGIN
  /* YNX̊w܂ׂKvBwȂꍇɂ́A
     G[ʒmKvB */
  SELECT COUNT(*)
    INTO v_NumberStudents
    FROM registered_students
    WHERE department = p_Department
      AND course = p_Course;

  IF v_NumberStudents = 0 THEN
    RAISE_APPLICATION_ERROR(-20001, 'No students registered for ' ||
      p_Department || ' ' || p_Course);
  END IF;

  /* т͕Ŋi[Ă邽߁AAVGt@NV𒼐ڎgp邱Ƃ͂łȂB
     ̂߁ADECODE֐gpĕ\̐т𐔒lɕϊĂA
     ςvZB */
  SELECT AVG(DECODE(grade, 'A', 5,
                           'B', 4,
                           'C', 3,
                           'D', 2,
                           'E', 1))
    INTO v_NumericGrade
    FROM registered_students
    WHERE department = p_Department
    AND course = p_Course;

  /* v_NumericGradeɂ́Aϐт1`5̐lƂĊi[ĂB
     x́A𕶎ɕϊKvBDECODEt@NV́A
     gpłBϊʂ́Ał͂ȂSELECTɂv_AverageGrade
     i[Ă_ɒӁBȂȂADECODEt@NV́ASQL̒ł
     gpłȂ߂łB */
  SELECT DECODE(ROUND(v_NumericGrade), 5, 'A',
                                       4, 'B',
                                       3, 'C',
                                       2, 'D',
                                       1, 'E')
    INTO v_AverageGrade
    FROM dual;

  RETURN v_AverageGrade;
END AverageGrade;



SQL> select * from registered_students;

STUDENT_ID DEP    COURSE G
---------- --- --------- -
     10000 CS        102 A
     10002 CS        102 B
     10003 CS        102 C
     10000 HIS       101 A
     10001 HIS       101 B
     10002 HIS       101 B
     10003 HIS       101 A
     10004 HIS       101 C
     10005 HIS       101 C
     10006 HIS       101 E
     10007 HIS       101 B
     10008 HIS       101 A
     10009 HIS       101 D
     10010 HIS       101 A
     10008 NUT       307 A
     10010 NUT       307 A
     10009 MUS       410 B
     10006 MUS       410 E

18 rows selected.



SQL> VARIABLE v_AveGrade VARCHAR2(1)
SQL> exec :v_AveGrade := AverageGrade('HIS', 101)

PL/SQL procedure successfully completed.

SQL> print v_AveGrade

V_AVEGRADE
-------------------------------
B

SQL> exec :v_AveGrade := AverageGrade('NUT', 307)

PL/SQL procedure successfully completed.

SQL> print v_AveGrade

V_AVEGRADE
-------------------------------
A

SQL> exec :v_AveGrade := AverageGrade('MUS', 410)

PL/SQL procedure successfully completed.

SQL> print v_AveGrade

V_AVEGRADE
-------------------------------
C

SQL> exec :v_AveGrade := AverageGrade('CS', 102)
begin :v_AveGrade := AverageGrade('CS', 102); end;

 *
s:1ŃG[܂B
ORA-20001: No students registered for CS 102
ORA-06512: "EXAMPLE.AVERAGEGRADE", s: 25



-- Available online as debug1.sql
CREATE OR REPLACE PACKAGE Debug AS
  /* Po[WDebugpbP[WB̃pbP[ẂA
     \debug_tableɑ}s邱Ƃɂē삷B
     o͌ʂɂ́ASQL*PlusŎ̕ɂAdebug_table
     猟邱ƁB
 SELECT debug_str FROM debug_table ORDER BY linecount; */

  /* Debug̃CvV[WAp_DescriptiońA
     p_ValueƘAAdebug_tableɑ}B */
  PROCEDURE Debug(p_Description IN VARCHAR2, p_Value IN VARCHAR2);
 
  /* Debug̓ZbgBReset́A{pbP[W߂
     CX^VF[gꂽƂɂɃR[B܂AV
     ZbV̂߂debug_table̓e폜ꍇA
     ResetR[邱ƁB */
  PROCEDURE Reset;
 END Debug;
/

CREATE OR REPLACE PACKAGE BODY Debug AS
  /* v_LineCount́Adebug_table̒̍sԂɕׂ邽߂ɎgpB */
  v_LineCount NUMBER;
 
  PROCEDURE Debug(p_Description IN VARCHAR2, p_Value IN VARCHAR2) IS
  BEGIN
    INSERT INTO debug_table (linecount, debug_str)
      VALUES (v_LineCount, p_Description || ': ' || p_Value);
    COMMIT;
    v_LineCount := v_LineCount + 1;
  END Debug;
 
  PROCEDURE Reset IS
  BEGIN
    v_LineCount := 1;
    DELETE FROM debug_table;
  END Reset;
 
BEGIN /* pbP[W̏R[h */
  Reset;
END Debug;



-- Available online as avgrade2.sql
CREATE OR REPLACE FUNCTION AverageGrade (
  p_Department IN VARCHAR2,
  p_Course IN NUMBER) RETURN VARCHAR2 AS

  v_AverageGrade VARCHAR2(1);
  v_NumericGrade NUMBER;
  v_NumberStudents NUMBER;

  CURSOR c_Grades IS
    SELECT grade
      FROM registered_students
      WHERE department = p_Department
      AND course = p_Course;
BEGIN
  Debug.Reset;
  Debug.Debug('p_Department', p_Department);
  Debug.Debug('p_Course', p_Course);

  /* YNX̊w܂ׂKvBwȂꍇɂ́A
     G[ʒmKvB */
  SELECT COUNT(*)
    INTO v_NumberStudents
    FROM registered_students
    WHERE department = p_Department
    AND course = p_Course;

  Debug.Debug('After select, v_NumberStudents', v_NumberStudents);
  IF v_NumberStudents = 0 THEN
    RAISE_APPLICATION_ERROR(-20001, 'No students registered for ' ||
      p_Department || ' ' || p_Course);
  END IF;

  SELECT AVG(DECODE(grade, 'A', 5,
                           'B', 4,
                           'C', 3,
                           'D', 2,
                           'E', 1))
    INTO v_NumericGrade
    FROM registered_students
    WHERE department = p_Department
      AND course = p_Course;

  SELECT DECODE(ROUND(v_NumericGrade), 5, 'A',
                                       4, 'B',
                                       3, 'C',
                                       2, 'D',
                                       1, 'E')
    INTO v_AverageGrade
    FROM dual;

  RETURN v_AverageGrade;
END AverageGrade;



SQL> EXEC :v_AveGrade := AverageGrade('CS', 102)
begin :v_AveGrade := AverageGrade('CS', 102); end;

 *
s:1ŃG[܂B
ORA-20001: No students registered for CS 102
ORA-06512: "EXAMPLE.AVERAGEGRADE", s: 25
ORA-06512: s: 1


SQL> SELECT debug_str FROM debug_table ORDER BY linecount;

DEBUG_STR
----------------------------------------------------------
p_Department: CS
p_Course: 102
After select, v_NumberStudents: 0



SELECT COUNT(*)
    INTO v_NumberStudents
    FROM registered_students
    WHERE department = p_Department
    AND course = p_Course;



-- Available online as avgrade3.sql
CREATE OR REPLACE FUNCTION AverageGrade
  ...
BEGIN
  Debug.Reset;
  Debug.Debug('p_Department', '''' || p_Department || '''');
  Debug.Debug('p_Course', '''' || p_Course || '''');

  /* YNX̊w܂ׂKvBwȂꍇ́A
     G[ʒmKvB */
  SELECT COUNT(*)
    INTO v_NumberStudents
    FROM registered_students
    WHERE department = p_Department
      AND course = p_Course;

  Debug.Debug('After select, v_NumberStudents', v_NumberStudents);
  ...



SQL> exec :v_AveGrade := AverageGrade('CS', 102)
begin :v_AveGrade := AverageGrade('CS', 102); end;

 *
s:1ŃG[܂B
ORA-20001: No students registered for CS 102
ORA-06512: "EXAMPLE.AVERAGEGRADE", s: 25
ORA-06512: s: 1


SQL> SELECT debug_str FROM debug_table ORDER BY linecount;

DEBUG_STR
----------------------------------------------------------
p_Department: 'CS'
p_Course: '102'
After select, v_NumberStudents: 0



CREATE OR REPLACE FUNCTION AverageGrade (
  p_Department IN CHAR,
  p_Course IN NUMBER) RETURN VARCHAR2 AS
  ...
BEGIN
  ...
END AverageGrade;



SQL> exec :v_AveGrade := AverageGrade('CS', 102)

PL/SQL procedure successfully completed.

SQL> print v_AveGrade

V_AVEGRADE
-------------------------------
B 



-- Available online as avgrade4.sql
CREATE OR REPLACE FUNCTION AverageGrade (
  p_Department IN registered_students.department%TYPE,
  p_Course IN registered_students.course%TYPE) RETURN CHAR AS
 
  v_AverageGrade CHAR(1);
  v_NumericGrade NUMBER;
  v_NumberStudents NUMBER;
...
BEGIN
  ...
END AverageGrade;



-- Available online as output.sql
DECLARE
  /* PUT_LINE GET_LINE̎gp */
  v_Data      DBMS_OUTPUT.CHARARR;
  v_NumLines  NUMBER;
BEGIN
  -- obt@܂LɂB
  DBMS_OUTPUT.ENABLE(1000000);

  -- GET_LINESŉo悤ɁApbt@ɉf[^
  -- i[ĂB
  DBMS_OUTPUT.PUT_LINE('Line One');
  DBMS_OUTPUT.PUT_LINE('Line Two');
  DBMS_OUTPUT.PUT_LINE('Line Three');

  -- os̍őlݒ肷B
  v_NumLines := 3;

  /* obt@̓eoBv_DatáADBMS_OUTPUT.GET_LINES
     ̐錾ɍv悤ɁBDBMS_OUTPUT.CHARARRƂ^Ő錾
     _ɒӂ邱ƁB */
  DBMS_OUTPUT.GET_LINES(v_Data, v_NumLines);

  /* Ԃꂽobt@̓eA[vŏAtemp_table
     }B */
  FOR v_Counter IN 1..v_NumLines LOOP
    INSERT INTO temp_table (char_col)
      VALUES (v_Data(v_Counter));
  END LOOP;
END;



ORA-20000: ORU-10027: buffer overflow,
           limit of <buf_limit> bytes.



ORA-20000: ORU-10028: line length overflow,
           limit of 255 bytes per line.



-- Available online as cntcred1.sql
CREATE OR REPLACE FUNCTION CountCredits (
  /* p_StudentIDŎw肳ꂽw݂̌̎擾ςݒPʐԂB */
  p_StudentID IN students.ID%TYPE)
  RETURN NUMBER AS

  v_TotalCredits NUMBER;  -- Pʐ
  v_CourseCredits NUMBER; -- P̉Ȗڂ̒Pʐ
  CURSOR c_RegisteredCourses IS
    SELECT department, course
      FROM registered_students
      WHERE student_id = p_StudentID;
BEGIN
  FOR v_CourseRec IN c_RegisteredCourses LOOP
    -- YȖڂ̒Pʐ𒲂ׂ
    SELECT num_credits
      INTO v_CourseCredits
      FROM classes
      WHERE department = v_CourseRec.department
      AND course = v_CourseRec.course;

    -- ܂ł̓vɑB
    v_TotalCredits := v_TotalCredits + v_CourseCredits;
  END LOOP;

  RETURN v_TotalCredits;
END CountCredits;



SQL> SELECT ID, CountCredits(ID) "Total Credits"
  2    FROM students;

       ID Total Credits
--------- -------------
    10000
    10001
    10002
    10003
    10004
    10005
    10006
    10007
    10008
    10009
    10010

11 rows selected.



-- Available online as debug2.sql
CREATE OR REPLACE PACKAGE Debug AS
  PROCEDURE Debug(p_Description IN VARCHAR2,
                  p_Value IN VARCHAR2); IS

  BEGIN
    DBMS_OUTPUT.PUT_LINE(p_Description || ': ' || p_Value);
  END Debug;

  PROCEDURE Reset IS
  BEGIN
       /* obt@A񖳌ɂĂAőTCYw
          ėLɂBDISABLEsƓobt@폜邽߁A
          ResetR[邽тɐVobt@擾łB */
    DBMS_OUTPUT.DISABLE;
    DBMS_OUTPUT.ENABLE(1000000);
  END Reset;
BEGIN /* pbP[W̏R[h */
  Reset;
END Debug;



-- Available online as cntcred2.sql
CREATE OR REPLACE FUNCTION CountCredits (
  /* p_StudentIDŎw肳ꂽw݂̌̎擾ςݒPʐԂB */
  p_StudentID IN students.ID%TYPE)
  RETURN NUMBER AS

  v_TotalCredits NUMBER;  -- Pʐ
  v_CourseCredits NUMBER; -- P̉Ȗڂ̒Pʐ
  CURSOR c_RegisteredCourses IS
    SELECT department, course
      FROM registered_students
      WHERE student_id = p_StudentID;
BEGIN
  Debug.Reset;
  FOR v_CourseRec IN c_RegisteredCourses LOOP
    -- YȖڂ̒Pʐ𒲂ׂB
    SELECT num_credits
      INTO v_CourseCredits
      FROM classes
      WHERE department = v_CourseRec.department
      AND course = v_CourseRec.course;

    Debug.Debug('Inside loop, v_CourseCredits', v_CourseCredits);
    -- ܂ł̑vɑ
    v_TotalCredits := v_TotalCredits + v_CourseCredits;
  END LOOP;

  Debug.Debug('After loop, returning', v_TotalCredits);
  RETURN v_TotalCredits;
END CountCredits;



SQL> VARIABLE v_Total NUMBER
SQL> SET SERVEROUTPUT ON
SQL> exec :v_Total := CountCredits(10006);
Inside loop, v_CourseCredits: 4
Inside loop, v_CourseCredits: 3
After loop, returning:

PL/SQL procedure successfully completed.

SQL> print v_Total

  V_TOTAL
---------


SQL>



CREATE OR REPLACE FUNCTION CountCredits (
  /* p_StudentIDŎw肳ꂽw݂̌̎擾ςݒPʐԂB */
  p_StudentID IN students.ID%TYPE)
  RETURN NUMBER AS

  v_TotalCredits NUMBER;  -- Pʐ
  v_CourseCredits NUMBER; -- P̉Ȗڂ̒Pʐ
  CURSOR c_RegisteredCourses IS
    SELECT department, course
      FROM registered_students
      WHERE student_id = p_StudentID;
BEGIN
  Debug.Reset;
  Debug.Debug('Before loop, v_TotalCredits', v_TotalCredits);
  FOR v_CourseRec IN c_RegisteredCourses LOOP
    -- YȖڂ̒Pʐ𒲂ׂB
    SELECT num_credits
      INTO v_CourseCredits
      FROM classes
      WHERE department = v_CourseRec.department
      AND course = v_CourseRec.course;

    Debug.Debug('Inside loop, v_CourseCredits', v_CourseCredits);
    -- ܂ł̑vɑB
    v_TotalCredits := v_TotalCredits + v_CourseCredits;
    Debug.Debug('Inside loop, v_TotalCredits', v_TotalCredits);
  END LOOP;

  Debug.Debug('After loop, returning', v_TotalCredits);
  RETURN v_TotalCredits;
END CountCredits;



SQL> exec :v_Total := CountCredits(10006);
Before loop, v_TotalCredits:
Inside loop, v_CourseCredits: 4
Inside loop, v_TotalCredits:
Inside loop, v_CourseCredits: 3
Inside loop, v_TotalCredits:
After loop, returning:

PL/SQL procedure successfully completed.



-- Available online as cntcred4.sql
CREATE OR REPLACE FUNCTION CountCredits (
  /* p_StudentIDŎw肳ꂽw݂̌̎擾ςݒPʐԂB */
  p_StudentID IN students.ID%TYPE)
  RETURN NUMBER AS

  v_TotalCredits NUMBER := 0;  -- Pʐ
  v_CourseCredits NUMBER;      -- P̉Ȗڂ̒Pʐ
  CURSOR c_RegisteredCourses IS
    SELECT department, course
      FROM registered_students
      WHERE student_id = p_StudentID;
BEGIN
  FOR v_CourseRec IN c_RegisteredCourses LOOP
    -- YȖڂ̒Pʐ𒲂ׂB
    SELECT num_credits
      INTO v_CourseCredits
      FROM classes
      WHERE department = v_CourseRec.department
      AND course = v_CourseRec.course;

    -- ܂ł̑vɑB
    v_TotalCredits := v_TotalCredits + v_CourseCredits;
  END LOOP;

  RETURN v_TotalCredits;
END CountCredits;



SQL> exec :v_Total := CountCredits(10006);

PL/SQL procedure successfully completed.

SQL> print v_Total

  V_TOTAL
---------
        7

SQL> SELECT ID, CountCredits(ID) "Total Credits"
  2    FROM students;

       ID Total Credits
--------- -------------
    10000             8
    10001             4
    10002             8
    10003             8
    10004             4
    10005             4
    10006             7
    10007             4
    10008             8
    10009             7
    10010             8



-- Available online as crloop1.sql
CREATE OR REPLACE PROCEDURE CreditLoop AS
  /* temp_tableɁAwIDԍƌ݂̒Pʐ}B */
  v_StudentID students.ID%TYPE;
  v_Credits   students.current_credits%TYPE;
  CURSOR c_Students IS
    SELECT ID
      FROM students;
BEGIN
  OPEN c_Students;
  LOOP
    FETCH c_Students INTO v_StudentID;
    v_Credits := CountCredits(v_StudentID);
    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_StudentID, 'Credits = ' || TO_CHAR(v_Credits));
    EXIT WHEN c_Students%NOTFOUND;
  END LOOP;
  CLOSE c_Students;
END CreditLoop;



SQL> exec CreditLoop;
PL/SQL procedure successfully completed.
SQL> SELECT * FROM temp_table
  2    ORDER BY num_col;

  NUM_COL CHAR_COL
--------- --------------------
    10000 Credits = 8
    10001 Credits = 4
    10002 Credits = 8
    10003 Credits = 8
    10004 Credits = 4
    10005 Credits = 4
    10006 Credits = 7
    10007 Credits = 4
    10008 Credits = 8
    10009 Credits = 7
    10010 Credits = 8
    10010 Credits = 8

12 rows selected.



CreditLoop;



SQL> exec CreditLoop
PL/SQL procedure successfully completed.

SQL> SELECT * FROM temp_table
  2    ORDER BY num_col;

  NUM_COL CHAR_COL
--------- -------------------------------
    10000 Credits = 8
    10001 Credits = 4
    10002 Credits = 8
    10003 Credits = 8
    10004 Credits = 4
    10005 Credits = 4
    10006 Credits = 7
    10007 Credits = 4
    10008 Credits = 8
    10009 Credits = 7
    10010 Credits = 8

11 rows selected.



CREATE OR REPLACE PROCEDURE PrintTranscript(
  /* w肳ꂽw̐яؖo͂Bяؖ́A
     wݓo^ĂÃNXƂ̊eNX
     т\B܂Aя̖ؖɂ́A
     ̊wGPAo͂B */
  p_StudentID IN students.ID%TYPE) AS

  v_StudentGPA  NUMBER;  -- YwGPAt.
  CURSOR CurrentClasses IS
    SELECT *
      FROM registered_students
      WHERE student_id = p_StudentID;
BEGIN
  -- UȂǁAYwɊւwb_[o͂B

  FOR v_ClassesRecord IN CurrentClasses LOOP
    -- eNXɊւo͂B
    NULL;
  END LOOP;

  -- GPAvZB
  CalculateGPA(p_StudentID, v_StudentGPA);

  -- GPAo͂B
END PrintTranscript;



CREATE OR REPLACE PROCEDURE CalculateGPA(
  /* p_StudentIDŎw肳ꂽwGPAp_GPAɕԂ */
  p_StudentID IN students.ID%TYPE,
  p_GPA OUT NUMBER) AS
BEGIN
  NULL;
END CalculateGPA;



Chapter 15
DECLARE
  v_Department classes.department%TYPE := 'ECN';
  v_NumCredits classes.num_credits%TYPE := 5;
BEGIN
  UPDATE classes
    SET num_credits = v_NumCredits
    WHERE department = v_Department;
END;



DECLARE
  v_SQLString   VARCHAR2(100);
  v_SetClause   VARCHAR2(100);
  v_WhereClause VARCHAR2(100);
BEGIN
  v_SetClause := 'SET num_credits = :num_credits WHERE ';
  v_WhereClause := 'department = :department';
  v_SQLString := 'UPDATE classes ' || v_SetClause ||
  v_WhereClause;
  DoIt(v_SQLString);
END;



-- Available online as recrtemp.sql
CREATE OR REPLACE PROCEDURE RecreateTempTable (
  /* temp_tablex폜Aēx쐬B\̐́A 
     p_Descriptionœn̂ƂA\̖ǑCREATE TABLE̓e
     Lq邱ƁBƂ΁Â悤ȃR[͗LłB

     RecreateTempTable('(num_col NUMBER, char_col VARCHAR2(2000))');
  */
  p_Description IN VARCHAR2) IS

  v_Cursor        NUMBER;
  v_CreateString  VARCHAR2(100);
  v_DropString    VARCHAR2(100);
  v_NumRows       INTEGER; 
BEGIN
  /* ɎgpJ[\I[vB */
  v_Cursor := DBMS_SQL.OPEN_CURSOR;

  /* ŏɕ\폜B */
  v_DropString := 'DROP TABLE temp_table';

  /* 'DROP TABLE'R}h͂ĎsBY\܂
     ĂȂꍇ́AORA-942ƂG[oB */
  BEGIN
    -- DBMS_SQL.V7́ApbP[Wwb_[Œ`Ă萔łB
    DBMS_SQL.PARSE(v_Cursor, v_DropString, DBMS_SQL.V7);
    v_NumRows := DBMS_SQL.EXECUTE(v_Cursor);
  EXCEPTION
    WHEN OTHERS THEN
      IF SQLCODE != -942 THEN
        RAISE;
      END IF;
  END;
  /* ŁAtemp_tableēx쐬B܂ACREATE TABLE̕쐬
     ĂẢ͂ƎssKvB */
  v_CreateString := 'CREATE TABLE temp_table ' || p_Description;
  DBMS_SQL.PARSE(v_Cursor, v_CreateString, DBMS_SQL.V7);
  v_NumRows := DBMS_SQL.EXECUTE(v_Cursor);

  /* ÎŁAJ[\N[YB */
  DBMS_SQL.CLOSE_CURSOR(v_Cursor);
EXCEPTION
  WHEN OTHERS THEN
    /* ܂J[\N[YĂAG[ēxʒmA
       Oɓ`dB */
    DBMS_SQL.CLOSE_CURSOR(v_Cursor);
    RAISE;
END RecreateTempTable;



INSERT INTO temp_table (num_col, char_col)
  VALUES (:number_value, :char_value);



DBMS_SQL.BIND_VARIABLE(v_CursorID, ':number_value', -7);
DBMS_SQL.BIND_VARIABLE(v_CursorID, ':char_value', 'Hello');



-- Available online as updclass.sql
CREATE OR REPLACE PROCEDURE UpdateClasses(
  /* DBMS_SQLgăNX\XVBw肳ꂽw̑SNX̒PʐA
     w肳ꂽPʐɃZbgB*/
  p_Department  IN classes.department%TYPE,
  p_NewCredits  IN classes.num_credits%TYPE,
  p_RowsUpdated OUT INTEGER) AS

  v_CursorID   INTEGER;
  v_UpdateStmt VARCHAR2(100);
BEGIN
  -- ɎgpJ[\I[vB
  v_CursorID := DBMS_SQL.OPEN_CURSOR;

  -- SQL肷B
  v_UpdateStmt :=
    'UPDATE classes
       SET num_credits = :nc
       WHERE department = :dept';

  -- ͂B
  DBMS_SQL.PARSE(v_CursorID, v_UpdateStmt, DBMS_SQL.V7);

  -- p_NewCreditsv[Xz_:ncɃoChB
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':nc', p_NewCredits);

  -- p_Departmentv[Xz_:deptɃoChB
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':dept', p_Department);

  -- sB
  p_RowsUpdated := DBMS_SQL.EXECUTE(v_CursorID);

  -- J[\N[YB
  DBMS_SQL.CLOSE_CURSOR(v_CursorID);
EXCEPTION
  WHEN OTHERS THEN
    -- J[\N[YAG[ēxʒmB
    DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    RAISE;
END UpdateClasses;



SQL> VARIABLE v_RowsUpdated NUMBER
SQL> exec UpdateClasses('MUS', 5, :v_RowsUpdated)

PL/SQL procedure successfully completed.

SQL> print v_RowsUpdated

V_ROWSUPDATED
-------------
            1



-- Available online as recrtmp2.sql
CREATE OR REPLACE PROCEDURE RecreateTempTable (
  /* temp_tablex폜Aēx쐬B\̐́Ap_Description
     n̂ƂA\̖ǑCREATE TABLE̓eLq邱ƁBƂ΁A
     ̂悤ȃR[͗LłB
 
     RecreateTempTable('(num_col NUMBER, char_col VARCHAR2(2000))');
 */
  p_Description IN VARCHAR2) IS

  v_Cursor        NUMBER;
  v_CreateString  VARCHAR2(100);
  v_DropString    VARCHAR2(100);
BEGIN
  /* ɎgpJ[\I[vB */
  v_Cursor := DBMS_SQL.OPEN_CURSOR;
 
  /* ŏɕ\폜B */
  v_DropString := 'DROP TABLE temp_table';
 
  /* 'DROP TABLE'R}h͂ĎsBY\܂݂ĂȂꍇ
     ORA-942 ƂG[oB*/
  BEGIN
    -- DBMS_SQL.V7́ApbP[Wwb_[Œ`Ă萔łB
    DBMS_SQL.PARSE(v_Cursor, v_DropString, DBMS_SQL.V7);
  EXCEPTION
    WHEN OTHERS THEN
      IF SQLCODE != -942 THEN
        RAISE;
      END IF;
  END; 
  /* temp_tableēx쐬B܂CREATE TABLE̕쐬ĂA
     ̉͂ƎssKvB */
  v_CreateString := 'CREATE TABLE temp_table ' || p_Description;
  DBMS_SQL.PARSE(v_Cursor, v_CreateString, DBMS_SQL.V7);
 
  /* ÎŁAJ[\N[YB */
  DBMS_SQL.CLOSE_CURSOR(v_Cursor);
EXCEPTION
  WHEN OTHERS THEN
    /* ܂J[\N[YĂAG[ēxʒmA
       Oɓ`dB*/
    DBMS_SQL.CLOSE_CURSOR(v_Cursor);
    RAISE;
END RecreateTempTable;



SELECT * FROM students

SELECT COUNT(*) "Number of Students", department || course
  FROM registered_students
  WHERE department IN (:d1, :d2)
  GROUP BY department || course

SELECT FullName(ID), ID
  FROM students
  WHERE ID = :student_id



SELECT first_name, last_name, num_credits
  FROM students 



DECLARE
  v_FirstName  students.first_name%TYPE,
  v_LastName   students.last_name%TYPE,
  v_NumCredits students.num_credits%TYPE,
  v_CursorID   INTEGER;
BEGIN
  ...
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 1, v_FirstName);
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 2, v_LastName);
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 3, v_NumCredits);
  ...
END;



-- Available online as dquery.sql
CREATE OR REPLACE PROCEDURE DynamicQuery (
  /* DBMS_SQLgpĕ\studentsɖ⍇sAʂtemp_table
     i[Bw肳ꂽUi2܂Łj̊wɊւāAOAA
     U}B */
  p_Major1 IN students.major%TYPE DEFAULT NULL,
  p_Major2 IN students.major%TYPE DEFAULT NULL) AS

  v_CursorID   INTEGER;
  v_SelectStmt VARCHAR2(500);
  v_FirstName  students.first_name%TYPE;
  v_LastName   students.last_name%TYPE;
  v_Major      students.major%TYPE;
  v_Dummy      INTEGER;

BEGIN
  -- ɎgpJ[\I[vB
  v_CursorID := DBMS_SQL.OPEN_CURSOR;

  -- ⍇̕쐬B
  v_SelectStmt := 'SELECT first_name, last_name, major
                     FROM students
                     WHERE major IN (:m1, :m2)
                     ORDER BY major, last_name';

  -- ⍇͂B
  DBMS_SQL.PARSE(v_CursorID, v_SelectStmt, DBMS_SQL.V7);

  -- ͕ϐoChB
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':m1', p_Major1);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':m2', p_Major2);

  -- o͕ϐ`B
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 1, v_FirstName, 20);
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 2, v_LastName, 20);
  DBMS_SQL.DEFINE_COLUMN(v_CursorID, 3, v_Major, 30);

  -- sB߂l͉łĂ܂ȂA
  -- ߂lp̕ϐ錾KvB
  v_Dummy := DBMS_SQL.EXECUTE(v_CursorID);

  -- ĹAtFb`[v
  LOOP
    -- A̍sobt@ɎoA
    -- [v̏I`FbNB
    IF DBMS_SQL.FETCH_ROWS(v_CursorID) = 0 THEN
      EXIT;
    END IF;

    -- A̍sobt@PL/SQLϐɃtFb`B
    DBMS_SQL.COLUMN_VALUE(v_CursorID, 1, v_FirstName);
    DBMS_SQL.COLUMN_VALUE(v_CursorID, 2, v_LastName);
    DBMS_SQL.COLUMN_VALUE(v_CursorID, 3, v_Major);

    -- tFb`f[^Atemp_tableɑ}B
    INSERT INTO temp_table (char_col)
      VALUES (v_FirstName || ' ' || v_LastName || ' is a ' ||
              v_Major || ' major.');
  END LOOP;

  -- J[\N[YB
  DBMS_SQL.CLOSE_CURSOR(v_CursorID);

  -- sʂR~bgB
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    -- J[\N[YAG[ēxʒmB
    DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    RAISE;
END DynamicQuery;



SQL> exec DynamicQuery('History', 'Computer Science')
PL/SQL procedure successfully completed.

SQL> SELECT char_col FROM temp_table;

CHAR_COL
------------------------------------------
Joanne Junebug is a Computer Science major.
Scott Smith is a Computer Science major.
Margaret Mason is a History major.
Patrick Poll is a History major.
Timothy Taller is a History major.



BEGIN :placeholder := 7; END;

DECLARE
  v_Numeric   NUMBER := :p1;
  v_Character VARCHAR2(50) := :p2;
BEGIN
  INSERT INTO temp_table VALUES (v_Numeric, v_Character);
END;

BEGIN
  SELECT first_name, last_name
    INTO :first_name, :last_name
    FROM students
    WHERE ID = :ID;
END;



-- Available online as dynPLSQL.sql
CREATE OR REPLACE PROCEDURE DynamicPLSQL (
  /* PL/SQLubN𓮓IɎsBPL/SQLubNł́A
     studentsɑ΂đIsA͗p̃v[Xz_Ƃ
     p_StudentIDgpB */
  p_StudentID IN students.ID%TYPE) IS

  v_CursorID  INTEGER;
  v_BlockStr  VARCHAR2(500);
  v_FirstName students.first_name%TYPE;
  v_LastName  students.last_name%TYPE;
  v_Dummy     INTEGER;

BEGIN
  -- ŎgpJ[\I[vB
  v_CursorID := DBMS_SQL.OPEN_CURSOR;

  -- PL/SQLubN܂ޕ쐬B
  -- ̒̕ŁA:first_name:last_nameƂ
  -- v[Xz_͏o͕ϐA:ID͓͕ϐłB
  v_BlockStr := 
    'BEGIN
       SELECT first_name, last_name
         INTO :first_name, :last_name
         FROM students
         WHERE ID = :ID;
     END;';

  -- ͂B
  DBMS_SQL.PARSE(v_CursorID, v_BlockStr, DBMS_SQL.V7);

  -- v[Xz_ϐɃoChB̏́A͕ϐ
  -- o͕ϐ̗Ɏs_ɒӂ邱ƁB:first_name
  -- :last_nameł́Aő咷nB
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':first_name', v_FirstName, 30);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':last_name', v_LastName, 30);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':ID', p_StudentID);

  -- sB߂l͉łĂ܂Ȃ
  -- ߂lp̕ϐ錾KvB
  v_Dummy := DBMS_SQL.EXECUTE(v_CursorID);

  -- o͕ϐ̒ltFb`B
  DBMS_SQL.VARIABLE_VALUE(v_CursorID, ':first_name', v_FirstName);
  DBMS_SQL.VARIABLE_VALUE(v_CursorID, ':last_name', v_LastName);

  -- tFb`ltemp_tableɑ}B
  INSERT INTO temp_table (num_col, char_col)
    VALUES (p_StudentID, v_FirstName || ' ' || v_LastName);

  -- J[\N[YB
  DBMS_SQL.CLOSE_CURSOR(v_CursorID);

  -- sʂR~bgB
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    -- J[\N[YAG[ēxʒmB
    DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    RAISE;
END DynamicPLSQL;



SQL> exec DynamicPLSQL(10010)
PL/SQL procedure successfully completed.

SQL> exec DynamicPLSQL(10003)
PL/SQL procedure successfully completed.

SQL> SELECT * FROM temp_table;

  NUM_COL CHAR_COL
--------- ------------------
    10010 Rita Razmataz
    10003 Manish Murgratroid



  -- ϐɃv[Xz_oChB͕ϐƏo͕ϐ̗ɑ΂
  -- sƂɒӂBv_FirstNamev_LastNameɍő咷nȂB
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':first_name', v_FirstName);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':last_name', v_LastName);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':ID', p_StudentID);



SQL> exec DynamicPLSQL(10010)
begin DynamicPLSQL(10010); end;

*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "EXAMPLE.DYNAMICPLSQL", line 51
ORA-06512: at line 1



  -- ϐɃv[Xz_oChB͕ϐƏo͕ϐ̗ɑ΂
  -- sƂɒӂB܂2̕ϐ̍ő咷ɏB
  v_FirstName := '12345678901234567890';
  v_LastName := '12345678901234567890';
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':first_name', v_FirstName);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':last_name', v_LastName);
  DBMS_SQL.BIND_VARIABLE(v_CursorID, ':ID', p_StudentID);



-- Available online as execany.sql
CREATE OR REPLACE PACKAGE ExecuteAny AS 
  -- XgAhvV[W܂̓XgAht@NV̔ėpp[^
  TYPE t_Parameter IS RECORD (
    actual_type   VARCHAR2(8),  -- 'NUMBER', 'VARCHAR2', 'DATE','CHAR'
								   -- ̂ꂩ1
    actual_length INTEGER,
    name          VARCHAR2(50),
    num_param     NUMBER,
    vchar_param   VARCHAR2(500),
    char_param    CHAR(500),
    date_param    DATE);

  -- ėpp[^Xg
  TYPE t_ParameterList IS TABLE OF t_Parameter
    INDEX BY BINARY_INTEGER;

  -- CӃvV[WsBp_ParameterŝׂĂINp[^ɁAȂƂ
  -- _paramtB[hactual_typetB[h͂ĂAׂĂOUTp[^
  -- actual_typetB[hړĂKvB
  -- nametB[h͏o͎ɈړB
  PROCEDURE RunProc(p_NumParams IN NUMBER,
                    p_ProcName IN VARCHAR2,
                    p_Parameters IN OUT t_ParameterList);

  -- p_ProcNameɂė^vV[WɂĂ̋Lqf[^\ɈړB 
  -- p_PrintTRUEł΁ȀDBMS_OUTPUTgpďo͂B
 PROCEDURE DescribeProc(p_ProcName IN VARCHAR2,
                         p_Print IN BOOLEAN);

  -- DBMS_OUTPUTgpāAp[^p_Parametersɕ\B
  PROCEDURE Printparams(p_Parameters IN t_ParameterList,
                        p_NumParams IN NUMBER);
END ExecuteAny; 

CREATE OR REPLACE PACKAGE BODY ExecuteAny AS 
  -- DBMS_DESCRIBE.DESCRIBE_PROCEDUREϐ
  v_Overload     DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Position     DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Level        DBMS_DESCRIBE.NUMBER_TABLE; 
  v_ArgumentName DBMS_DESCRIBE.VARCHAR2_TABLE; 
  v_Datatype     DBMS_DESCRIBE.NUMBER_TABLE; 
  v_DefaultValue DBMS_DESCRIBE.NUMBER_TABLE; 
  v_InOut        DBMS_DESCRIBE.NUMBER_TABLE;
  v_Length       DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Precision    DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Scale        DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Radix        DBMS_DESCRIBE.NUMBER_TABLE; 
  v_Spare        DBMS_DESCRIBE.NUMBER_TABLE; 

  -- f[^^R[h𕶎ɕϊ郍[Jt@NV
  FUNCTION ConvertDatatype(p_Code IN NUMBER)
    RETURN VARCHAR2 IS
    v_Output VARCHAR2(20);
  BEGIN
    SELECT DECODE(p_Code, 0, ' ',
                          1, 'VARCHAR2',
                          2, 'NUMBER',
                          3, 'BINARY_INTEGER',
                          8, 'LONG',
                          11, 'ROWID',
                          12, 'DATE',
                          23, 'RAW',
                          24, 'LONG RAW',
                          96, 'CHAR',
                          106, 'MLSLABEL',
                          250, 'RECORD',
                          251, 'TABLE',
                          252, 'BOOLEAN')
    INTO v_Output
    FROM dual;

    RETURN v_Output;
  END ConvertDatatype;

  -- p[^[h𕶎ɕϊ郍[Jt@NV
  FUNCTION ConvertMode(p_Code IN NUMBER)
    RETURN VARCHAR2 IS
    v_Output VARCHAR2(10);
  BEGIN
    SELECT DECODE(p_Code, 0, 'IN',
                          1, 'IN OUT',
                          2, 'OUT')
      INTO v_Output
      FROM dual;

    RETURN v_Output;
  END ConvertMode;

  PROCEDURE DescribeProc(p_ProcName IN VARCHAR2,
                         p_Print IN BOOLEAN) IS
    v_ArgCounter NUMBER := 1;
  BEGIN
    -- ܂DESCRIBE_PROCEDURER[āAvV[WɂĂ̓ϐړB
    DBMS_DESCRIBE.DESCRIBE_PROCEDURE( 
      p_ProcName, 
      null, 
      null, 
      v_Overload, 
      v_Position, 
      v_Level, 
      v_ArgumentName, 
      v_Datatype, 
      v_DefaultValue, 
      v_InOut, 
      v_Length, 
      v_Precision, 
      v_Scale, 
      v_Radix, 
      v_Spare);  

    IF NOT p_Print THEN
      RETURN;
    END IF;

    -- ^Cgo͂B
    DBMS_OUTPUT.PUT_LINE('Description of ' || p_ProcName || ':');
    DBMS_OUTPUT.PUT('Overload Position Argument Name Level ');
    DBMS_OUTPUT.PUT('Datatype        Mode   Length Precision Scale');
    DBMS_OUTPUT.NEW_LINE;
    DBMS_OUTPUT.PUT('-------- -------- ------------- ----- 
    DBMS_OUTPUT.PUT('--------------- ------ ------ --------- -----');
    DBMS_OUTPUT.NEW_LINE;
  
    -- p[^ɂĂ̏o͂B
    LOOP
      BEGIN
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Overload(v_ArgCounter)), 9));
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Position(v_ArgCounter)), 9));
        DBMS_OUTPUT.PUT(RPAD(v_ArgumentName(v_ArgCounter), 14));
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Level(v_ArgCounter)), 6));
        DBMS_OUTPUT.PUT(RPAD(ConvertDatatype(v_Datatype
                                            (v_ArgCounter)), 15));
        DBMS_OUTPUT.PUT(RPAD(ConvertMode(v_InOut(v_ArgCounter)), 7));
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Length(v_ArgCounter)), 7));
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Precision(v_ArgCounter)), 10));
        DBMS_OUTPUT.PUT(RPAD(TO_CHAR(v_Scale(v_ArgCounter)), 5));
        DBMS_OUTPUT.NEW_LINE;
        v_ArgCounter := v_ArgCounter + 1;
      EXCEPTION
        WHEN NO_DATA_FOUND THEN
          EXIT;
      END;
    END LOOP;

  END DescribeProc;

  PROCEDURE RunProc(p_NumParams IN NUMBER,
                    p_ProcName IN VARCHAR2,
                    p_Parameters IN OUT t_ParameterList) IS

    -- DBMS_SQLϐ
    v_Cursor  NUMBER; 
    v_NumRows NUMBER; 

    v_ProcCall VARCHAR2(500);
    v_FirstParam BOOLEAN := TRUE;
  BEGIN 
    -- ܂vV[WLqB
    DescribeProc(p_ProcName, TRUE);

    -- ŃvV[WR[쐬KvB́A'BEGIN
    -- <procedure_name>(:p1, :p2, ...) ; END'ō\B
    v_ProcCall := 'BEGIN ' || p_ProcName || '(';

    FOR v_Counter IN 1..p_NumParams LOOP
      IF v_FirstParam THEN
        v_ProcCall := v_ProcCall || ':' || v_ArgumentName(v_Counter);
        v_FirstParam := FALSE;
      ELSE
        v_ProcCall := v_ProcCall || ', :' || v_ArgumentName(v_Counter);
      END IF;
    END LOOP;

    v_ProcCall := v_ProcCall || '); END;';

    -- J[\I[vāA͂B
    v_Cursor := DBMS_SQL.OPEN_CURSOR;
    DBMS_SQL.PARSE(v_Cursor, v_ProcCall, DBMS_SQL.V7);

    -- vV[Wp[^oChB
    FOR v_Counter IN 1..p_NumParams LOOP
  
      -- ܂p[^ݒ肵܂B
      p_Parameters(v_Counter).name := v_ArgumentName(v_Counter);

      -- p[^̃^CvɊÂăoChB
      IF p_Parameters(v_Counter).actual_type = 'NUMBER' THEN
        DBMS_SQL.BIND_VARIABLE(v_Cursor, p_Parameters(v_Counter).name,
                              p_Parameters(v_Counter).num_param);
      ELSIF p_Parameters(v_Counter).actual_type = 'VARCHAR2' THEN
        DBMS_SQL.BIND_VARIABLE(v_Cursor, p_Parameters(v_Counter).name,
                             p_Parameters(v_Counter).vchar_param, 500);
      ELSIF p_Parameters(v_Counter).actual_type = 'DATE' THEN
        DBMS_SQL.BIND_VARIABLE(v_Cursor, p_Parameters(v_Counter).name,
                             p_Parameters(v_Counter).date_param);
      ELSIF p_Parameters(v_Counter).actual_type = 'CHAR' THEN
       DBMS_SQL.BIND_VARIABLE_CHAR(v_Cursor,p_Parameters(v_Counter).name,
                                p_Parameters(v_Counter).char_param, 500);
      ELSE
        RAISE_APPLICATION_ERROR(-20001, 'Invalid type');
      END IF;
    END LOOP;

    -- vV[WsB
    v_NumRows := DBMS_SQL.EXECUTE(v_Cursor);

    -- OUT܂IN OUTp[^ɂVARIABLE_VALUER[B
    FOR v_Counter IN 1..p_NumParams LOOP
      IF v_InOut(v_Counter) = 1 OR v_InOut(v_Counter) = 2 THEN
        IF p_Parameters(v_Counter).actual_type = 'NUMBER' THEN
          DBMS_SQL.VARIABLE_VALUE(v_Cursor, ':' ||
                               p_Parameters(v_Counter).name,
                               p_Parameters(v_Counter).num_param);
        ELSIF p_Parameters(v_Counter).actual_type = 'VARCHAR2' THEN
          DBMS_SQL.VARIABLE_VALUE(v_Cursor, ':' ||
                               p_Parameters(v_Counter).name,
                               p_Parameters(v_Counter).vchar_param);
        ELSIF p_Parameters(v_Counter).actual_type = 'DATE' THEN
          DBMS_SQL.VARIABLE_VALUE(v_Cursor, ':' ||
                               p_Parameters(v_Counter).name,
                               p_Parameters(v_Counter).date_param);
        ELSIF p_Parameters(v_Counter).actual_type = 'CHAR' THEN
          DBMS_SQL.VARIABLE_VALUE_CHAR(v_Cursor, ':' ||
                               p_Parameters(v_Counter).name,
                               p_Parameters(v_Counter).char_param);
        ELSE
          RAISE_APPLICATION_ERROR(-20001, 'Invalid type');
        END IF;
      END IF;
    END LOOP;

  END RunProc;

  PROCEDURE Printparams(p_Parameters IN t_ParameterList,
                        p_NumParams IN NUMBER) IS
  BEGIN
    -- p[^[vāAOA^Cvђl\B
    FOR v_Counter IN 1..p_NumParams LOOP
      DBMS_OUTPUT.PUT('Parameter ' || v_Counter || ': Name = ');
      DBMS_OUTPUT.PUT(p_Parameters(v_Counter).name || ', Type = ');
      DBMS_OUTPUT.PUT(p_Parameters(v_Counter).actual_type ||
                      ', Value = ');
      IF p_Parameters(v_Counter).actual_type = 'NUMBER' THEN
        DBMS_OUTPUT.PUT_LINE(p_Parameters(v_Counter).num_param);
      ELSIF p_Parameters(v_Counter).actual_type = 'VARCHAR2' THEN
        DBMS_OUTPUT.PUT_LINE(p_Parameters(v_Counter).vchar_param);
      ELSIF p_Parameters(v_Counter).actual_type = 'DATE' THEN
        DBMS_OUTPUT.PUT_LINE(p_Parameters(v_Counter).date_param);
      ELSE
        DBMS_OUTPUT.PUT_LINE(p_Parameters(v_Counter).char_param);
      END IF;
    END LOOP;
  END PrintParams;

END ExecuteAny;



-- Available online as testpkg.sql
CREATE OR REPLACE PACKAGE TestPkg AS
  -- 
łExecuteAny킩₷邽߂ɁA
  -- 
قȂ^Cv̈ɊȒPȃpbP[WgpB
  PROCEDURE P1(p_Num IN NUMBER, p_Date OUT DATE);
  PROCEDURE P2(p_String OUT VARCHAR2);
  PROCEDURE P3(p_Num IN OUT NUMBER, p_String OUT VARCHAR2);
END TestPkg;

CREATE OR REPLACE PACKAGE BODY TestPkg AS
  PROCEDURE P1(p_Num IN NUMBER, p_Date OUT DATE) IS
  BEGIN
    p_Date := SYSDATE;
  END P1;
  
  PROCEDURE P2(p_String OUT VARCHAR2) IS
  BEGIN
    p_String := 'Hello World!';
  END P2;

  PROCEDURE P3(p_Num IN OUT NUMBER, p_String OUT VARCHAR2) IS
  BEGIN
    p_String := 'Original value was ' || TO_NUMBER(p_Num);
    p_Num := p_Num + 25;
  END P3;
END TestPkg;



-- Available online as anyexamp.sql
DECLARE
  -- 
v_Paramsɂ͂ꂩR[vV[W̃p[^XgێB
BEGIN
  -- v_ParamsTestPkg.P1̏͂Bŏ̃p[^INŁA2Ԗڂ
  -- p[^OUTȂ̂ŁAp[^1_paraml݂̂ɓ͂邱ƂɒӂB
  -- ExecuteAny.RunProcOUTp[^ׂĂɓ͂BA
  -- p[^ɂĂ^CvɂĂ͓̏͂KvB
  v_Params(1).actual_type := 'NUMBER';
  v_Params(1).num_param := 7;
  v_Params(2).actual_type := 'DATE';
  ExecuteAny.RunProc(2, 'TestPkg.P1', v_Params);
  DBMS_OUTPUT.PUT_LINE('After call to RunProc for P1:');
  ExecuteAny.PrintParams(v_Params, 2);
  DBMS_OUTPUT.NEW_LINE;

  -- TestPkg.P2v_Params͂BP2ɂOUTp[^
  -- 1Ȃ̂ŁA^Cv͂邾łB
  v_Params(1).actual_type := 'VARCHAR2';
  ExecuteAny.RunProc(1, 'TestPkg.P2', v_Params);
  DBMS_OUTPUT.PUT_LINE('After call to RunProc for P2:');
  ExecuteAny.PrintParams(v_Params, 1);
  DBMS_OUTPUT.NEW_LINE;
  
  -- TestPkg.P3v_Params͂B
  v_Params(1).actual_type := 'NUMBER';
  v_Params(1).num_param := -34;
  v_Params(2).actual_type := 'VARCHAR2';
  ExecuteAny.RunProc(2, 'TestPkg.P3', v_Params);
  DBMS_OUTPUT.PUT_LINE('After call to RunProc for P3:');
  ExecuteAny.PrintParams(v_Params, 2);
  DBMS_OUTPUT.NEW_LINE;
END;



statement(lb) || statement(lb + 1) || ... || statement(ub)



CREATE OR REPLACE PROCEDURE DynamicPLSQL (
  p_StudentID IN students.ID%TYPE) IS

  v_CursorID  INTEGER;
  v_BlockStr  DBMS_SQL.VARCHAR2S;
  ...
BEGIN
  -- pɃJ[\I[vB
  v_CursorID := DBMS_SQL.OPEN_CURSOR;

  -- PL/SQLubN܂ޕ쐬B
  -- ̕ł́A:first_name:last_namẽv[Xz_͏o͕ϐŁA
  -- :ID͓͕ϐB
  v_BlockStr(1) := 'BEGIN';
  v_BlockStr(2) := 'SELECT first_name, last_name';
  v_BlockStr(3) := '  INTO :first_name, :last_name';
  v_BlockStr(4) := '    FROM students';
  v_BlockStr(5) := '    WHERE ID = :ID;';
  v_BlockStr(6) := 'END;';

  -- ͂B
  DBMS_SQL.PARSE(v_CursorID, v_BlockStr, 1, 6, TRUE, DBMS_SQL.V7);
  ...
END DynamicPLSQL;



-- Available online as copyRS.sql
CREATE OR REPLACE PROCEDURE CopyRegisteredStudents(
  p_NewName IN VARCHAR2) AS
  /* 
registered_studentsƓ\V\Ap_NewNameɂĎw肳ꂽO	
	ō쐬Bregistered_students̓ePL/SQL\ɓǂݍ܂AV\ɑ}
	B*/

  v_BatchSize CONSTANT INTEGER := 5;
  v_IDs DBMS_SQL.NUMBER_TABLE;
  v_Departments DBMS_SQL.VARCHAR2_TABLE;
  v_Courses DBMS_SQL.NUMBER_TABLE;
  v_Grades DBMS_SQL.VARCHAR2_TABLE;

  v_Cursor1 INTEGER;
  v_Cursor2 INTEGER;
  v_ReturnCode INTEGER;
  v_NumRows INTEGER;
  v_SQLStatement VARCHAR2(200);
  v_SelectStmt VARCHAR2(200);
  v_InsertStmt VARCHAR2(200);

BEGIN
  v_Cursor1 := DBMS_SQL.OPEN_CURSOR;
  v_Cursor2 := DBMS_SQL.OPEN_CURSOR;

  -- 
܂V\폜BORA-942i\܂̓r[݂܂jG[
  -- 
B
  BEGIN
    v_SQLStatement := 'DROP TABLE ' || p_NewName;
    DBMS_SQL.PARSE(v_Cursor1, v_SQLStatement, DBMS_SQL.V7);
    v_ReturnCode := DBMS_SQL.EXECUTE(v_Cursor1);
  EXCEPTION
    WHEN OTHERS THEN
      IF SQLCODE != -942 THEN
        RAISE;
      END IF;
  END;

  -- 
V\쐬B
  v_SQLStatement := 'CREATE TABLE ' || p_NewName || '(';
  v_SQLStatement := v_SQLStatement || 'student_id NUMBER(5),';
  v_SQLStatement := v_SQLStatement || 'department CHAR(3),';
  v_SQLStatement := v_SQLStatement || 'course NUMBER(3),';
  v_SQLStatement := v_SQLStatement || 'grade CHAR(1))';
  DBMS_SQL.PARSE(v_Cursor1, v_SQLStatement, DBMS_SQL.V7);
  v_ReturnCode := DBMS_SQL.EXECUTE(v_Cursor1);

  -- 
selectinsert͂B
  v_SelectStmt := 'SELECT * FROM registered_students';
  v_InsertStmt := 'INSERT INTO ' || p_NewName || ' VALUES ';
  v_InsertStmt := v_InsertStmt || '(:ID, :department, :course,
                                    :grade)';
  DBMS_SQL.PARSE(v_Cursor1, v_SelectStmt, DBMS_SQL.V7);
  DBMS_SQL.PARSE(v_Cursor2, v_InsertStmt, DBMS_SQL.V7);

  -- 
DEFINE_ARRAYgpselect̏o͕ϐw肷B
  DBMS_SQL.DEFINE_ARRAY(v_Cursor1, 1, v_IDs, v_BatchSize, 1);
  DBMS_SQL.DEFINE_ARRAY(v_Cursor1, 2, v_Departments, v_BatchSize, 1);
  DBMS_SQL.DEFINE_ARRAY(v_Cursor1, 3, v_Courses, v_BatchSize, 1);
  DBMS_SQL.DEFINE_ARRAY(v_Cursor1, 4, v_Grades, v_BatchSize, 1);

  -- 
selectsB
  v_ReturnCode := DBMS_SQL.EXECUTE(v_Cursor1);

  -- 
̓tFb`[vłBFETCH_ROWSւ̃R[͂f[^v_BatchSizes
  -- 
oBFETCH_ROWSv_BatchSize菬lԂƁA[v͏IB
  LOOP
    v_NumRows := DBMS_SQL.FETCH_ROWS(v_Cursor1);
    DBMS_SQL.COLUMN_VALUE(v_Cursor1, 1, v_IDs);
    DBMS_SQL.COLUMN_VALUE(v_Cursor1, 2, v_Departments);
    DBMS_SQL.COLUMN_VALUE(v_Cursor1, 3, v_Courses);
    DBMS_SQL.COLUMN_VALUE(v_Cursor1, 4, v_Grades);

    -- 
ꂪŌ̃tFb`ł΁AFETCH_ROWSv_BatchSizes菬lԂB
    -- 
A܂sԂꍇAv_NumRowsƓ̍s邱ƂB
    -- 
āÃoChłv_BatchSizeł͂ȂAv_NumRowsgpB

    -- 
v_NumRows = 0ƂʂȏꍇŃ`FbNKvB́A
    -- 
ÕtFb`łׂĂ̍sԂA[vƂӖB
    IF v_NumRows = 0 THEN
      EXIT;
    END IF;  

    -- 
BIND_ARRAYgpđ}͕̓ϐw肷B
    -- 
vf1..v_NumRowŝ݂gpB
    DBMS_SQL.BIND_ARRAY(v_Cursor2, ':ID', v_IDs, 1, v_NumRows);
    DBMS_SQL.BIND_ARRAY(v_Cursor2, ':department', v_Departments, 1,
                        v_NumRows);
    DBMS_SQL.BIND_ARRAY(v_Cursor2, ':course', v_Courses, 1, v_NumRows);
    DBMS_SQL.BIND_ARRAY(v_Cursor2, ':grade', v_Grades, 1, v_NumRows);

    -- 
insertsB
    v_ReturnCode := DBMS_SQL.EXECUTE(v_Cursor2);

    -- 
[v̏IB`FbNOɂłɃ[vIĂ邱Ƃ
    -- 
ӂB
    EXIT WHEN v_NumRows < v_BatchSize;
  END LOOP;

  COMMIT;

  DBMS_SQL.CLOSE_CURSOR(v_Cursor1);
  DBMS_SQL.CLOSE_CURSOR(v_Cursor2);
END CopyRegisteredStudents;



-- Available online as descrtab.sql
CREATE OR REPLACE PROCEDURE DescribeTable(p_Table IN VARCHAR2) AS
  v_Cursor       INTEGER;
  v_SQLStatement VARCHAR2(100);
  v_DescribeInfo DBMS_SQL.DESC_TAB;
  v_DRec         DBMS_SQL.DESC_REC;
  v_ReturnCode   INTEGER;
  v_NumColumns   INTEGER;

  FUNCTION ConvertDatatype (v_Datatype IN NUMBER)
    RETURN VARCHAR2 IS
    v_Output VARCHAR2(20);
  BEGIN
    SELECT DECODE(v_Datatype, 1, 'VARCHAR2',
                              2, 'NUMBER',
                              8, 'LONG',
                              12, 'DATE',
                              23, 'RAW',
                              24, 'LONG RAW',
                              69, 'ROWID',
                              96, 'CHAR',
                              106, 'MLSLABEL',
                              112, 'CLOB',
                              113, 'BLOB',
                              114, 'BFILE')
      INTO v_Output
      FROM dual;

    RETURN v_Output;
  END ConvertDatatype;

BEGIN
  v_Cursor := DBMS_SQL.OPEN_CURSOR;

  -- 
\select͂B
  -- 
sKv͂ȂB
  v_SQLStatement := 'SELECT * FROM ' || p_Table;
  DBMS_SQL.PARSE(v_Cursor, v_SQLStatement, DBMS_SQL.V7);

  -- 
LqBƕ\LqB
  DBMS_SQL.DESCRIBE_COLUMNS(v_Cursor,  v_NumColumns, v_DescribeInfo);

  -- 
wb_[o͂B
  DBMS_OUTPUT.PUT_LINE('Description of ' || p_Table || ':');
  DBMS_OUTPUT.PUT('Column Name     Datatype Length Precision Scale ');
  DBMS_OUTPUT.PUT_LINE('Null?');
  DBMS_OUTPUT.PUT('------------- -------- ------ ------- ----- ');
  DBMS_OUTPUT.PUT_LINE('-----');

  -- e[vāAꂼ̋Lqo͂B
  FOR v_Col IN 1..v_NumColumns LOOP
    v_DRec := v_DescribeInfo(v_Col);
    DBMS_OUTPUT.PUT(RPAD(v_DRec.col_name, 16));
    DBMS_OUTPUT.PUT(RPAD(ConvertDatatype(v_DRec.col_type), 9));
    DBMS_OUTPUT.PUT(RPAD(v_DRec.col_max_len, 7));
    DBMS_OUTPUT.PUT(RPAD(v_DRec.col_precision, 10));
    DBMS_OUTPUT.PUT(RPAD(v_DRec.col_scale, 6));
    IF v_DescribeInfo(v_Col).col_null_ok THEN
      DBMS_OUTPUT.NEW_LINE;
    ELSE
      DBMS_OUTPUT.PUT_LINE('NOT NULL');
    END IF;
  END LOOP;

END DescribeTable;



DECLARE
  v_CursorID INTEGER;
  ...
BEGIN
  ...
EXCEPTION
  WHEN OTHERS THEN
    IF DBMS_SQL.IS_OPEN(v_CursorID) THEN
      DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    END IF;
    RAISE;
END;



Name                            Null?     Type 
 ------------------------------- -------- ---- 
 ID                                       NUMBER 
 DOCUMENT                                 LONG



-- Available online as dumplong.sql
CREATE OR REPLACE FUNCTION dump_doc(docid    IN NUMBER, 
                                    filename IN VARCHAR2) 
                           RETURN VARCHAR2 
IS 
  data_chunk          VARCHAR2(254);   
  chunk_size          NUMBER:=254; 
  chunk_size_returned NUMBER; 
  -- t@C̈ƂȂfBNgP[VƂĐݒ肷B
  location            VARCHAR2(20) := 'c:\temp'; 
  mycursor            NUMBER;  
  stmt                VARCHAR2(1024); 
  cur_pos             NUMBER:=0; 
  rows                NUMBER; 
  dummy               NUMBER; 
  file_handle         UTL_FILE.FILE_TYPE; 
  status              VARCHAR2(50); 
BEGIN 
  -- ݂s邽߂Ƀt@CI[vB
  file_handle := utl_file.fopen(location, filename, 'w');
  -- t@NV̒ɓnplsqlp[^dociddoctoget
  -- zXgϐɃoChB
  stmt := 'SELECT DOCUMENT FROM ASCII_DOCS WHERE ID = :doctoget'; 
  mycursor := dbms_sql.open_cursor; 
  dbms_sql.parse(mycursor, stmt, dbms_sql.v7); 
  dbms_sql.bind_variable(mycursor, ':doctoget', docid); 

  -- hLgŜƂĂ݂ȂL[ɂĂ1tFb`1sɊi[B
  dbms_sql.define_column_long(mycursor,1); 
  dummy := dbms_sql.execute(mycursor); 
  rows := dbms_sql.fetch_rows(mycursor); 

  loop 
    -- long^́u`NvtFb`B
    dbms_sql.column_value_long(mycursor, 
                               1, 
                               chunk_size, 
                               cur_pos, 
                               data_chunk, 
                               chunk_size_returned); 
    utl_file.put(file_handle, data_chunk);  
    cur_pos := cur_pos + chunk_size; 
    exit when chunk_size_returned = 0;  
  end loop; 

  dbms_sql.close_cursor(mycursor); 
  utl_file.fclose(file_handle); 
  return('Success'); 
EXCEPTION 
  WHEN OTHERS THEN 
    utl_file.fclose(file_handle); 
    return('Failure'); 
END dump_doc;



DROP TABLE temp_table;
CREATE TABLE temp_table (num_col NUMBER, char_col VARCHAR2(50));



ORA-01031: sĂ܂B



Chapter 16
-- Available online as logRSins.sql
CREATE OR REPLACE TRIGGER LogRSInserts
  BEFORE INSERT ON registered_students
  FOR EACH ROW
DECLARE
  v_Status     INTEGER;
BEGIN

  /* ̎ނ܂obt@ɃpbLOB */
  DBMS_PIPE.PACK_MESSAGE('I');

  /* ݂̃[U[ƃ^CX^vpbLOB */
  DBMS_PIPE.PACK_MESSAGE(user);
  DBMS_PIPE.PACK_MESSAGE(sysdate);

  /* VlpbLOB */
  DBMS_PIPE.PACK_MESSAGE(:new.student_ID);
  DBMS_PIPE.PACK_MESSAGE(:new.department);
  DBMS_PIPE.PACK_MESSAGE(:new.course);
  DBMS_PIPE.PACK_MESSAGE(:new.grade);

  /* pCv'RSInserts'āAbZ[W𑗐MB */
  v_Status := DBMS_PIPE.SEND_MESSAGE('RSInserts');

  /* MɎsȂꍇ́AύX
     sȂ悤ɁAG[ʒmB */
  IF v_Status != 0 THEN
    RAISE_APPLICATION_ERROR(-20010, 'LogRSInserts trigger ' ||
      'couldn''t send the message, status = ' || v_Status);
  END IF;
  
END LogRSInserts;



/* Available online as RSinsert.pc */
/* ̃vÓARSInsertsƂpCv烁bZ[WMA
   t@CɃMOB */

/* CSQL̃wb_[t@C */
#include <stdio.h>
EXEC SQL INCLUDE sqlca;

EXEC SQL BEGIN DECLARE SECTION;
  /* f[^x[Xɐڑ邽߂̃[U[ƃpX[h */
  char *v_Connect = "example/example";

  /* DBMS_PIPER[ۂɎgp󋵕ϐ */
  int v_Status;
  VARCHAR v_Code[5];

  /* pCvoRőMϐ - ꂪMȎΏۂƂȂB */
  VARCHAR v_Userid[9];
  VARCHAR v_Changedate[10];
  int v_StudentID;
  VARCHAR v_Department[4];
  int v_Course;
  VARCHAR v_Grade[2];
  short v_Grade_ind;
EXEC SQL END DECLARE SECTION;

/* Ot@Cɑ΂t@C|C^ */
FILE *outfile;

void sqlerror();

int main() {

  /* G[̏ */
  EXEC SQL WHENEVER SQLERROR DO sqlerror();

  /* f[^x[Xւ̐ڑ */
  EXEC SQL CONNECT :v_Connect;

  /* Ot@C̃I[v */
  outfile = fopen("rs.log", "w");

  /* C[vB'STOP'bZ[WMꍇA
     G[ꍇłȂƁÃ[v甲ȂB */
  for (;;) {
    /* pCv'RSInserts'ăbZ[WM܂ŃX[v
       ^CAEgĺAw肵ĂȂ߁AftHglgpB */
    EXEC SQL EXECUTE
      BEGIN
        :v_Status := DBMS_PIPE.RECEIVE_MESSAGE('RSInserts');
      END;
    END-EXEC;

    if (v_Status == 0) {
      /* bZ[W̐MB@肷邽߂ɁA
         擪̃f[^vf擾KvB */
      v_Code.len = 5;
      EXEC SQL EXECUTE
        BEGIN
          DBMS_PIPE.UNPACK_MESSAGE(:v_Code);
        END;
      END-EXEC;
      v_Code.arr[v_Code.len] = '\0';

      if (!strcmp(v_Code.arr, "STOP")) {
        /* 'Stop'bZ[W̎MB[v甲B */
        break;
      }

      /* bZ[W̎c̏([U[ID, tAѐVl)
         oB */
      v_Userid.len = 9;
      v_Changedate.len = 10;    
      v_Department.len = 4;
      v_Grade.len = 2;
      EXEC SQL EXECUTE
        DECLARE
          v_ChangeDate DATE;
        BEGIN
          DBMS_PIPE.UNPACK_MESSAGE(:v_Userid);
          DBMS_PIPE.UNPACK_MESSAGE(v_ChangeDate);
          :v_Changedate := TO_CHAR(v_ChangeDate, 'DD-MON-YY');
          DBMS_PIPE.UNPACK_MESSAGE(:v_StudentID);
          DBMS_PIPE.UNPACK_MESSAGE(:v_Department);
          DBMS_PIPE.UNPACK_MESSAGE(:v_Course);
          DBMS_PIPE.UNPACK_MESSAGE(:v_Grade:v_Grade_ind);
        END;
      END-EXEC;

      /* ̖NULLtB */
      v_Userid.arr[v_Userid.len] = '\0';
      v_Changedate.arr[v_Changedate.len] = '\0';
      v_Department.arr[v_Department.len] = '\0';

      if (v_Grade_ind == -1)
        v_Grade.arr[0] = '\0';
      else
        v_Grade.arr[v_Grade.len] = '\0';

      /* f[^Ot@Cɏo */
      fprintf(outfile, "User: %s Timestamp: %s",
        v_Userid.arr, v_Changedate.arr);
      fprintf(outfile, " ID: %d Course: %s %d Grade: %s\n",
        v_StudentID, v_Department.arr, v_Course, v_Grade.arr);

    }
    else if (v_Status == 1) {
      /* RECEIVE_MESSAGER[̃^CAEgB[vōēx҂B */
      continue;
    }
    else {
      /* RECEIVE_MESSAGEG[ňُIB
         YG[o͂AIB */
      printf("RECEIVE_MESSAGE Error!  Status = %d\n", v_Status);
      EXEC SQL ROLLBACK WORK RELEASE;
      exit(1);
    }

  }  /* C[v̏I */
    
  /* t@C̃N[Y */
  fclose(outfile);

  /* f[^x[XƂ̐ڑ */
  EXEC SQL COMMIT WORK RELEASE;
}


/* G[֐BG[ʂɏo͂AIB */
void sqlerror() {

  printf("SQL Error!\n");
  printf("%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);

  EXEC SQL WHENEVER SQLERROR CONTINUE;

  EXEC SQL ROLLBACK RELEASE;
}



ORA-23322: pCvɃANZXɂ͌s\łB 



/* Available online as debug.pc */
/* {vÓADBMS_PIPEłDebugpbP[W̃obNGh
   sB{vÓAfobNΏۂPL/SQLZbVƂ͕ʂ
   EChEŎs邱ƁB */

/* CSQL̃wb_[t@C */
#include <stdio.h>
EXEC SQL INCLUDE sqlca;

EXEC SQL BEGIN DECLARE SECTION;
  /* f[^x[Xɐڑ邽߂̃[U[ƃpX[h */
  char *v_Connect = "example/example";

  /* DBMS_PIPER[ۂɎgpԕϐ */
  int v_Status;
  VARCHAR v_Code[6];

  /* pCvoRőMϐ */
  VARCHAR v_ReturnPipeName[31];
  VARCHAR v_Description[100];
  VARCHAR v_Value[100];
EXEC SQL END DECLARE SECTION;

/* G[֐. */
void sqlerror();

int main() {

  /* G[̏ */
  EXEC SQL WHENEVER SQLERROR DO sqlerror();

  /* f[^x[Xւ̐ڑ */
  EXEC SQL CONNECT :v_Connect;

  printf("Debug ready for input.\n");

  /* C[vB'STOP'bZ[WMꍇA
     G[ꍇłȂƁÃ[v甲ȂB */
  for (;;) {
    /* pCv'Debug'ăbZ[WM܂ŃX[vB
       ^CAEgĺAw肵ĂȂ߁AftHglgpB */
    EXEC SQL EXECUTE
      BEGIN
        :v_Status := DBMS_PIPE.RECEIVE_MESSAGE('DebugPipe');
      END;
    END-EXEC;

    if (v_Status == 0) {
      /* bZ[W̐MB@肷邽߂ɁA
         擪̃f[^vf擾KvB */
      v_Code.len = 6;
      EXEC SQL EXECUTE
        BEGIN
          DBMS_PIPE.UNPACK_MESSAGE(:v_Code);
        END;
      END-EXEC;
      v_Code.arr[v_Code.len] = '\0';

      if (!strcmp(v_Code.arr, "STOP")) {
        /* 'STOP'bZ[W̎MB[v甲B */
        break;
      } /* STOP̏I */

      else if (!strcmp(v_Code.arr, "TEST")) {
        /* TESTbZ[W̎MBpCv
           nhVFCNԑB */
        EXEC SQL EXECUTE
          BEGIN
            DBMS_PIPE.PACK_MESSAGE('Handshake');
            :v_Status := DBMS_PIPE.SEND_MESSAGE('DebugPipe');
          END;
        END-EXEC;

        if (v_Status != 0) {
          /* G[bZ[Wo͂B */
          printf("Error %d while responding to TEST message\n",
                 v_Status);
        }
      } /* TEST̏I */

      else if (!strcmp(v_Code.arr, "DEBUG")) {
        /* DEBUGbZ[W̎MB^[p̃pCvAA
           яo͒l̃pbLOB */
        v_ReturnPipeName.len = 30;
        v_Description.len = 100;
        v_Value.len = 100;
        EXEC SQL EXECUTE
          BEGIN
            DBMS_PIPE.UNPACK_MESSAGE(:v_ReturnPipeName);
            DBMS_PIPE.UNPACK_MESSAGE(:v_Description);
            DBMS_PIPE.UNPACK_MESSAGE(:v_Value);
          END;
        END-EXEC;

        /* o͕ϐ̖NULLtB */
        v_Description.arr[v_Description.len] = '\0';
        v_Value.arr[v_Value.len] = '\0';

        /* fobNʃGR[ɕ\B */
        printf("%s: %s\n", v_Description.arr, v_Value.arr);

        /* nhVFCNbZ[WԑB */
        EXEC SQL EXECUTE
          BEGIN
            DBMS_PIPE.PACK_MESSAGE('Processed');
            :v_Status := DBMS_PIPE.SEND_MESSAGE(:v_ReturnPipeName);
          END;
        END-EXEC;

        if (v_Status != 0) {
          /* G[bZ[Wo͂B */
          printf("Error %d while sending handshake message\n",
                 v_Status);
        }
      } /* DEBUG̏I */
    } /* bZ[W̐M̏I */

    else if (v_Status == 1) {
      /* RECEIVE_MESSAGER[̃^CAEgB[vōēx҂B */
      continue;
    }

    else {
      /* RECEIVE_MESSAGEG[ňُIB
         YG[o͂āAIB */
      printf("Main loop RECEIVE_MESSAGE Error. Status = %d\n",
             v_Status);
      EXEC SQL ROLLBACK WORK RELEASE;
      exit(1);
    }

  }  /* C[v̏I */
    
  /* f[^x[XƂ̐ڑ */
  EXEC SQL COMMIT WORK RELEASE;
}


/* G[֐BG[ʂɏo͂AIB */
void sqlerror() {

  printf("SQL Error!\n");
  printf("%.*s\n", sqlca.sqlerrm.sqlerrml,
                   sqlca.sqlerrm.sqlerrmc);

  EXEC SQL WHENEVER SQLERROR CONTINUE;

  EXEC SQL ROLLBACK RELEASE;
}



-- Available online as debug.sql
CREATE OR REPLACE PACKAGE Debug AS
  -- nhVFCNbZ[W̍ő҂ԁibj
  v_TimeOut NUMBER := 10;

  -- Debug̃CvV[W
  PROCEDURE Debug(p_Description IN VARCHAR2, p_Value IN
VARCHAR2);

  -- Debug̊̃ZbgAbv
  PROCEDURE Reset;

  -- f[IB
  PROCEDURE Exit;
END Debug;
/

CREATE OR REPLACE PACKAGE BODY Debug as

  v_CurrentPipeName VARCHAR2(30);

  PROCEDURE Debug(p_Description IN VARCHAR2, p_Value IN
VARCHAR2) IS
    v_ReturnCode NUMBER;
    v_Handshake  VARCHAR2(10);
  BEGIN
    /* pCv̖Ȍꍇɂ́ApCv̖O肷B */
    IF v_CurrentPipeName IS NULL THEN
      v_CurrentPipeName := DBMS_PIPE.UNIQUE_SESSION_NAME;
    END IF;

    /* ̏Ƃ 'DEBUG' bZ[W𑗐MB
         - nhVFCNp̃pCv
         - 
         - l
    */
    DBMS_PIPE.PACK_MESSAGE('DEBUG');
    DBMS_PIPE.PACK_MESSAGE(v_CurrentPipeName);
    DBMS_PIPE.PACK_MESSAGE(p_Description);
    DBMS_PIPE.PACK_MESSAGE(p_Value);
    v_ReturnCode := DBMS_PIPE.SEND_MESSAGE('DebugPipe');

    IF v_ReturnCode != 0 THEN
      RAISE_APPLICATION_ERROR(-20210,
        'Debug.Debug: SEND_MESSAGE failed with ' || v_ReturnCode);
    END IF;

    /* ^[p̃pCvŃnhVFCNbZ[W҂B */
    v_ReturnCode := DBMS_PIPE.RECEIVE_MESSAGE(v_CurrentPipeName);

    IF v_ReturnCode = 1 THEN
       -- ^CAEg
      RAISE_APPLICATION_ERROR(-20211,
        'Debug.Debug: No handshake message received');
    ELSIF v_ReturnCode != 0 THEN
      -- ̑̃G[
      RAISE_APPLICATION_ERROR(-20212,
        'Debug.Debug: RECEIVE_MESSAGE failed with ' ||
        v_ReturnCode);
    ELSE
      -- nhVFCNbZ[W̃`FbN
      DBMS_PIPE.UNPACK_MESSAGE(v_Handshake);
      IF v_Handshake = 'Processed' THEN
        -- o͂ꂽꍇ
        NULL;
      ELSE
        -- nhVFCNȂ̏ꍇ
        RAISE_APPLICATION_ERROR(-20213,
          'Debug.Debug: Incorrect handshake message received');
      END IF;
    END IF;
  END Debug;

  PROCEDURE Reset IS
    /* pCvăeXgbZ[W𑗐MAf[삵Ă邩
       mFB삵ĂȂꍇ́AG[ʒmB */
    v_ReturnCode NUMBER;
  BEGIN
    DBMS_PIPE.PACK_MESSAGE('TEST');
    v_ReturnCode := DBMS_PIPE.SEND_MESSAGE('DebugPipe');

    IF v_ReturnCode != 0 THEN
      RAISE_APPLICATION_ERROR(-20200,
        'Debug.Reset: SEND_MESSAGE failed with ' || v_ReturnCode);
    END IF;

    /* f[́ApCvĉB̃R[
       ^CAEgɂȂꍇ́Af[̏łĂȂ
       ߁AG[ʒmB */
    v_ReturnCode := DBMS_PIPE.RECEIVE_MESSAGE('DebugPipe', v_TimeOut);
    IF v_ReturnCode = 1 THEN
      -- ^CAEg
      RAISE_APPLICATION_ERROR(-20201,
        'Debug.Reset: Daemon not ready');
    ELSIF v_ReturnCode != 0 THEN
      -- ̑̃G[
      RAISE_APPLICATION_ERROR(-20202,
        'Debug.Reset: RECEIVE_MESSAGE failed with ' ||
        v_ReturnCode);
    ELSE
      -- f[́A
      NULL;
    END IF;
  END Reset;

  PROCEDURE Exit IS
    v_ReturnCode NUMBER;
  BEGIN
    -- 'STOP'bZ[W𑗐M
    DBMS_PIPE.PACK_MESSAGE('STOP');
    v_ReturnCode := DBMS_PIPE.SEND_MESSAGE('DebugPipe');

    IF v_ReturnCode != 0 THEN
      RAISE_APPLICATION_ERROR(-20230,
        'Debug.Exit: SEND_MESSAGE failed with ' || v_ReturnCode);
    END IF;
  END Exit;

END Debug;



Chapter 17
GRANT AQ_ADMINISTRATOR_ROLE TO example;
BEGIN DBMS_AQADM.GRANT_TYPE_ACCESS('example'); END;



-- Available online as createq.sql
CREATE OR REPLACE TYPE MessageObj AS OBJECT (
  title  VARCHAR2(30),
  data1  NUMBER,
  data2  VARCHAR2(100),
  data3  DATE,

  MEMBER PROCEDURE Print(v_Message IN VARCHAR2)
);

CREATE OR REPLACE TYPE BODY MessageObj AS
  MEMBER PROCEDURE Print(v_Message IN VARCHAR2) IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE(v_Message || ': ' || title);
    DBMS_OUTPUT.PUT('Data 1: ' || data1);
    DBMS_OUTPUT.PUT(' Data 2: ' || data2);
    DBMS_OUTPUT.PUT_LINE(' Data 3: ' || data3);
  END Print;
END;

BEGIN
  -- ׂẴftHg܂񂾊ȒPȕ\쐬BŁAbZ[W̃O[v
  -- ̃RV[}gpȂAFIFOL[\ɂȂB
  DBMS_AQADM.CREATE_QUEUE_TABLE(
    queue_table => 'SimpleQTab',
    queue_payload_type => 'MessageObj',
    comment => 'Simple Queue Table');

  -- SimpleQTab̒ɊȒPȃL[쐬BftHg̃p[^
  -- gp邱ƁB
  DBMS_AQADM.CREATE_QUEUE(
    queue_name => 'SimpleQ',
    queue_table => 'SimpleQTab',
    comment => 'Simple Queue');

  -- SimpleQɑ΂GL[уfL[gp\ɂB
  DBMS_AQADM.START_QUEUE('SimpleQ');

  -- SimpleQTab̒ɗOL[쐬B
  DBMS_AQADM.CREATE_QUEUE(
    queue_name => 'ExceptionQ',
    queue_table => 'SimpleQTab',
    queue_type => DBMS_AQADM.EXCEPTION_QUEUE,
    comment => 'Exception Queue');

  -- ExceptionQɑ΂fL[Iy[Vgp\ɂB
  DBMS_AQADM.START_QUEUE('ExceptionQ', FALSE, TRUE);
END;

BEGIN
  -- \[gw肵ėD揇ʃL[\쐬B
  -- ̃L[ɂ̓bZ[W̃O[v╡̃RV[}͎gpȂB
  DBMS_AQADM.CREATE_QUEUE_TABLE(
    queue_table => 'PriorityQTab',
    queue_payload_type => 'MessageObj',
    sort_list => 'priority,enq_time',
    comment => 'Priority Queue Table');

  -- PriorityQTab̒ɗD揇ʃL[쐬BftHg
  -- p[^gp邱ƁB

  DBMS_AQADM.CREATE_QUEUE(
    queue_name => 'PriorityQ',
    queue_table => 'PriorityQTab',
    comment => 'Priority Queue');

  -- PriorityQɑ΂GL[уfL[Iy[Vgp\ɂB
  DBMS_AQADM.START_QUEUE('PriorityQ');
END;



-- Available online as simple.sql
DECLARE
  v_Message MessageObj;
  v_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);

  c_NumMessages CONSTANT INTEGER := 10;

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  FOR v_Counter IN 1..c_NumMessages LOOP
    -- GL[郁bZ[W쐬B
    v_Message :=
      MessageObj('Message ' || v_Counter, v_Counter * 10,
                 'abcdefghijklmnopqrstuvwxyz', SYSDATE + v_Counter);

    -- ftHgIvVł̃bZ[WGL[B
    DBMS_AQ.ENQUEUE(
      queue_name => 'SimpleQ',
      enqueue_options => v_EnqueueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);
  END LOOP;

  -- ׂẴGL[R~bgB
  COMMIT;

  -- fL[郁bZ[WȂȂ܂Ń[vB
  BEGIN
    LOOP
      -- ŏ̃bZ[Wv_MessageɃfL[Bő҂Ԃ1bB
      v_DequeueOptions.wait := 1;
      DBMS_AQ.DEQUEUE(
        queue_name => 'SimpleQ',
        dequeue_options => v_DequeueOptions,
        message_properties => v_MessageProperties,
        payload => v_Message,
        msgid => v_MsgID);

      -- o͂B
      v_Message.Print('After dequeue');
    END LOOP;
  EXCEPTION
    WHEN e_QTimeOut THEN
      -- L[̍Ō
      NULL;
  END;

  -- ׂẴfL[R~bgB
  COMMIT;
END;



After dequeue: Message 1
Data 1: 10 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 15-AUG-97
After dequeue: Message 2
Data 1: 20 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 16-AUG-97
After dequeue: Message 3
Data 1: 30 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 17-AUG-97
After dequeue: Message 4
Data 1: 40 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 18-AUG-97
After dequeue: Message 5
Data 1: 50 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 19-AUG-97
After dequeue: Message 6
Data 1: 60 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 20-AUG-97
After dequeue: Message 7
Data 1: 70 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 21-AUG-97
After dequeue: Message 8
Data 1: 80 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 22-AUG-97
After dequeue: Message 9
Data 1: 90 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 23-AUG-97
After dequeue: Message 10
Data 1: 100 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 24-AUG-97



-- Available online as clearq.sql
CREATE OR REPLACE PROCEDURE ClearQueue(p_QueueName IN VARCHAR2) AS
  v_Message MessageObj;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  -- fL[郁bZ[WȂȂ܂Ń[vB
  BEGIN
    LOOP
      -- ŏ̃bZ[Wv_MessageɃfL[Bő҂Ԃ1bB
      v_DequeueOptions.wait := 1;
      DBMS_AQ.DEQUEUE(
        queue_name => 'SimpleQ',
        dequeue_options => v_DequeueOptions,
        message_properties => v_MessageProperties,
        payload => v_Message,
        msgid => v_MsgID);
    END LOOP;
  EXCEPTION
    WHEN e_QTimeOut THEN
      -- L[̍Ō
      NULL;
  END;

  -- ׂẴfL[R~bgB
  COMMIT;
END;



-- Available online as priority.sql
DECLARE
  v_Message MessageObj;
  v_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);

  c_NumMessages CONSTANT INTEGER := 10;

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  FOR v_Counter IN 1..c_NumMessages LOOP
    -- GL[郁bZ[W쐬B
    v_Message :=
      MessageObj('Message ' || v_Counter, v_Counter * 10,
                 'zyxwvutsrqponmlkjihgfedcba', SYSDATE + v_Counter);

    -- -v_CounterɓD揇ʂŃGL[BāAŌɃGL[
    -- 郁bZ[WłD揇ʂbZ[WɂȂB
    v_MessageProperties.priority := -v_Counter;
    DBMS_AQ.ENQUEUE(
      queue_name => 'PriorityQ',
      enqueue_options => v_EnqueueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);
  END LOOP;

  -- ׂẴGL[R~bgB
  COMMIT;

  -- fL[郁bZ[WȂȂ܂Ń[vB
  BEGIN
    LOOP
      -- ŏ̃bZ[Wv_MessageɃfL[Bő҂Ԃ1bB
      v_DequeueOptions.wait := 1;
      DBMS_AQ.DEQUEUE(
        queue_name => 'PriorityQ',
        dequeue_options => v_DequeueOptions,
        message_properties => v_MessageProperties,
        payload => v_Message,
        msgid => v_MsgID);

      -- o͂B
      v_Message.Print('After dequeue');
    END LOOP;
  EXCEPTION
    WHEN e_QTimeOut THEN
      -- L[̍Ō
      NULL;
  END;

  -- ׂẴfL[R~bgB
  COMMIT;
END;



Data 1: 100 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 24-AUG-97
After dequeue: Message 9
Data 1: 90 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 23-AUG-97
After dequeue: Message 8
Data 1: 80 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 22-AUG-97
After dequeue: Message 7
Data 1: 70 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 21-AUG-97
After dequeue: Message 6
Data 1: 60 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 20-AUG-97
After dequeue: Message 5
Data 1: 50 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 19-AUG-97
After dequeue: Message 4
Data 1: 40 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 18-AUG-97
After dequeue: Message 3
Data 1: 30 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 17-AUG-97
After dequeue: Message 2
Data 1: 20 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 16-AUG-97
After dequeue: Message 1
Data 1: 10 Data 2: zyxwvutsrqponmlkjihgfedcba Data 3: 15-AUG-97



-- Available online as ident.sql
DECLARE
  v_Message MessageObj;
  v_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);
  v_TigerMsgID RAW(16);

  c_NumMessages CONSTANT INTEGER := 10;

  TYPE t_Correlations IS TABLE OF VARCHAR2(30)
    INDEX BY BINARY_INTEGER;
  v_Correlations t_Correlations;

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  -- ֎ʎq̔zB
  -- S5̈قȂ鑊֎ʎqA2̃bZ[WꂼɊlB
  FOR v_Counter IN 1..c_NumMessages LOOP
    IF MOD(v_Counter, 5) = 1 THEN
      v_Correlations(v_Counter) := 'Lion';
    ELSIF MOD(v_Counter, 5) = 2 THEN
      v_Correlations(v_Counter) := 'Tiger';
    ELSIF MOD(v_Counter, 5) = 3 THEN
      v_Correlations(v_Counter) := 'Bear';
    ELSIF MOD(v_Counter, 5) = 4 THEN
      v_Correlations(v_Counter) := 'Fish';
    ELSE
      v_Correlations(v_Counter) := 'Horse';
    END IF;
  END LOOP;

  FOR v_Counter IN 1..c_NumMessages LOOP
    -- GL[郁bZ[W쐬B
    v_Message :=
      MessageObj('Message ' || v_Counter, v_Counter * 10,
                 'abcdefghijklmnopqrstuvwxyz', SYSDATE + v_Counter);

    v_MessageProperties.correlation := v_Correlations(v_Counter);
    DBMS_OUTPUT.PUT_LINE('Enqueing message ' || v_Counter || 
      ' with correlation ID ' || v_Correlations(v_Counter));
    DBMS_AQ.ENQUEUE(
      queue_name => 'SimpleQ',
      enqueue_options => v_EnqueueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);

    -- tigerbZ[WID̂ꂩ1ۑB
    IF v_Correlations(v_Counter) = 'Tiger' THEN
      v_TigerMsgID := v_MsgID;
    END IF;
  END LOOP;

  -- ׂẴGL[R~bgB
  COMMIT;

  -- ID'Fish'̃bZ[WfL[B
  BEGIN
    LOOP
      -- ŏ̃bZ[Wv_MessageɃfL[Bő҂Ԃ1bB
      v_DequeueOptions.wait := 1;
      v_DequeueOptions.correlation := 'Fish';
      DBMS_AQ.DEQUEUE(
        queue_name => 'SimpleQ',
        dequeue_options => v_DequeueOptions,
        message_properties => v_MessageProperties,
        payload => v_Message,
        msgid => v_MsgID);

      -- o͂B
      v_Message.Print('After dequeue with correlation ID Fish');
    END LOOP;
  EXCEPTION
    WHEN e_QTimeOut THEN
      -- L[̍Ō
      NULL;
  END;

  -- ۑς݂̃bZ[WIDbZ[Ŵ݂fL[B
  v_DequeueOptions.correlation := NULL;
  v_DequeueOptions.msgid := v_TigerMsgID;
  DBMS_AQ.DEQUEUE(
    queue_name => 'SimpleQ',
    dequeue_options => v_DequeueOptions,
    message_properties => v_MessageProperties,
    payload => v_Message,
    msgid => v_MsgID);

  -- o͂B
  v_Message.Print('After dequeue with saved message ID');

  -- c̃bZ[WׂďB
  ClearQueue('SimpleQ');

  -- ׂẴfL[R~bgB
  COMMIT;
END;



Enqueing message 1 with correlation ID Lion
Enqueing message 2 with correlation ID Tiger
Enqueing message 3 with correlation ID Bear
Enqueing message 4 with correlation ID Fish
Enqueing message 5 with correlation ID Horse
Enqueing message 6 with correlation ID Lion
Enqueing message 7 with correlation ID Tiger
Enqueing message 8 with correlation ID Bear
Enqueing message 9 with correlation ID Fish
Enqueing message 10 with correlation ID Horse
After dequeue with correlation ID Fish: Message 4
Data 1: 40 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 18-AUG-97
After dequeue with correlation ID Fish: Message 9
Data 1: 90 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 23-AUG-97
After dequeue with saved message ID: Message 7
Data 1: 70 Data 2: abcdefghijklmnopqrstuvwxyz Data 3: 21-AUG-97



-- Available online as part of searchq.sql
CREATE OR REPLACE FUNCTION SearchQueue(
  /* L[āAp_MessageTitlebZ[W̍ŏ̃IJXTA
     ɂ̃IJX̃bZ[WIDԂBY郁bZ[WȂ΁ANULL
     ԂB */
  p_QueueName IN VARCHAR2,
  p_MessageTitle IN VARCHAR2)
  RETURN RAW AS

  v_Message MessageObj;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  -- fL[郁bZ[WȂȂ܂ŁA܂͖ړĨbZ[W܂Ń[vB
  BEGIN
    LOOP
      -- iBROWSE[hŁjŏ̃bZ[Wv_MessageɃfL[B
      -- ő҂Ԃ1bBQƂĂ邾Ȃ̂ŁAbZ[W̓L[폜ȂB
      v_DequeueOptions.wait := 1;
      v_DequeueOptions.dequeue_mode := DBMS_AQ.BROWSE;
      DBMS_AQ.DEQUEUE(
        queue_name => p_QueueName,
        dequeue_options => v_DequeueOptions,
        message_properties => v_MessageProperties,
        payload => v_Message,
        msgid => v_MsgID);

      -- bZ[W̃^Cg`FbNB
      IF v_Message.title = p_MessageTitle THEN
        -- Y郁bZ[W̂ŁAbZ[WIDԂB
        COMMIT;
        RETURN v_MsgID;
      END IF;
    END LOOP;
  EXCEPTION
    WHEN e_QTimeOut THEN
      -- L[̍Ō
      NULL;
  END;

  -- fL[ׂăR~bgāAY郁bZ[WȂƂNULLԂB
  COMMIT;
  RETURN NULL;
END;



-- Available online as part of searchq.sql
DECLARE
  v_Message MessageObj;
  v_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);

  c_NumMessages CONSTANT INTEGER := 10;

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  FOR v_Counter IN 1..c_NumMessages LOOP
    -- GL[郁bZ[W쐬B
    v_Message :=
      MessageObj('Message ' || v_Counter, v_Counter * 10,
                 'abcdefghijklmnopqrstuvwxyz', SYSDATE + v_Counter);

    -- ftHgIvVŃGL[B
    DBMS_AQ.ENQUEUE(
      queue_name => 'SimpleQ',
      enqueue_options => v_EnqueueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);
  END LOOP;

  -- ׂẴGL[R~bgB
  COMMIT;

  -- bZ[W4B
  v_MsgID := SearchQueue('SimpleQ', 'Message 4');

  -- AfL[ďo͂B
  IF v_MsgID IS NOT NULL THEN
    v_DequeueOptions.wait := 1;
    v_DequeueOptions.msgid := v_MsgID;
    DBMS_AQ.DEQUEUE(
      queue_name => 'SimpleQ',
      dequeue_options => v_DequeueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);
    v_Message.Print('After search');
  ELSE
    DBMS_OUTPUT.PUT_LINE('Message 4 not found');
  END IF;

  -- L[NAB
  ClearQueue('SimpleQ');
END;



-- Available online as except.sql
DECLARE
  v_Message MessageObj;
  v_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
  v_DequeueOptions DBMS_AQ.DEQUEUE_OPTIONS_T;
  v_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_MsgID RAW(16);
  v_NormalCount INTEGER;
  v_ExceptionCount INTEGER;

  c_NumMessages CONSTANT INTEGER := 3;

  e_QTimeOut EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_QTimeOut, -25228);
BEGIN
  -- OL[ݒ肵3̃bZ[WGL[B
  FOR v_Counter IN 1..c_NumMessages LOOP
    -- GL[郁bZ[W쐬B
    v_Message :=
      MessageObj('Message ' || v_Counter, v_Counter * 10,
                 'abcdefghijklmnopqrstuvwxyz', SYSDATE + v_Counter);

    -- bZ[WGL[B
    v_MessageProperties.exception_queue := 'ExceptionQ';
    DBMS_AQ.ENQUEUE(
      queue_name => 'SimpleQ',
      enqueue_options => v_EnqueueOptions,
      message_properties => v_MessageProperties,
      payload => v_Message,
      msgid => v_MsgID);
  END LOOP;

  -- ׂẴGL[R~bgB
  COMMIT;

  -- WL[3̃bZ[WĂāAOL[ɂ̓bZ[W
  -- ĂȂƂmFB
  SELECT COUNT(*)
    INTO v_NormalCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('Simpleq');
  SELECT COUNT(*)
    INTO v_ExceptionCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('ExceptionQ');
  DBMS_OUTPUT.PUT('After initial enqueues, count(simple) = ' || 
                  v_NormalCount);
  DBMS_OUTPUT.PUT_LINE(', count(exception) = ' || v_ExceptionCount);

  -- ŏ̃bZ[WfL[ĂA[obNBŁAfL[[obN
  -- AbZ[WvpeB̎s񐔃tB[h̉񐔂1񑝕BSimpleQ
  -- max_retries0Ȃ̂ŁAbZ[W͗OL[ɈڂB
  v_DequeueOptions.wait := 1;
  DBMS_AQ.DEQUEUE(
    queue_name => 'SimpleQ',
    dequeue_options => v_DequeueOptions,
    message_properties => v_MessageProperties,
    payload => v_Message,
    msgid => v_MsgID);

  ROLLBACK;

  -- WL[ɂ̓bZ[W2AOL[ɂ̓bZ[W1Ă邱Ƃ
  -- mFB
  SELECT COUNT(*)
    INTO v_NormalCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('Simpleq');
  SELECT COUNT(*)
    INTO v_ExceptionCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('ExceptionQ');
  DBMS_OUTPUT.PUT('After dequeue and rollback, count(simple) = ' ||
                  v_NormalCount);
  DBMS_OUTPUT.PUT_LINE(', count(exception) = ' || v_ExceptionCount);

  -- ŗOL[烁bZ[WlłB̃bZ[W̏ԂEXPIREDŁA
  -- fL[READYȊȌԂ̃bZ[W𕁒ʂ͕ԂȂ̂ŁAbZ[WIDgp
  -- Ȃ΂ȂȂƂɒӂB
  v_DequeueOptions.msgid := v_MsgID;
  DBMS_AQ.DEQUEUE(
    queue_name => 'ExceptionQ',
    dequeue_options => v_DequeueOptions,
    message_properties => v_MessageProperties,
    payload => v_Message,
    msgid => v_MsgID);
  v_Message.Print('After exception dequeuing');

  -- WL[ɂ̓bZ[W2AOL[ɂ̓bZ[WĂȂƂ
  -- mFB
  SELECT COUNT(*)
    INTO v_NormalCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('Simpleq');
  SELECT COUNT(*)
    INTO v_ExceptionCount
    FROM aq$SimpleQTab
    WHERE queue = UPPER('ExceptionQ');
  DBMS_OUTPUT.PUT('After exception dequeue, count(simple) = ' || 
                  v_NormalCount);
  DBMS_OUTPUT.PUT_LINE(', count(exception) = ' || v_ExceptionCount);

  -- L[NAāAR~bgB
  ClearQueue('SimpleQ');
  COMMIT;
END;



-- Available online as dropq.sql
BEGIN
  DBMS_AQADM.STOP_QUEUE('SimpleQ');
  DBMS_AQADM.DROP_QUEUE('SimpleQ');
  DBMS_AQADM.STOP_QUEUE('ExceptionQ');
  DBMS_AQADM.DROP_QUEUE('ExceptionQ');
  DBMS_AQADM.DROP_QUEUE_TABLE('SimpleQTab');
END;

BEGIN
  DBMS_AQADM.STOP_QUEUE('PriorityQ');
  DBMS_AQADM.DROP_QUEUE('PriorityQ');
  DBMS_AQADM.DROP_QUEUE_TABLE('PriorityQTab');
END;

DROP TYPE MessageObj;



Chapter 18
-- Available online as tmpins.sql
CREATE SEQUENCE temp_seq
  START WITH 1
  INCREMENT BY 1;

CREATE OR REPLACE PROCEDURE TempInsert AS
BEGIN
    INSERT INTO temp_table (num_col, char_col)
      VALUES (temp_seq.nextval, TO_CHAR(SYSDATE,
              'DD-MON-YY HH24:MI:SS'));
    COMMIT;
END TempInsert;



-- Available online as part of tmpins.sql
SQL> VARIABLE v_JobNum NUMBER
SQL> BEGIN
  2    DBMS_JOB.SUBMIT(:v_JobNum, 'TempInsert;', SYSDATE,
  3                    'sysdate + (10/(24*60*60))');
  4  END;
  5  /

PL/SQL procedure successfully completed.
SQL> print v_JobNum

 V_JOBNUM
---------
        2



-- Available online as tmpins1.sql
CREATE OR REPLACE PROCEDURE TempInsert
  (p_NextDate IN OUT DATE) AS
  v_SeqNum   NUMBER;
  v_StartNum NUMBER;
  v_SQLCode NUMBER;
  v_Errmsg  VARCHAR2(60);
BEGIN
  SELECT temp_seq.nextval
    INTO v_SeqNum
    FROM dual;
  -- ͂߂ẴR[̏ꍇ
  BEGIN
    SELECT num_col
      INTO v_StartNum
      FROM temp_table
      WHERE char_col = 'TempInsert Start';

    -- ȑOɃR[Ă̂ŁAVl}B
    INSERT INTO temp_table (num_col, char_col)
      VALUES (v_SeqNum, TO_CHAR(SYSDATE, 'DD-MON-YY HH24:MI:SS'));
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- ͂߂ẴR[Ȃ̂ő}B
      INSERT INTO temp_table (num_col, char_col)
        VALUES (v_SeqNum, 'TempInsert Start');
  END;

  -- 15𒴂R[ꍇ͏IB
  IF v_SeqNum - V_StartNum > 15 THEN
    p_NextDate := NULL;
  END IF;

  COMMIT;
END TempInsert;



BEGIN
  DBMS_JOB.SUBMIT(:v_JobNum, 'TempInsert(next_date);', sysdate,
                  'sysdate + (5/(24*60*60))');
END;



'Register(10006, ''MUS'', 410);'



UTL_FILE_DIR = /tmp
UTL_FILE_DIR = /home/oracle/output_files



UTL_FILE_DIR = *



DECLARE
  v_OutputFile UTL_FILE.FILE_TYPE;
  v_Name VARCHAR2(10) := 'Scott';
BEGIN
  v_OutputFile := UTL_FILE.FOPEN(...);
  UTL_FILE.PUTF(v_OutputFile,
    'Hi there!\nMy name is %s, and I am a %s major.\n',
    v_Name, 'Computer Science');
  FCLOSE(v_OutputFile);
END;



Hi There!
My name is Scott, and I am a Computer Science major.



-- Available online as debug.sql
CREATE OR REPLACE PACKAGE Debug AS

  /* fobNp̃t@C̖OƃfBgNi[邽߂̃O[oϐ */
  v_DebugDir VARCHAR2(50);
  v_DebugFile VARCHAR2(20);

  PROCEDURE Debug(p_Description IN VARCHAR2,
                  p_Value IN VARCHAR2);

  PROCEDURE Reset(p_NewFile IN VARCHAR2 := v_DebugFile,
                  p_NewDir IN VARCHAR2 := v_DebugDir) ;

  /* fobNp̃t@CN[YB */
  PROCEDURE Close;
END Debug;
/

CREATE OR REPLACE PACKAGE BODY Debug AS
  v_DebugHandle UTL_FILE.FILE_TYPE;

  PROCEDURE Debug(p_Description IN VARCHAR2,
                  p_Value IN VARCHAR2) IS
  BEGIN
    /* o͂At@CtbVB */
    UTL_FILE.PUTF(v_DebugHandle, '%s: %s\n', p_Description, p_Value);
    UTL_FILE.FFLUSH(v_DebugHandle);
  EXCEPTION
    WHEN UTL_FILE.INVALID_OPERATION THEN
      RAISE_APPLICATION_ERROR(-20102,
                              'Debug: Invalid Operation');
    WHEN UTL_FILE.INVALID_FILEHANDLE THEN
      RAISE_APPLICATION_ERROR(-20103,
                              'Debug: Invalid File Handle');
    WHEN UTL_FILE.WRITE_ERROR THEN
      RAISE_APPLICATION_ERROR(-20104,
                              'Debug: Write Error');
  END Debug;

  PROCEDURE Reset(p_NewFile IN VARCHAR2 := v_DebugFile,
                  p_NewDir IN VARCHAR2 := v_DebugDir) IS
  BEGIN

    /* t@CN[YĂ邩A܂`FbNB */
    IF UTL_FILE.IS_OPEN(v_DebugHandle) THEN
      UTL_FILE.FCLOSE(v_DebugHandle);
    END IF;

    /* ݗp̃t@CI[vB */
    v_DebugHandle := UTL_FILE.FOPEN(p_NewDir, p_NewFile, 'w');

    /* Anꂽ΂̒lpbP[Wϐɐݒ肷B */
    v_DebugFile := p_NewFile;
    v_DebugDir := p_NewDir;
  EXCEPTION
    WHEN UTL_FILE.INVALID_PATH THEN
      RAISE_APPLICATION_ERROR(-20100, 'Reset: Invalid Path');
    WHEN UTL_FILE.INVALID_MODE THEN
      RAISE_APPLICATION_ERROR(-20101, 'Reset: Invalid Mode');
    WHEN UTL_FILE.INVALID_OPERATION THEN
      RAISE_APPLICATION_ERROR(-20101, 'Reset: Invalid Operation');
  END Reset;

  PROCEDURE Close IS
  BEGIN
    UTL_FILE.FCLOSE(v_DebugHandle);
  END Close;

BEGIN
  v_DebugDir := '/tmp';
  v_DebugFile := 'debug.out';
  Reset;
END Debug; 



-- Available online as loadstud.sql
CREATE OR REPLACE PROCEDURE LoadStudents (
  /* J}؂t@Cǂݍ݁A\studentsɃ[hB
     Yt@Cɂ́Â悤ȍsi[Ă̂ƂB

     first_name, last_name, major

     wID́Astudent_sequence琶B
     ܂A}s̑́Ap_TotalInsertedԂB */
  p_FileDir  IN VARCHAR2,
  p_FileName IN VARCHAR2,
  p_TotalInserted IN OUT NUMBER) AS

  v_FileHandle UTL_FILE.FILE_TYPE;
  v_NewLine  VARCHAR2(100);  -- Input line
  v_FirstName students.first_name%TYPE;
  v_LastName students.last_name%TYPE;
  v_Major students.major%TYPE;
  /* ͍sł̃J}̈ʒu */
  v_FirstComma NUMBER;
  v_SecondComma NUMBER;

BEGIN
  -- w肳ꂽt@CAǂݍݗpɃI[vB
  v_FileHandle := UTL_FILE.FOPEN(p_FileDir, p_FileName, 'r');

  -- w̏o͐B
  p_TotalInserted := 0;

  -- Yt@CŜA[vłPsǂݍށB
  -- ǂݍ݂ƁAGET_LINENO_DATA_FOUNDʒmB
  -- ̂߁A̓[v̏IƂĎgB
  LOOP
    BEGIN
      UTL_FILE.GET_LINE(v_FileHandle, v_NewLine);
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        EXIT;
    END;

    -- ̓R[h̊etB[h́AJ}ŋ؂Ă
    -- ͓̂Q̃J}̈ʒu𒲂ׁÄʒugp
    -- v_NewLineYtB[h擾KvB
    -- J}̈ʒúAINSTRgpĒׂB
    v_FirstComma := INSTR(v_NewLine, ',', 1, 1);
    v_SecondComma := INSTR(v_NewLine, ',', 1, 2);

    -- ܂ł΁ASUBSTRɂĈÃtB[h𒊏oł
    v_FirstName := SUBSTR(v_NewLine, 1, v_FirstComma - 1);
    v_LastName := SUBSTR(v_NewLine, v_FirstComma + 1,
                         v_SecondComma - v_FirstComma - 1);
    v_Major := SUBSTR(v_NewLine, v_SecondComma + 1);

    -- studentsɐVR[hP}B
    INSERT INTO students (ID, first_name, last_name, major)
      VALUES (student_sequence.nextval, v_FirstName,
              v_LastName, v_Major);

    p_TotalInserted := p_TotalInserted + 1;
  END LOOP;

  -- t@CN[YB
  UTL_FILE.FCLOSE(v_FileHandle);

  COMMIT;
EXCEPTION
  -- UTL_FILËA̗OӖʂɏAYt@CN[Y
  -- Ă邩`FbNB
  WHEN UTL_FILE.INVALID_OPERATION THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20051,
                            'LoadStudents: Invalid Operation');
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20052,
                            'LoadStudents: Invalid File Handle');
  WHEN UTL_FILE.READ_ERROR THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20053,
                            'LoadStudents: Read Error');
  WHEN OTHERS THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE;
END LoadStudents; 



Scott,Smith,Computer Science
Margaret,Mason,History
Joanne,Junebug,Computer Science
Manish,Murgratroid,Economics
Patrick,Poll,History
Timothy,Taller,History
Barbara,Blues,Economics
David,Dinsmore,Music
Ester,Elegant,Nutrition
Rose,Riznit,Music
Rita,Razmataz,Nutrition



-- Available online as calcGPA.sql
CREATE OR REPLACE PROCEDURE CalculateGPA (
  /* p_StudentIDŎw肳ꂽwGPAp_GPAɕԂB */
  p_StudentID IN students.ID%TYPE,
  p_GPA OUT NUMBER) AS

  CURSOR c_ClassDetails IS
    SELECT classes.num_credits, rs.grade
      FROM classes, registered_students rs
      WHERE classes.department = rs.department
      AND classes.course = rs.course
      AND rs.student_id = p_StudentID;

  v_NumericGrade NUMBER;
  v_TotalCredits NUMBER := 0;
  v_TotalGrade NUMBER := 0;

BEGIN
  FOR v_ClassRecord in c_ClassDetails LOOP
    -- тɊY鐔l𒲂ׂB
    SELECT DECODE(v_ClassRecord.grade, 'A', 4,
                                       'B', 3,
                                       'C', 2,
                                       'D', 1,
                                       'E', 0)
      INTO v_NumericGrade
      FROM dual;

    v_TotalCredits := v_TotalCredits + v_ClassRecord.num_credits;
    v_TotalGrade := v_TotalGrade +
                    (v_ClassRecord.num_credits * v_NumericGrade);
  END LOOP;

  p_GPA := v_TotalGrade / v_TotalCredits;
END CalculateGPA; 



-- Available online as printran.sql
CREATE OR REPLACE PROCEDURE PrintTranscript (
  /* w肳ꂽw̐яؖo͂Bяؖ́A
     wݓo^ĂÃNXƂ̊eNX
     т\B܂Aя̖ؖɂ́A
     ̊wGPAo͂B */
  p_StudentID IN students.ID%TYPE,
  p_FileDir IN VARCHAR2,
  p_FileName IN VARCHAR2) AS

  v_StudentGPA NUMBER;
  v_StudentRecord  students%ROWTYPE;
  v_FileHandle UTL_FILE.FILE_TYPE;
  v_NumCredits NUMBER;

  CURSOR c_CurrentClasses IS
    SELECT *
      FROM registered_students
      WHERE student_id = p_StudentID;

BEGIN
  -- o̓t@Cǉ(append)[hŃI[vB
  v_FileHandle := UTL_FILE.FOPEN(p_FileDir, p_FileName, 'w');

  SELECT *
    INTO v_StudentRecord
    FROM students
    WHERE ID = p_StudentID;

  -- wb_[o͂Bwb_[́A݂̓tƎA
  -- Yw̏񂩂\B

  UTL_FILE.PUTF(v_FileHandle, 'Student ID: %s\n',
    v_StudentRecord.ID);
  UTL_FILE.PUTF(v_FileHandle, 'Student Name: %s %s\n',
    v_StudentRecord.first_name, v_StudentRecord.last_name);
  UTL_FILE.PUTF(v_FileHandle, 'Major: %s\n',
    v_StudentRecord.major);
  UTL_FILE.PUTF(v_FileHandle, 'Transcript Printed on: %s\n\n\n',
    TO_CHAR(SYSDATE, 'Mon DD,YYYY HH24:MI:SS'));

  UTL_FILE.PUT_LINE(v_FileHandle, 'Class   Credits Grade');
  UTL_FILE.PUT_LINE(v_FileHandle, '------- ------- -----');
  FOR v_ClassesRecord in c_CurrentClasses LOOP
    -- YNX̒Pʐ𒲂ׂB
    SELECT num_credits
      INTO v_NumCredits
      FROM classes
      WHERE course = v_ClassesRecord.course
      AND department = v_ClassesRecord.department;

    -- YNX̏o͂B
    UTL_FILE.PUTF(v_FileHandle, '%s %s %s\n',
      RPAD(v_ClassesRecord.department || ' '  ||
           v_ClassesRecord.course, 7),
      LPAD(v_NumCredits, 7),
      LPAD(v_ClassesRecord.grade, 5));
  END LOOP;

  -- GPA߂B
  CalculateGPA(p_StudentID, v_StudentGPA);

  -- GPAo͂B
  UTL_FILE.PUTF(v_FileHandle, '\n\nCurrent GPA: %s\n',
    TO_CHAR(v_StudentGPA, '9.99'));

  -- Yt@CN[YB
  UTL_FILE.FCLOSE(v_FileHandle);

EXCEPTION
  -- UTL_FILËA̗OӖʂ̏AYt@CN[Y
  -- Ă邩`FbNB
  WHEN UTL_FILE.INVALID_OPERATION THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20061,
                            'PrintTranscript: Invalid Operation');
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20062,
                            'PrintTranscript: Invalid File Handle');
  WHEN UTL_FILE.WRITE_ERROR THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE_APPLICATION_ERROR(-20063,
                            'PrintTranscript: Write Error');
  WHEN OTHERS THEN
    UTL_FILE.FCLOSE(v_FileHandle);
    RAISE;
END PrintTranscript; 



SQL> select * from registered_students;
STUDENT_ID DEP     COURSE G
---------- --- ---------- -
     10002 CS         102 B
     10002 HIS        101 B
     10002 ECN        203 A
     10002 CS         101 A
     10009 HIS        101 D
     10009 MUS        410 B
     10009 HIS        301 C
     10009 MUS        410 B

8 rows selected.



Student ID: 10002
Student Name: Joanne Junebug
Major: Computer Science
Transcript Printed on: Jan 27,1996 17:37:43


Class   Credits Grade
------- ------- -----
CS  102       4     B
IS  101       4     B
ECN 203       3     A
CS  101       4     A


Current GPA:  3.47

Student ID: 10009
Student Name: Rose Riznit
Major: Music
Transcript Printed on: Jan 27,1996 17:38:56


Class   Credits Grade
------- ------- -----
HIS 101       4     D
MUS 410       3     B
HIS 301       4     C
MUS 410       3     B


Current GPA:  2.14



Chapter 19
-- Available online as hello.sql
CREATE OR REPLACE PROCEDURE hello(p_Greeting IN VARCHAR2) AS
BEGIN
  HTP.htmlOpen;
  HTP.headOpen;
  HTP.Title('Hello World!');
  HTP.headClose;
  HTP.bodyOpen;
  HTP.print(p_Greeting);
  HTP.bodyClose;
  HTP.htmlClose;
END hello;



http://host:port/example/owa/hello?p_Greeting=Welcome!



<HTML>
<HEAD>
<TITLE>Hello World!</TITLE>
</HEAD>
<BODY>
Welcome!
</BODY>
</HTML>



-- Available online as prntdemo.sql
CREATE OR REPLACE PROCEDURE PrintDemo AS
BEGIN
  -- ̃vV[ẂAPRINTgpĂׂĂHTMLo͂܂B
  -- HTPHTFpbP[Wɂ́Aقړ@\sł郆[eBeBvV[W
  -- ܂܂Ă܂B
  HTP.print('<HTML>');
  HTP.print('This is a demonstration of the ');
  HTP.print('<STRONG>HTP.print</STRONG> procedure. It can be ');
  HTP.print('used to output additional tags that are not in ');
  HTP.print('HTP and HTF, such as the ');
  HTP.print('<BLINK>BLINK</BLINK> tag.');
  OWA_UTIL.signature('PrintDemo');
  HTP.print('</HTML>);
END PrintDemo;



<HTML>
This is a demonstration of the 
<STRONG>HTP.print</STRONG> procedure. It can be 
used to output additional tags that are not in 
HTP and HTF, such as the 
<BLINK>BLINK</BLINK> tag.
</HTML>



-- Available online as bodydemo.sql
CREATE OR REPLACE PROCEDURE BodyDemo AS
BEGIN
  HTP.htmlOpen;
  HTP.headOpen;
  HTP.title('Body tags demo');
  HTP.headClose;

  HTP.bodyOpen;
  HTP.print('This page demonstrates several of the tags ');
  HTP.print('available for formatting the text in the body ');
  HTP.print('of a web page, and for inserting additional ');
  HTP.print('tags.' || HTF.para);

  HTP.header(2, 'Links');
  HTP.print('Here are some links to check out.  These are ');
  HTP.print('generated using the HTP.anchor procedure.');
  HTP.para;
  HTP.anchor('//www.oracle.com/', 'Oracle Corporation');
  HTP.para;
  HTP.anchor('//www.osborne.com/oracle/index.htm', 
             'Oracle Press');
  HTP.para;
  HTP.anchor('//www.platinum.com/', 'Platinum Corporation');
  HTP.para;

  HTP.header(2, 'Formats');
  HTP.print(HTF.centerOpen || 'These lines are centered, using ');
  HTP.br;
  HTP.print('the HTF.centerOpen and HTF.centerClose functions.');
  HTP.centerClose;

  HTP.strike('Here''s some strikethrough text.');
  OWA_UTIL.signature('BodyDemo')
  HTP.bodyClose;
  HTP.htmlClose;
END BodyDemo;



<HTML>
<HEAD>
<TITLE>Body tags demo</TITLE>
</HEAD>
<BODY>
This page demonstrates several of the tags 
available for formatting the text in the body 
of a web page, and for inserting additional 
tags.<P>
<H2>Links</H2>
Here are some links to check out.  These are
generated using the HTP.anchor procedure.
<P>
<A HREF="//www.oracle.com/">Oracle Corporation</A>
<P>
<A HREF="//www.osborne.com/oracle/index.htm">Oracle Press</A>
<P>
<A HREF="//www.platinum.com/">Platinum Corporation</A>
<P>
<H2>Formats</H2>
<CENTER>These lines are centered, using 
<BR>
the HTF.centerOpen and HTF.centerClose functions.
</CENTER>
<STRIKE>Here's some strikethrough text.</STRIKE>
</BODY>
</HTML>



-- Available online as listdemo.sql
CREATE OR REPLACE PACKAGE ListDemo AS
  PROCEDURE Go;
  PROCEDURE ShowList(p_ListType IN CHAR);
END ListDemo;

CREATE OR REPLACE PACKAGE BODY ListDemo AS
  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  -- [U[Ɏgp\ȃXg̃^Cv\B
  PROCEDURE ShowChoices IS
    c_ListPath VARCHAR2(100) :=
      c_OWAPATH || 'ListDemo.ShowList?p_ListType=';
  BEGIN
    HTP.line;
    HTP.p('Click on any of the following links to see the ');
    HTP.p('students in the specified list type.' || HTF.para);

    HTP.anchor(c_ListPath || 'U', 'Unordered');
    HTP.anchor(c_ListPath || 'O', 'Ordered');
    HTP.anchor(c_ListPath || 'M', 'Menu');
    HTP.anchor(c_ListPath || 'D', 'Directory');
  END ShowChoices;

  -- w肳ꂽXg^CvŃt@[Xgl[ƃXgl[\B
  PROCEDURE ShowList(p_ListType IN CHAR) IS
    v_Title VARCHAR2(20);
    v_ListOpen VARCHAR2(10);
    v_ListClose VARCHAR2(10);
    CURSOR c_Names IS
      SELECT first_name || ' ' || last_name name
        FROM students
        ORDER BY last_name;
  BEGIN
    IF p_ListType = 'U' THEN
      v_Title := 'Unordered List';
      v_ListOpen := HTF.ulistOpen;
      v_ListClose := HTF.ulistClose;
    ELSIF p_ListType = 'O' THEN
      v_Title := 'Ordered List';
      v_ListOpen := HTF.olistOpen;
      v_ListClose := HTF.olistClose;
    ELSIF p_ListType = 'M' THEN
      v_Title := 'Menu List';
      v_ListOpen := HTF.menulistOpen;
      v_ListClose := HTF.menulistClose;
    ELSIF p_ListType = 'D' THEN
      v_Title := 'Directory List';
      v_ListOpen := HTF.dirlistOpen;
      v_ListClose := HTF.dirlistClose;
    END IF;
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title(v_Title);
    HTP.headClose;

    HTP.bodyOpen;
    -- Xgo͂B
    HTP.p(v_ListOpen);
    FOR v_NamesRec IN c_Names LOOP
      HTP.listItem(v_NamesRec.name);
    END LOOP;
    HTP.p(v_ListClose);

    -- Io͂B
    ShowChoices;

    OWA_UTIL.signature('ListDemo.ShowList');
    HTP.bodyClose;
  END ShowList;

  PROCEDURE Go IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('List Demo');
    HTP.headClose;

    HTP.bodyOpen;
    HTP.header(2, 'Welcome to the list demo');
    ShowChoices;
    OWA_UTIL.signature('ListDemo.Go');
    HTP.bodyClose;
    HTP.htmlClose;
  END Go;
END ListDemo;



CREATE OR REPLACE PROCEDURE CharDemo AS
BEGIN
  HTP.htmlOpen;
  HTP.headOpen;
  HTP.title('Character Formatting Tags');
  HTP.headClose;

  HTP.bodyOpen;
  HTP.header(2, 'This page demonstrates character formatting
                 tags.');
  HTP.para;
  HTP.cite('This text is a citation, usually rendered as
            italics.');
  HTP.para;
  HTP.code('This text is code, usually rendered as a monospace
            font.');
  HTP.para;
  HTP.strong('This text is strong, usually rendered as bold.');
  HTP.para;

  OWA_UTIL.signature('CharDemo');
  HTP.bodyClose;
  HTP.htmlClose;
END CharDemo;



-- Available online as formdemo.sql
CREATE OR REPLACE PACKAGE FormDemo AS
  PROCEDURE Go;
  PROCEDURE Process(p_Checkbox IN VARCHAR2 DEFAULT 'off',
                    p_Password IN VARCHAR2 DEFAULT NULL,
                    p_Radio IN VARCHAR2 DEFAULT NULL);
END FormDemo;

CREATE OR REPLACE PACKAGE BODY FormDemo AS
  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  PROCEDURE ShowForm IS
  BEGIN
    HTP.line;
    -- ܂A^[QbgURLƂProcessvV[Ww肵āAtH[JB
    HTP.formOpen(curl => c_OWAPath || 'FormDemo.Process');

    -- ɂ̃eLXgƓ̓foCXo͂B
    HTP.p('Welcome to a HTML form.  Fill out some information'):
    HTP.p('below, and press the ''Submit'' button to process it.');
    HTP.p('Press ''Reset'' to clear your entries.');
    HTP.para;

    HTP.p('Here is a checkbox: ');
    HTP.formCheckbox(cname => 'p_CheckBox');
    HTP.para;
    HTP.p('Here is a password entry: ');
    HTP.formPassword(cname => 'p_Password',
                     csize => 10);
    HTP.para;
    HTP.p('Select one of the following radio buttons:');
    HTP.nl;
    HTP.formRadio(cname => 'p_Radio', cvalue => 'One');
    HTP.p('One');
    HTP.formRadio(cname => 'p_Radio', cvalue => 'Two');
    HTP.p('Two');
    HTP.formRadio(cname => 'p_Radio', cvalue => 'Three');
    HTP.p('Three' || HTF.nl);
    HTP.formRadio(cname => 'p_Radio', cvalue => 'Four');
    HTP.p('Four');
    HTP.formRadio(cname => 'p_Radio', cvalue => 'Five');
    HTP.p('Five' || HTF.para);
    HTP.formSubmit;
    HTP.formReset;
    HTP.formClose;
  END ShowForm;

  PROCEDURE Process(p_Checkbox IN VARCHAR2 DEFAULT 'off',
                    p_Password IN VARCHAR2 DEFAULT NULL,
                    p_Radio IN VARCHAR2 DEFAULT NULL) IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Form Results');
    HTP.headClose;

    HTP.bodyOpen;
    HTP.header(2, 'Form Results:');
    HTP.p('p_Checkbox = ' || p_Checkbox || HTF.nl);
    HTP.p('p_Password = ' || p_Password || HTF.nl);
    HTP.p('p_Radio = ' || p_Radio || HTF.para);
    ShowForm;
    OWA_UTIL.signature('FormDemo.Process');
    HTP.bodyClose;
    HTP.htmlClose;
  END Process;

  PROCEDURE Go IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Forms Demo');
    HTP.headClose;
    HTP.bodyOpen;
    ShowForm;
    OWA_UTIL.signature('FormDemo.Go');
    HTP.bodyClose;
    HTP.htmlClose;
  END Go;
END FormDemo;



-- Available online as tabldemo.sql
CREATE OR REPLACE PROCEDURE TableDemo AS
  CURSOR c_Students IS
    SELECT *
      FROM students
      ORDER BY ID;
BEGIN
  HTP.htmlOpen;
  HTP.headOpen;
  HTP.title('Table Demo');
  HTP.headClose;

  HTP.bodyOpen;
  HTP.tableOpen(cborder => 'BORDER=1');

  -- studentsiwj[vāAo͂Ƃ2̍ŝ悤ɕ\B
  -- +--------------------------------+
  -- |    |   first_name last_name    |
  -- | ID +---------+-----------------+
  -- |    | major   | current_credits |
  -- +----+---------+-----------------+
  FOR v_StudentRec in c_Students LOOP
    HTP.tableRowOpen;
    HTP.tableData(crowspan => 2,
                  cvalue => HTF.bold(v_StudentRec.ID));
    HTP.tableData(ccolspan => 2,
                  calign => 'CENTER',
                  cvalue => v_StudentRec.first_name || ' ' ||
                            v_StudentRec.last_name);
    HTP.tableRowClose;
    HTP.tableRowOpen;
    HTP.tableData(cvalue => 'Major: ' || v_StudentRec.major);
    HTP.tableData(cvalue => 'Credits: ' || 
                              v_StudentRec.current_credits);
    HTP.tableRowClose;
  END LOOP;

  HTP.tableClose;
  OWA_UTIL.signature('TableDemo');
  HTP.bodyClose;
  HTP.htmlClose;
END TableDemo;



-- Available online as utildemo.sql
CREATE OR REPLACE PROCEDURE UtilDemo AS
  v_Temp BOOLEAN;
BEGIN
  HTP.htmlOpen;
  HTP.headOpen;
  HTP.title('OWA_UTIL HTML Demos');
  HTP.headClose;

  HTP.bodyOpen;
  HTP.p('This page demonstrates several of the HTML utilities ');
  HTP.p('in the OWA_UTIL package.' || HTF.para);

  HTP.header(2, 'print_cgi_env');
  HTP.p('The following is generated by ');
  HTP.bold('OWA_UTIL.print_cgi_env');
  HTP.p(':' || HTF.nl);
  OWA_UTIL.print_cgi_env;

  HTP.header(2, 'get_owa_service_path');
  HTP.p('The following is generated by ');
  HTP.bold('OWA_UTIL.get_owa_service_path');
  HTP.p(':' || HTF.nl);
  HTP.p(OWA_UTIL.get_owa_service_path);

  HTP.header(2, 'tableprint');
  HTP.p('The following table (containing information from ');
  HTP.p('registered_students) is generated by ');
  HTP.bold('OWA_UTIL.tableprint');
  HTP.p(':' || HTF.nl);
  v_Temp := OWA_UTIL.tableprint(
              ctable => 'registered_students',
              cattributes => 'BORDER=1',
              ntable_type => OWA_UTIL.html_table,
              cclauses => 'ORDER BY student_id');

  HTP.p('Here is the same data, as a preformatted table instead:');
  HTP.nl;
  v_Temp := OWA_UTIL.tableprint(
              ctable => 'registered_students',
              cattributes => 'BORDER=1',
              ntable_type => OWA_UTIL.pre_table,
              cclauses => 'ORDER BY student_id');

  OWA_UTIL.signature('UtilDemo');
  HTP.bodyClose;
END UtilDemo;



-- Available online as dyndemo.sql
CREATE OR REPLACE PACKAGE DynamicDemo AS
  PROCEDURE Go;
  PROCEDURE Process(p_Query IN VARCHAR2 DEFAULT NULL,
                    p_Type IN VARCHAR2);
  PROCEDURE ListProcess(p_Value IN VARCHAR2 DEFAULT NULL);
END DynamicDemo;

CREATE OR REPLACE PACKAGE BODY DynamicDemo AS
  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  PROCEDURE ShowForm IS
  BEGIN
    HTP.line;
    HTP.p('Enter a query in the box below, and select the ');
    HTP.p('output type, then click ''Submit''.  If you choose ');
    HTP.p('the picklist, then your query should be of the ');
    HTP.p('following form: ');
    HTP.nl;
    HTP.p('Column 1: Result returned for this item' || HTF.nl);
    HTP.p('Column 2: String displayed for this item' || HTF.nl);
    HTP.p('Column 3: NULL or non-NULL.  If non-NULL, the ');
    HTP.p('current field will be flagged as selected.');
    HTP.para;
    -- ܂A^[QbgURLƂProcessvV[Ww肵āAtH[JB
    HTP.formOpen(curl => c_OWAPath || 'DynamicDemo.Process');
    HTP.formTextArea(cname => 'p_Query',
                     nrows => 5,
                     ncolumns => 40);
    HTP.nl;
    HTP.p('Output type: ');
    HTP.p('HTML Table');
    HTP.formRadio(cname => 'p_Type',
                  cvalue => 'table',
                  cchecked => 'CHECKED');
    HTP.p('Picklist');
    HTP.formRadio(cname => 'p_Type',
                  cvalue => 'list');
    HTP.formSubmit;
  END ShowForm;

  /* CGgvV[W */
  PROCEDURE Go IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('OWA_UTIL Dynamic SQL Utilities Demo');
    HTP.headClose;

    HTP.bodyOpen;
    ShowForm;
    OWA_UTIL.signature('DynamicDemo.Go');
    HTP.bodyClose;
    HTP.htmlClose;
  END Go;

  /* CtH[B */
  PROCEDURE Process(p_Query IN VARCHAR2 DEFAULT NULL,
                    p_Type IN VARCHAR2) IS
    v_CursorID INTEGER;
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Query Results');
    HTP.headClose;

    HTP.bodyOpen;
    v_CursorID := OWA_UTIL.bind_variables(p_Query);
    HTP.p('Output from query ');
    HTP.bold(p_Query);
    HTP.p(':' || HTF.para);
    IF p_Type = 'table' THEN
      HTP.tableOpen(cborder => 'BORDER=1');
      OWA_UTIL.cellsprint(v_CursorID);
      HTP.tableClose;
    ELSE
      HTP.formOpen(curl => c_OWAPath || 'DynamicDemo.ListProcess');
      OWA_UTIL.listprint(v_CursorID, 'p_Value', 10);
      HTP.formSubmit;
      HTP.formClose;
    END IF;
    ShowForm;
   OWA_UTIL.signature('DynamicDemo.Process');
    HTP.bodyClose;
    HTP.htmlClose;
  END Process;

  /* sbNXgtH[B */
  PROCEDURE ListProcess(p_Value IN VARCHAR2 DEFAULT NULL) IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('List Results');
    HTP.headClose;

    HTP.bodyOpen;
    HTP.p('You picked ' || p_Value || '.');
    ShowForm;
    OWA_UTIL.signature('DynamicDemo.ListProcess');
    HTP.bodyClose;
    HTP.htmlClose;
  END ListProcess;
END DynamicDemo;



-- Available online as part of datedemo.sql
CREATE TABLE calendar (
  today        DATE,
  description  VARCHAR2(25),
  link         VARCHAR2(20)
  );

INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE - 5, 'Hello!', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE - 4, 'Getting there...', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE - 3, 'How''s it going?', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE - 2, 'Soon...', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE - 1, 'Tomorrow, tomorrow', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE, 'Made it!', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE + 1, 'Did you miss it?', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE + 2, 'Sure hope not...', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE + 3, 'It was pretty cool', '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE + 4, 'Better luck next year',                             '//www.oracle.com');
INSERT INTO calendar (today, description, link)
  VALUES (SYSDATE + 5, 'Goodbye!', '//www.oracle.com');



-- Available online as datedemo.sql
CREATE OR REPLACE PACKAGE DateDemo AS
  PROCEDURE Go;
  PROCEDURE Process(p_DateVal IN OWA_UTIL.dateType);
END DateDemo;

CREATE OR REPLACE PACKAGE BODY DateDemo AS
  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  -- Iꂽt󂯎B
  PROCEDURE Process(p_DateVal IN OWA_UTIL.dateType) IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Results');
    HTP.headClose;
    HTP.bodyOpen;
    HTP.p('You picked ');
    HTP.p(TO_CHAR(OWA_UTIL.todate(p_DateVal)));
    HTP.nl;
    OWA_UTIL.signature('DateDemo.Process');
    HTP.bodyClose;
    HTP.htmlClose;
  END Process;

  -- CGgvV[W
  PROCEDURE Go IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('OWA_UTIL Date Utilities');
    HTP.headClose;

    HTP.bodyOpen;
    HTP.p('Welcome to the Date demo.  Here''s a calendar, ');
    HTP.p('created with ' || HTF.bold('OWA_UTIL.calendarprint'));
    HTP.p(':' || HTF.nl);
    OWA_UTIL.calendarprint(
      'SELECT * FROM calendar ORDER BY today');

    HTP.para;
    HTP.p('Enter a year, month, and day below, and then press');
    HTP.p(' submit:' || HTF.nl);
    HTP.formOpen(curl => c_OWAPath || 'DateDemo.Process');
    OWA_UTIL.choose_date(p_name => 'p_DateVal');
    HTP.formSubmit;
    HTP.formClose;
    OWA_UTIL.signature('DateDemo.Go');
    HTP.bodyClose;
    HTP.htmlClose;
  END Go;
END DateDemo;



-- Available online as imagemap.sql
CREATE OR REPLACE PACKAGE Imagemap AS
  PROCEDURE Go;
  PROCEDURE Process(p_Img IN OWA_IMAGE.POINT);
END Imagemap;

CREATE OR REPLACE PACKAGE BODY Imagemap AS
  -- c_ImagePathAboxes.gift@Ci[ĂT[o[̉zpXɐݒ肷B
  c_ImagePath CONSTANT VARCHAR2(50) := '/ows-img/boxes.gif';

  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  PROCEDURE ShowBoxes IS
  BEGIN
    HTP.p('Click anywhere on the image below.' || HTF.para);
    -- 1̃NbN\ȃC[WtH[ZbgAbvB̃C[W
    -- ^[QbǵAProcessvV[WłB̃tH[tB[ȟ^̓C[WȂ̂ŁA
    -- p_Imgp[^ɂOWA_IMAGE.POINT^̒lnB
    HTP.formOpen(curl => c_OWAPath || 'Imagemap.Process');
    HTP.formImage(cname => 'p_Img',
                  csrc => c_ImagePath,
                  cattributes => 'BORDER=0');
    HTP.formClose;
  END ShowBoxes;

  PROCEDURE Go IS
  BEGIN
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Imagemap test');
    HTP.headClose;

    HTP.bodyOpen;
    ShowBoxes;
    HTP.bodyClose;
    HTP.htmlClose;
  END Go;

  PROCEDURE Process(p_Img IN OWA_IMAGE.POINT) IS
    v_x INTEGER := OWA_IMAGE.GET_X(p_Img);
    v_y INTEGER := OWA_IMAGE.GET_Y(p_Img);
    v_Color VARCHAR2(5);
  BEGIN
    IF v_x < 200 THEN
      IF v_y < 100 THEN
        v_Color := 'Blue';
      ELSE
        v_Color := 'Red';
      END IF;
    ELSE
      IF v_y < 100 THEN
        v_Color := 'Green';
      ELSE
        v_Color := 'Black';
      END IF;
    END IF;
    HTP.htmlOpen;
    HTP.headOpen;
    HTP.title('Imagemap results');
    HTP.headClose;

    HTP.bodyOpen;
    HTP.print('Processed.  X = ' || v_x || ' and Y = ' || v_y);
    HTP.print('.  This means that you selected the ' || v_Color);
    HTP.print(' box.' || HTF.para);

    ShowBoxes;
    HTP.bodyClose;
    HTP.htmlClose;
  END Process;

END Imagemap;



Set-Cookie: name=value expires=expires path=path
            domain=domain [secure]



Set-Cookie: name=value path=path expires=01-JAN-1990



-- Available online as cookie.sql
CREATE OR REPLACE PROCEDURE CookieDemo(
  p_NewVal IN NUMBER DEFAULT NULL) AS
  -- c_OWAPathAOracle WebG[WFgCXg[ĂiDCD܂ށj
  -- zpXɐݒ肷B
  c_OWAPath CONSTANT VARCHAR2(50) := '/example/owa/';

  v_Cookie OWA_COOKIE.COOKIE;
BEGIN
  -- NbL[݂̌̒loāAp[^ɊÂVl𑗂B
  v_Cookie := OWA_COOKIE.GET('Count');
  OWA_UTIL.MIME_HEADER('text/html', FALSE);
  IF p_NewVal IS NOT NULL THEN
    OWA_COOKIE.SEND('Count', p_NewVal + 1);
  ELSIF (v_Cookie.num_vals = 0) THEN
    OWA_COOKIE.SEND('Count', 0);
  ELSE
    OWA_COOKIE.SEND('Count', v_Cookie.vals(1) + 1);
  END IF;
  OWA_UTIL.HTTP_HEADER_CLOSE;

  HTP.htmlOpen;
  HTP.headOpen;
  HTP.title('Cookie Demo');
  HTP.headClose;

  HTP.bodyOpen;
  HTP.print('Welcome to the cookie demo, using the OWA_COOKIE ');
  HTP.print('package.' || HTF.para);
  IF p_NewVal IS NOT NULL THEN
    HTP.print('The cookie value has been reset to ');
    HTP.bold(p_NewVal);
    HTP.print('.' || HTF.para);
  ELSIF v_Cookie.num_vals > 0 THEN
    HTP.print('The cookie value is now ');
    HTP.bold(v_Cookie.vals(1));
    HTP.print('.' || HTF.para);
  ELSE
    HTP.print('The cookie value has been set to zero.');
  END IF;
  HTP.para;
  HTP.print('Click ');
  HTP.anchor(c_OWAPath || 'CookieDemo', 'here');
  HTP.print(' to increment the value, or enter a new value in');
  HTP.print(' the box below and click Submit to reset it.');
  HTP.para;

  HTP.formOpen(curl => c_OWAPath || 'CookieDemo');
  HTP.formText(cname => 'p_NewVal',
               csize => 10);
  HTP.formSubmit;
  HTP.formClose;

  OWA_UTIL.signature('CookieDemo');
  HTP.bodyClose;
  HTP.htmlClose;
END CookieDemo;



SQL> exec BodyDemo
PL/SQL procedure successfully completed.

SQL> set SERVEROUTPUT ON
SQL> exec OWA_UTIL.SHOWPAGE
<HTML>
<HEAD>
<TITLE>Body tags demo</TITLE>
</HEAD>
<BODY>
This page demonstrates several of the tags
available for formatting the text in the body
of a web page, and for inserting additional
tags.<P>
<H2>Links</H2>
Here are some links to check out. These are
generated using the HTP.anchor procedure.
<P>
<A HREF="//www.oracle.com/">Oracle Corporation</A>
<P>
<A HREF="//www.osborne.com/oracle/index.htm">Oracle Press</A>
<P>
<A HREF="//www.platinum.com/">Platinum Corporation</A>
<P>
<H2>Formats</H2>
<CENTER>These lines are centered, using
<BR>
the HTF.centerOpen and HTF.centerClose functions.
</CENTER>
<STRIKE>Here's some strikethrough text.</STRIKE>
</BODY>
</HTML>

PL/SQL procedure successfully completed.



Chapter 20
/* Available online as part of outstr.c */
#include <stdio.h>

/* bZ[WɊ܂܂镶pXŎw肳ꂽt@Cɏo͂Bt@C݂Ȃꍇ
   ́A쐬B */
void OutputString(path, message)
char *path;
char *message;  {

  FILE *file_handle;

  /* ރt@CJB */
  file_handle = fopen(path, "w");

  /* ̌ɉsďo͂B */
  fprintf(file_handle, "%s\n", message);

  /* t@CB */
  fclose(file_handle);
}



cc -G -o /home/utils/stringlib.so outstr.c



#Available online as listener.ora
#Sample listener.ora for external procedures.
#Replace <<ORACLE_HOME>> with the $ORACLE_HOME directory,
#replace <<LISTENER_KEY>> with an IPC key, and
#replace <<EXTPROC_SID>> with an identifier for extproc.

listener =
  (ADDRESS_LIST =
    (ADDRESS =
       (PROTOCOL = ipc)
       (KEY = <<LISTENER_KEY>>)
    )
  )

sid_list_listener =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = <<EXTPROC_SID>>)
      (ORACLE_HOME = <<ORACLE_HOME>>)
      (PROGRAM = extproc)
    )
  )



#Available online as tnsnames.ora
#Sample tnsnames.ora for external procedures.
#Replace <<LISTENER_KEY>> with an IPC key, and
#replace <<EXTPROC_SID>> with an identifier for extproc.

extproc_connection_data =
  (DESCRIPTION =
    (ADDRESS =
      (PROTOCOL = ipc)
      (KEY = <<LISTENER_KEY>>)
    )
    (CONNECT_DATA =
      (SID = <<EXTPROC_SID>>)
    )
  )



$ lsnrctl start
LSNRCTL for Solaris: Version 8.0.3.0.0 - Production on 12-AUG-97 01:03:55

(c) Copyright 1997 Oracle Corporation. All rights reserved.
Starting /oracle/app/oracle/product/8.0.3/bin/tnslsnr: please wait...

TNSLSNR for Solaris: Version 8.0.3.0.0 - Production 
System parameter file is
  /oracle/app/oracle/product/8.0.3/network/admin/listener.or a
Log messages written to
  /oracle/app/oracle/product/8.0.3/network/log/listener.log
Listening on: (ADDRESS=(PROTOCOL=ipc)(DEV=9)(KEY=V803_extproc))

Connecting to (ADDRESS=(PROTOCOL=ipc)(KEY=V803_extproc))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Solaris: Version 8.0.3.0.0 - Production
Start Date                12-AUG-97 01:04:00
Uptime                    0 days 0 hr. 0 min. 1 sec
Trace Level               off
Security                  OFF
SNMP                      OFF
Listener Parameter File
  /oracle/app/oracle/product/8.0.3/network/admin/listener.ora
Listener Log File
  /oracle/app/oracle/product/8.0.3/network/log/listener.log
Services Summary...
  V803          has 1 service handler(s)
The command completed successfully



CREATE LIBRARY stringlib AS
  '/home/utils/stringlib.so';



SQL> SELECT * FROM user_libraries
  2    WHERE library_name = 'STRINGLIB';

LIBRARY_NAME    FILE_SPEC                      D STATUS
--------------- ------------------------------ - -------
STRINGLIB       /home/utils/stringlib.so       Y VALID



-- Available online as part of outstr.sql
CREATE OR REPLACE PROCEDURE OutputString(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2) AS EXTERNAL

  LIBRARY stringlib
  NAME "OutputString"
  PARAMETERS (p_Path STRING,
              p_Message STRING);



SQL> BEGIN
  2    OutputString('/tmp/output.txt', 'Hello World!');
  3  END;
  4  /
PL/SQL procedure successfully completed.

SQL> exit
Disconnected from Oracle8 Server Release 8.0.3.0.0 - Production
With the Partitioning and Objects options
PL/SQL Release 8.0.3.0.0 - Production
$ cat /tmp/output.txt
Hello World!



CREATE OR REPLACE PROCEDURE OutputString(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2) AS EXTERNAL
  ...
  PARAMETERS (p_Path STRING,
              p_Message STRING);



void OutputString(path, message)
char *path;
char *message;  {
  ...



-- Available online as part of outstr.c
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂BbZ[Wnum_times
@@Ŏw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬B */
void OutputString2(path, message, num_times)
char *path;
char *message;
int   num_times;  {

  FILE *file_handle;
  int counter;

  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  for (counter = 0; counter < num_times; counter++)
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);

  /* t@CB */
  fclose(file_handle);
}



-- Available online as part of outstr.sql
CREATE OR REPLACE PROCEDURE OutputString2(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2,
  p_NumLines IN BINARY_INTEGER) AS EXTERNAL

  LIBRARY stringlib
  NAME "OutputString2"
  PARAMETERS (p_Path STRING,
              p_Message STRING,
              p_NumLines INT);



/* Available online as part of outstr.c */
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂BbZ[Wnum_times
@@Ŏw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬Bۂɏ
@@ꂽsAnum_lines_writtenɕԂB */
void OutputString3(path, message, num_times, num_lines_written)
char *path;
char *message;
int  num_times;
ub2 *num_lines_written;  {

  FILE *file_handle;
  int counter;

  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  for (counter = 0; counter < num_times; counter++)  {
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);
    (*num_lines_written)++;
  }

  /* t@CB */
  fclose(file_handle);
}



-- Available online as part of outstr.sql
CREATE OR REPLACE PROCEDURE OutputString3(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2,
  p_NumLines IN BINARY_INTEGER,
  p_NumLinesWritten OUT NATURAL) AS EXTERNAL 

  LIBRARY stringlib
  NAME "OutputString3"
  PARAMETERS (p_Path STRING,
              p_Message STRING,
              p_NumLines INT,
              p_NumLinesWritten UB2);



/* Available online as part of outstr.c */
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂BbZ[Wnum_times
@@Ŏw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬Bۂɏ
@@ꂽsAnum_lines_writtenɕԂBep[^NULLł邩ۂ`FbN
@@B */
void OutputString4(path, path_ind,
                   message, message_ind,
                   num_times, num_times_ind,
                   num_lines_written)
char *path;
short path_ind;
char *message;
short message_ind;
int   num_times;
short num_times_ind;
ub2  *num_lines_written;  {

  FILE *file_handle;
  int counter;

  /* ̓p[^̂ꂩNULL̏ꍇA[ԂAo͂ȂB */
  if (path_ind == OCI_IND_NULL || message_ind == OCI_IND_NULL ||
      num_times_ind == OCI_IND_NULL) {
    *num_lines_written = 0;
    return;
  }
  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  for (counter = 0; counter < num_times; counter++)  {
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);
    (*num_lines_written)++;
  }

  /* t@CB */
  fclose(file_handle);
}



-- Available online as part of outstr.sql
CREATE OR REPLACE PROCEDURE OutputString4(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2,
  p_NumLines IN BINARY_INTEGER,
  p_NumLinesWritten OUT NATURAL) AS EXTERNAL

  LIBRARY stringlib
  NAME "OutputString4"
  PARAMETERS (p_Path STRING,
              p_Path INDICATOR,
              p_Message STRING,
              p_Message INDICATOR,
              p_NumLines INT,
              p_NumLines INDICATOR,
              p_NumLinesWritten UB2);



/* Available online as part of outstr.c */
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂BbZ[Wnum_times
@@Ŏw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬Bۂɏ
@@ꂽsԂBep[^NULLł邩ۂ`FbNB */
ub2 OutputString5(path, path_ind,
                   message, message_ind,
                   num_times, num_times_ind,
                   retval_ind)
char  *path;
short  path_ind;
char  *message;
short  message_ind;
int    num_times;
short  num_times_ind;
short  *retval_ind;  {

  FILE *file_handle;
  ub2 counter;

  /* ̓p[^̂ꂩNULL̏ꍇANULLԂAo͂ȂB */
  if (path_ind == OCI_IND_NULL || message_ind == OCI_IND_NULL ||
      num_times_ind == OCI_IND_NULL) {
    *retval_ind = OCI_IND_NULL;
    return 0;
  }

  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  for (counter = 0; counter < num_times; counter++)  {
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);
  }

  /* t@CB */
  fclose(file_handle);

  /* ߂lݒ肷B */
  *retval_ind = OCI_IND_NOTNULL;
  return counter;
}



-- Available online as part of outstr.sql
CREATE OR REPLACE FUNCTION OutputString5(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2,
  p_NumLines IN BINARY_INTEGER)
  RETURN NATURAL AS EXTERNAL

  LIBRARY stringlib
  NAME "OutputString5"
  PARAMETERS (p_Path STRING,
              p_Path INDICATOR,
              p_Message STRING,
              p_Message INDICATOR,
              p_NumLines INT,
              p_NumLines INDICATOR,
              RETURN INDICATOR,
              RETURN UB2);



int OCIExtProcRaiseExcp(with_context, error_number)
  OCIExtProcContext *with_context;
  size_t error_number;



/* Available online as part of outstr.c */
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂B̃bZ[W
@@num_timesŎw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬B
@@ۂɏ܂ꂽsԂBep[^NULLł邩ۂ`FbNA
@@̓p[^̂ꂩNULLł΁AORA-6502ĂяoB */
ub2 OutputString6(context, path, path_ind,
                   message, message_ind,
                   num_times, num_times_ind,
                   retval_ind)
OCIExtProcContext *context;
char              *path;
short              path_ind;
char              *message;
short              message_ind;
int                num_times;
short              num_times_ind;
short              *retval_ind;  {

  FILE *file_handle;
  ub2 counter;

  /* ̓p[^̂ꂩNULL̏ꍇAORA-6502ĂяoAɃ^[B */
  if (path_ind == OCI_IND_NULL || message_ind == OCI_IND_NULL ||
      num_times_ind == OCI_IND_NULL) {
    OCIExtProcRaiseExcp(context, 6502);
    return 0;
  }

  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  for (counter = 0; counter < num_times; counter++)  {
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);
  }

  /* t@CB */
  fclose(file_handle);

  /* ߂lݒ肷B */
  *retval_ind = OCI_IND_NOTNULL;
  return counter;
}



-- Available online as part of outstr.sql
CREATE OR REPLACE FUNCTION OutputString6(
  p_Path IN VARCHAR2,
  p_Message IN VARCHAR2,
  p_NumLines IN BINARY_INTEGER)
  RETURN NATURAL AS EXTERNAL

  LIBRARY stringlib
  NAME "OutputString6"
  WITH CONTEXT
  PARAMETERS (CONTEXT,
              p_Path STRING,
              p_Path INDICATOR,
              p_Message STRING,
              p_Message INDICATOR,
              p_NumLines INT,
              p_NumLines INDICATOR,
              RETURN INDICATOR,
              RETURN UB2);



int OCIExtProcRaiseExcpWithMsg(
  with_context, error_number, error_message, len)
OCIExtProcContext *with_context;
size_t             error_number;
text              *error_message;
size_t             len;



dvoid *OCIExtprocAllocCallMemory(with_context, amount);
OCIExtProcContext *with_memory;
size_t             amount;



/* Available online as part of outstr.c */
/* pXŎw肳ꂽt@CɁAbZ[WɊ܂܂ꂽo͂B̃bZ[W
@@num_timesŎw肳ꂽ񐔂JԂBt@C݂Ȃꍇ́A쐬B
@@ۂɏ܂ꂽsԂBep[^NULLł邩ۂ`FbNA
@@̓p[^̂ꂩNULLł΁AORA-6502ĂяoBt@CJȂ
@@ꍇ́A[U[`̃G[ԂB */
ub2 OutputString7(context, path, path_ind,
                   message, message_ind,
                   num_times, num_times_ind,
                   retval_ind)
OCIExtProcContext *context;
char              *path;
short              path_ind;
char              *message;
short              message_ind;
int                num_times;
short              num_times_ind;
short              *retval_ind;  {

  FILE *file_handle;
  ub2 counter;

  /* ̓p[^̂ꂩNULL̏ꍇAORA-6502ĂяoAɃ^[B */
  if (path_ind == OCI_IND_NULL || message_ind == OCI_IND_NULL ||
      num_times_ind == OCI_IND_NULL) {
    OCIExtProcRaiseExcp(context, 6502);
    return 0;
  }

  /* o͂t@CJB */
  file_handle = fopen(path, "w");

  /* ǂ`FbNAsȂG[𐶐B */
  if (!file_handle) {
    text *initial_msg = (text *)"Cannot open file ";
    text *error_msg;

    /* G[bZ[WeLXĝ߂̗̈蓖ĂĐݒ肷B
       Kv͂ȂB
       PL/SQLɂĎIɍsB */
    error_msg = OCIExtProcAllocCallMemory(context,
                  strlen(path) + strlen(initial_msg) + 1);
    strcpy((char *)error_msg, (char *)initial_msg);
    strcat((char *)error_msg, path);

    OCIExtProcRaiseExcpWithMsg(context, 20001, error_msg, 0);
    return 0;
  }

  for (counter = 0; counter < num_times; counter++)  {
    /* Aɉso͂B */
    fprintf(file_handle, "%s\n", message);
  }

  /* t@CB */
  fclose(file_handle);

  /* ߂lݒ肷B */



  *retval_ind = OCI_IND_NOTNULL;
  return counter;
}



sword OciExtProcGetEnv(with_context, envh, svch, errh)
OCIExtProcContext *with_context;
OCIEnv           **envh;
OCISvcCtx        **svch;
OCIError         **errh;



-- Available online as dbgextp.sql
CREATE OR REPLACE PACKAGE debug_extproc IS
  -- ZbVextprocG[WFgNB
  --   ̃vV[WsƁÃZbVextprocG[WFgvZXNA
  --   s̃vZXPIDl邱ƂłBPID́AfobKgpĎs
  --   ̃vZXɃA^b`邽߂ɕKvɂȂB
  PROCEDURE startup_extproc_agent;
END debug_extproc;

CREATE OR REPLACE LIBRARY debug_extproc_library IS STATIC;

CREATE OR REPLACE PACKAGE BODY debug_extproc IS
  extproc_lib_error EXCEPTION;
  PRAGMA EXCEPTION_INIT (extproc_lib_error, -6520);

  extproc_func_error EXCEPTION;
  PRAGMA EXCEPTION_INIT (extproc_func_error, -6521);

  PROCEDURE local_startup_extproc_agent IS EXTERNAL
    LIBRARY debug_extproc_library;

  PROCEDURE startup_extproc_agent is
  BEGIN
    -- _~[vV[WĂяoāAׂẴG[gbvB
    local_startup_extproc_agent;
  EXCEPTION
    -- ֐܂̓CuȂꍇ́AG[𖳎B
    WHEN extproc_func_error then NULL;
    WHEN extproc_lib_error then NULL;
  END startup_extproc_agent;
END debug_extproc;



Chapter 21
--Available online as part of tables8.sql
CREATE TABLE lobdemo (
  key NUMBER PRIMARY KEY,
  clob_col  CLOB,
  blob_col  BLOB,
  bfile_col BFILE
);



INSERT INTO lobdemo(key, clob_col, blob_col, bfile_col)
  VALUES (10, NULL, NULL, NULL);



INSERT INTO lobdemo(key, clob_col, blob_col, bfile_col)
  VALUES (11, empty_clob(), empty_blob(), NULL);



-- Available online as lobdml.sql
DECLARE
  v_CLOBlocator CLOB;
  v_BLOBlocator BLOB;
BEGIN
  -- clob_colw肳ꂽɏāAv_LOBlocatorɃP[^ԂB 
  INSERT INTO lobdemo (key, clob_col)
    VALUES (20, 'abcdefghijklmnopqrstuvwxyz')
    RETURNING clob_col INTO v_CLOBlocator;

  -- sblob_colύXB
  UPDATE lobdemo
    SET blob_col = HEXTORAW('00FF00FF00FF')
    WHERE key = 20;

  -- VɍXVꂽl̂ł͂ȂAl̃P[^oB
  SELECT blob_col
    INTO v_BLOBlocator
    FROM lobdemo 
    WHERE key = 20;
END;



CREATE DIRECTORY utils AS '/home/utils';



INSERT INTO lobdemo (key, bfile_col)
   VALUES (-1, BFILENAME('utils', 'file1'));



-- Available online as part of tables8.sql
CREATE TABLE lobdemo2 (
  key NUMBER PRIMARY KEY,
  clob_col  CLOB,
  blob_col  BLOB,
  bfile_col BFILE
);



INSERT INTO lobdemo2
  SELECT key, clob_col, blob_col, NULL FROM lobdemo;



-- Available online as bfiledml.sql
BEGIN
  -- Ot@Cw1slobdemo̒ɍ쐬B
  INSERT INTO lobdemo (key, bfile_col)
    VALUES (5, BFILENAME('util', 'file1'));

  -- ̃P[^lobdemo2ɃRs[B
  INSERT INTO lobdemo2
    SELECT *
      FROM lobdemo
      WHERE key = 5;
END;



DELETE FROM lobdemo
  WHERE key = 5;



-- Available online as lobtest.sql
INSERT INTO lobdemo (key, clob_col, blob_col, bfile_col)
  VALUES (-1, EMPTY_CLOB(), EMPTY_BLOB(), NULL);
INSERT INTO lobdemo (key, clob_col, blob_col, bfile_col)
  VALUES (1, 'abcdefghijklmnopqrstuvwxyz',
             HEXTORAW('000102030405060708090A0B0C0D0E0F'), 
             NULL); 
INSERT INTO lobdemo (key, clob_col, blob_col, bfile_col)
  VALUES (2, 'A Quick Brown Fox Jumps Over the Lazy Dog',
             HEXTORAW('FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0'),
             NULL);
COMMIT;



-- Available online as lobcopy.sql
DECLARE
  v_Lob1 CLOB;
  v_Lob2 CLOB;
BEGIN
  -- \[XLOBP[^oB
  SELECT clob_col
    INTO v_Lob1
    FROM lobdemo
    WHERE key = 1;

  -- LOBP[^oB
  SELECT clob_col
    INTO v_Lob2
    FROM lobdemo
    WHERE key = 2;

  -- ItZbg50JnāAv_Lob126ׂĂv_Lob2̍ŌɃRs[B
  -- v_Lob2̒50ł͂Ȃ̂ŁAXy[X}B
  DBMS_LOB.COPY(v_Lob2, v_Lob1, 26, 50, 1);

  -- ʂo͂B
  LOBPrint(v_Lob2);
END;



-- Available online as fileexec.sql
CREATE OR REPLACE PROCEDURE FileExec(
  -- p_Directoryp_FileNameŎʂꂽt@CSQLsBeɂ́A
  -- iPL/SQLubNłꍇj㑱Z~R܂܂ĂĂ͂Ȃ炸A
  -- p_SeparationCharŋ؂KvB
  p_Directory IN VARCHAR2,
  p_FileName IN VARCHAR2,
  p_SeparationChar IN CHAR) AS

  v_FileLocator BFILE;
  v_CLOBLocator CLOB;
  v_SQLCursor INTEGER;
  v_StartPoint INTEGER := 1;
  v_EndPoint INTEGER;
  v_SQLStatement VARCHAR2(32000);
  v_StatementLength INTEGER;
  v_RC INTEGER;
BEGIN
  -- ݗp̕P[^B\CLOBFOR UPDATEselectKv
  -- 邱ƂɒӂBł̍sbNBLOADFROMFILE̗vłB
  SELECT clob_col
    INTO v_CLOBLocator
    FROM lobdemo
    WHERE key = -1
    FOR UPDATE;

  -- ǂݍݗpBLOBP[^B
  v_FileLocator := BFILENAME(p_Directory, p_FileName);
  DBMS_LOB.FILEOPEN(v_FileLocator, DBMS_LOB.FILE_READONLY);

  -- J[\ݒ肷B
  v_SQLCursor := DBMS_SQL.OPEN_CURSOR;

  -- t@CŜ𕶎^LOBɃ[hBRAWϐł͂ȂÃf[^l邽߂
  -- ̍ƂKvɂȂB
  DBMS_LOB.LOADFROMFILE(v_CLOBLocator, v_FileLocator, 
                        DBMS_LOB.GETLENGTH(v_FileLocator));

  -- LOB[vāA؂蕶̃IJXB
  LOOP
    v_EndPoint := DBMS_LOB.INSTR(v_CLOBLocator, 
                                 p_SeparationChar,
                                 v_StartPoint, 1);
    EXIT WHEN v_EndPoint = 0;

    -- Jn_ƏI_̊Ԃ̓eoBꂪsSQLɂȂB
    v_StatementLength := v_EndPoint - v_StartPoint;
    v_SQLStatement := DBMS_LOB.SUBSTR(v_CLOBLocator, 
       v_StatementLength, v_StartPoint);

    -- ʂɃGR[ĂADBMS_SQLgpĎsB
    DBMS_OUTPUT.PUT_LINE(v_SQLStatement);
    DBMS_SQL.PARSE(v_SQLCursor, v_SQLStatement, DBMS_SQL.V7);
    v_RC := DBMS_SQL.EXECUTE(v_SQLCursor);

    -- ̂̕߂ɕ|C^𑝕B
    v_StartPoint := v_EndPoint + 1;
  END LOOP; 

  -- N[AbvB
  DBMS_LOB.FILECLOSE(v_FileLocator);
  DBMS_SQL.CLOSE_CURSOR(v_SQLCursor);
EXCEPTION
  WHEN OTHERS THEN
    -- J[\ƃt@CāAxĂяoB
    DBMS_LOB.FILECLOSE(v_FileLocator);
    DBMS_SQL.CLOSE_CURSOR(v_SQLCursor);
    RAISE;
END FileExec;



-- Available online as inserts.sql
INSERT INTO temp_table (num_col, char_col)
  VALUES (1, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (2, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (3, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (4, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (5, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (6, 'hello')
/
INSERT INTO temp_table (num_col, char_col)
  VALUES (7, 'hello')



BEGIN
  FileExec('STATEMENTS', 'inserts.sql', '/');
END;



-- Available online as lobprint.sql
CREATE OR REPLACE PROCEDURE LOBPrint(p_CLOB IN CLOB) AS
  v_Buffer VARCHAR2(80);
  v_Offset INTEGER := 1;
  v_Amount INTEGER := 80;
BEGIN
  LOOP
    -- 80ǂݍŏo͂B
    DBMS_LOB.READ(p_CLOB, v_Amount, v_Offset, v_Buffer);
    DBMS_OUTPUT.PUT_LINE(v_Buffer);

    v_Offset := v_Offset + v_Amount;
  END LOOP;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- [v̍ŌB^[B
    NULL;
END LOBPrint;



-- Available online as lobtrim.sql
DECLARE
  v_BLOB BLOB;
BEGIN
  SELECT blob_col
    INTO v_BLOB
    FROM lobdemo
    WHERE key = 1
    FOR UPDATE;

  DBMS_OUTPUT.PUT_LINE('Before trim, length = ' || 
                        DBMS_LOB.GETLENGTH(v_BLOB));
  DBMS_LOB.TRIM(v_BLOB, 5);
  DBMS_OUTPUT.PUT_LINE('After trim, length = ' || 
                        DBMS_LOB.GETLENGTH(v_BLOB));

  -- 5ɒB̂ŁAG[ORA-22926B
  DBMS_LOB.TRIM(v_BLOB, 10);
END;



-- Available online as long2lob.sql
CREATE OR REPLACE PROCEDURE Long2Lob(
  -- DBMS_SQLgpāAp_LongQueryŎʂꂽLONGIAp_ClobŕԂB
  p_LongQuery IN VARCHAR2,
  p_CLob IN OUT CLOB) AS

  c_ChunkSize CONSTANT INTEGER := 100;  

  v_CursorID INTEGER;
  v_RC INTEGER;
  v_Chunk VARCHAR2(100);
  v_ChunkLength INTEGER;
  v_Offset INTEGER := 0;
BEGIN
  -- J[\JāA`AsуtFb`B
  v_CursorID := DBMS_SQL.OPEN_CURSOR;
  DBMS_SQL.PARSE(v_CursorID, p_LongQuery, DBMS_SQL.V7);
  DBMS_SQL.DEFINE_COLUMN_LONG(v_CursorID, 1);
  v_RC := DBMS_SQL.EXECUTE_AND_FETCH(v_CursorID);

  -- LONG[vāALONGc_ChunkSizetFb`āALOBɒǉ
  -- ĂB
  LOOP
    DBMS_SQL.COLUMN_VALUE_LONG(v_CursorID, 1, c_ChunkSize,
      v_Offset, v_Chunk, v_ChunkLength);
    DBMS_LOB.WRITE(p_CLob, v_ChunkLength, v_Offset + 1,
      v_Chunk);
    IF v_ChunkLength < c_ChunkSize THEN
      EXIT;
    ELSE
      v_Offset := v_Offset + v_ChunkLength;
    END IF;
  END LOOP;

  DBMS_SQL.CLOSE_CURSOR(v_CursorID);
EXCEPTION
  WHEN OTHERS THEN
    -- N[AbvāAG[ĂьĂяoB
    DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    RAISE;
END Long2Lob;



-- Available online as part of l2ltest.sql
CREATE TABLE long_tab (
  key NUMBER,
  long_col LONG
);
INSERT INTO long_tab (key, long_col)
  VALUES (100, 
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstu
vwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS
TUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmno
pqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJK
LMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefg
hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABC
DEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZ
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuv
wxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS
TUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopq
rstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM
NOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijk
lmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZ');



-- Available online as part of l2ltest.sql
DECLARE
  v_Query VARCHAR2(200);
  v_NewLOB CLOB;
BEGIN
  v_Query := 'SELECT long_col FROM long_tab where key = 100'; 
  INSERT INTO lobdemo (key, clob_col)
    VALUES (100, EMPTY_CLOB())
    RETURNING clob_col INTO v_NewLOB;

  Long2Lob(v_Query, v_NewLOB);
  LOBPrint(v_NewLOB);
  COMMIT;
END;



Chapter 22
ORA-4031: unable to allocate X bytes of shared memory



ALTER SYSTEM FLUSH SHARED POOL;



SQL> SELECT name, type, code_size
  2    FROM dba_object_size
  3    WHERE name IN ('DBMS_PIPE', 'STANDARD', 'DBMS_OUTPUT')
  4    ORDER BY name, type;

NAME                           TYPE         CODE_SIZE
------------------------------ ------------ ---------
DBMS_OUTPUT                    PACKAGE            388
DBMS_OUTPUT                    PACKAGE BODY      6217
DBMS_OUTPUT                    SYNONYM              0
DBMS_PIPE                      PACKAGE            699
DBMS_PIPE                      PACKAGE BODY      6427
DBMS_PIPE                      SYNONYM              0
STANDARD                       PACKAGE          10494
STANDARD                       PACKAGE BODY     22400



SQL> SELECT sid
  2    FROM v$process p, v$session s
  3    WHERE p.addr = s.paddr
  4    AND s.username = 'SYSTEM';

      SID
---------
        6



SQL> SELECT value
  2    FROM v$sesstat s, v$statname n
  3    WHERE s.statistic# = n.statistic#
  4    AND n.name = 'session uga memory max'
  5    AND SID = 6;

    VALUE
---------
    94704



CREATE TABLE plan_table (
  statement_id    VARCHAR2(30),
  timestamp       DATE,
  remarks         VARCHAR2(80),
  operation       VARCHAR2(30),
  options         VARCHAR2(30),
  object_node     VARCHAR2(30),
  object_owner    VARCHAR2(30),
  object_name     VARCHAR2(30),
  object_instance NUMBER,
  object_type     VARCHAR2(30),
  search_columns  NUMBER,
  id              NUMBER,
  parent_id       NUMBER,
  position        NUMBER,
  other           LONG);



EXPLAIN PLAN
  SET STATEMENT_ID = 'Query 1' FOR
    SELECT rs.course, rs.department, students.ID
      FROM registered_students rs, students
      WHERE rs.student_id = students.id
      AND students.last_name = 'Razmataz';



SELECT LPAD(' ', 2 * (LEVEL - 1)) || operation ||
       ' ' || options || ' ' || object_name || ' ' ||
       DECODE(id, 0, 'Cost = ' || position) "Execution Plan"
  FROM plan_table
  START WITH id = 0
    AND statement_id = 'Query 1'
  CONNECT BY PRIOR id = parent_id
    AND statement_id = 'Query 1';



Execution Plan
------------------------------------------
SELECT STATEMENT   Cost =
  NESTED LOOPS
    TABLE ACCESS FULL REGISTERED_STUDENTS
    TABLE ACCESS BY ROWID STUDENTS
      INDEX UNIQUE SCAN SYS_C00859



SQL> ALTER SESSION SET SQL_TRACE = TRUE;
Session altered.
SQL> SELECT rs.course, rs.department, students.ID
       FROM registered_students rs, students
       WHERE rs.student_id = students.id
       AND students.last_name = 'Razmataz';
    COURSE DEP         ID
---------- --- ----------
       101 HIS      10010
       307 NUT      10010

SQL> ALTER SESSION SET SQL_TRACE = FALSE;
Session altered.



SELECT rs.course, rs.department, students.ID
      FROM registered_students rs, students
      WHERE rs.student_id = students.id
      AND students.last_name = 'Razmataz'

call      count  cpu   elapsed  disk  query  current  rows
--------  -----  ----  -------  ----  -----  -------  ----
Parse         1  0.00  0.00     0     0      0        0
Execute       1  0.00  0.00     0     0      0        0
Fetch         1  0.00  0.00     0     55     3        2

--------  -----  ----  -------  ----  -----  ------   ----
total         3  0.00  0.00     0     55     3        2

Misses in library cache during parse: 1
Optimizer hint: CHOOSE
Parsing user id: 9  (EXAMPLE)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   OPTIMIZER HINT: CHOOSE
      2    NESTED LOOPS
     18      TABLE ACCESS (FULL) OF 'REGISTERED_STUDENTS'
     18      TABLE ACCESS (BY ROWID) OF 'STUDENTS'
     18        INDEX (UNIQUE SCAN) OF 'SYS_C00859' (UNIQUE)

**************************************************************


Appendix A
DECLARE
  "BEGIN" NUMBER;
BEGIN
  "BEGIN" := 7;
END;



Appendix B
DBMS_SESSION.SET_ROLE('Administrator IDENTIFIED BY admin');



DBMS_SESSION.SET_NLS('nls_date_format', '''DD-MON-YY
                      HH24:MI:SS''');



DECLARE
  v_Start NUMBER;
  v_End NUMBER;
BEGIN
  v_Start := DBMS_UTILITY.GET_TIME;
  /* ŁAsB*/
  v_End := DBMS_UTILITY.GET_TIME;
  /* Y鏈̎sɂ́A(v_Start - v_End) * 100bƂɂȂB */
END;



Appendix C
DECLARE
  e_NonExistentTable  EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_NonExistentTable, -942);
  ...



DECLARE
  v_ClassInfo classes%ROWTYPE;



DECLARE
  v_FirstName      students.first_name%TYPE;
  v_CurrentCredits students.current_credits%TYPE;



DECLARE
  TYPE t_Dates IS VARRAY(25) OF DATE;



  -- ́APs̃RgB
/* ́As̃RgłA
   sɂ܂ėLłB */



DECLARE
  TYPE t_DateTable IS TABLE OF DATE
    INDEX BY BINARY_INTEGER;
  v_Dates t_DateTable;



DECLARE
  TYPE t_StudentType IS RECORD (
    FirstName students.first_name%TYPE;
    LastName  students.last_name%TYPE;
    ID        students.ID%TYPE);
  v_StudentInfo t_StudentType;



Appendix D
SQL> SELECT object_type, status
  2    FROM user_objects
  3    WHERE object_name = UPPER('ClassPackage');

OBJECT_TYPE   STATUS
------------- -------
PACKAGE       VALID
PACKAGE BODY  VALID



SELECT line, position, text
  FROM user_errors
  WHERE name = object_name
  ORDER BY sequence;






































