Understanding CHAR and VARCHAR2 Semantics in PL/SQL B-1This appendix contains these topics: ■ Assigning Character Values on page B-1 ■ Comparing Character Values on page B-2 ■ Inserting
Trang 1Usage Notes
This function is part of the flashback query feature System change numbers provide aprecise way to specify the database state at a moment in time, so that you can see thedata as it was at that moment
Call this function to find out the system change number associated with the date andtime to which you want to "flash back"
Examples
DECLARE right_now TIMESTAMP; yesterday TIMESTAMP; sometime TIMESTAMP;
scn1 INTEGER; scn2 INTEGER; scn3 INTEGER;
BEGIN Get the current SCN.
dbms_output.put_line('SCN from yesterday is ' || scn2);
Find an arbitrary SCN somewhere between yesterday and today.
(In a real program we would have stored the SCN at some significant moment.) scn3 := (scn1 + scn2) / 2;
Find out what time that SCN was in effect.
Trang 2field_name
db_table_name column_name variable_name
% TYPE
type_attribute
Trang 3TheNOT NULL column constraint is not inherited by items declared using%TYPE.
Examples
DECLARE We know that BUFFER2 and BUFFER3 will be big enough to hold the answers If we have to increase the size of BUFFER1, the other variables will change size as well.
buffer1 VARCHAR2(13) := 'abCdefGhiJklm';
buffer2 buffer1%TYPE := UPPER(buffer1);
buffer3 buffer1%TYPE := LOWER(buffer1);
We know that this variable will be able to hold the contents of this table column If the table is altered to make the column longer or shorter, this variable will change size as well.
END;
BEGIN SELECT table_name INTO tname FROM user_tables WHERE ROWNUM < 2;
Trang 4UPDATE Statement
PL/SQL Language Elements 13-141
UPDATE Statement
TheUPDATEstatement changes the values of specified columns in one or more rows in
a table or view For a full description of theUPDATEstatement, see Oracle Database SQL Reference.
returning_clause
Returns values from updated rows, eliminating the need toSELECT the rowsafterward You can retrieve the column values into variables or host variables, or intocollections or host arrays You cannot use theRETURNING clause for remote or parallelupdates If the statement does not affect any rows, the values of the variables specified
in theRETURNING clause are undefined For the syntax ofreturning_clause, see
"DELETE Statement" on page 13-41
SET column_name = sql_expression
This clause assigns the value ofsql_expression to the column identified bycolumn_name Ifsql_expression contains references to columns in the table being
UPDATE ( subquery
TABLE ( subquery2 )
alias table_reference
Trang 5UPDATE Statement
13-142 PL/SQL User's Guide and Reference
updated, the references are resolved in the context of the current row The old columnvalues are used on the right side of the equal sign
SET column_name = (subquery3)
Assigns the value retrieved from the database bysubquery3 to the column identified
bycolumn_name The subquery must return exactly one row and one column
SET (column_name, column_name, ) = (subquery4)
Assigns the values retrieved from the database bysubquery4 to the columns in thecolumn_name list The subquery must return exactly one row that includes all thecolumns listed
The column values returned by the subquery are assigned to the columns in thecolumn list in order The first value is assigned to the first column in the list, thesecond value is assigned to the second column in the list, and so on
The following example creates a table with correct employee IDs but garbled names.Then it runs anUPDATE statement with a correlated query, to retrieve the correctnames from theEMPLOYEES table and fix the names in the new table
Create a table with all the right IDs, but messed-up names.
CREATE TABLE e1 AS SELECT employee_id, UPPER(first_name) first_name, TRANSLATE(last_name,'aeiou','12345') last_name FROM employees;
BEGIN Display the first 5 names to show they're messed up.
FOR person IN (SELECT * FROM e1 WHERE ROWNUM < 6) LOOP
dbms_output.put_line(person.first_name || ' ' || person.last_name);
END LOOP;
UPDATE e1 SET (first_name, last_name) = (SELECT first_name, last_name FROM employees WHERE employee_id = e1.employee_id);
dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows ***');
Display the first 5 names to show they've been fixed up.
FOR person IN (SELECT * FROM e1 WHERE ROWNUM < 6) LOOP
dbms_output.put_line(person.first_name || ' ' || person.last_name);
END LOOP;
END;
/ DROP TABLE e1;
Trang 6TABLE (subquery2)
The operand ofTABLE is aSELECT statement that returns a single column value,which must be a nested table or a varray OperatorTABLE informs Oracle that thevalue is a collection, not a scalar value
WHERE CURRENT OF cursor_name
Refers to the latest row processed by theFETCH statement associated with thespecified cursor The cursor must beFOR UPDATEand must be open and positioned on
a row
If the cursor is not open, theCURRENT OF clause causes an error If the cursor is open,but no rows have been fetched or the last fetch returned no rows, PL/SQL raises thepredefined exceptionNO_DATA_FOUND
The implicit cursorSQL and the cursor attributes%NOTFOUND,%FOUND,%ROWCOUNT,and%ISOPEN let you access useful information about the execution of anUPDATEstatement
Examples
The following example demonstrates how to update table rows based on conditions,and how to store the updated values, columns, or entire rows in PL/SQL variables: Create some rows with values in all caps like (EMPLOYEES,TABLE)
all_types type_typ;
TYPE table_typ IS TABLE OF my_objects%ROWTYPE INDEX BY PLS_INTEGER;
all_rows table_typ;
BEGIN Show the first 10 rows as they originally were.
FOR obj IN (SELECT * FROM my_objects WHERE ROWNUM < 11) LOOP
dbms_output.put_line('Name = ' || obj.object_name || ', type = ' ||
obj.object_type);
END LOOP;
Trang 7UPDATE Statement
13-144 PL/SQL User's Guide and Reference
UPDATE my_objects SET object_name = LOWER(object_name) WHERE object_type = 'TABLE';
dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows ***');
Show the first 10 rows after the update.
Only some of the names (the table names) have been changed to lowercase FOR obj IN (SELECT * FROM my_objects WHERE ROWNUM < 11)
LOOP dbms_output.put_line('Name = ' || obj.object_name || ', type = ' ||
RETURNING object_name, object_type INTO my_name, my_type;
dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows ***');
dbms_output.put_line('Affected this row: ' || my_name || ', ' || my_type); Update many rows, storing the values of updated (or unchanged)
columns in collections of records Can't use 'RETURNING *', have to list the columns individually.
UPDATE my_objects SET object_name = INITCAP(object_name) WHERE object_type IN ('TRIGGER','VIEW','SEQUENCE') RETURNING object_name, object_type BULK COLLECT INTO all_rows;
dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows ***');
FOR i IN all_rows.FIRST all_rows.LAST LOOP
dbms_output.put_line('Affected this row: ' || all_rows(i).object_name || ', ' || all_rows(i).object_type);
END LOOP;
Update many rows, storing the values of updated (or unchanged) columns in separate collections (Generally less useful than using collections of records as above.)
UPDATE my_objects SET object_name = INITCAP(object_name) WHERE object_type IN ('INDEX','PROCEDURE')
RETURNING object_name, object_type BULK COLLECT INTO all_names, all_types; dbms_output.put_line('*** Updated ' || SQL%ROWCOUNT || ' rows ***');
FOR i IN all_names.FIRST all_names.LAST LOOP
dbms_output.put_line('Affected this row: ' || all_names(i) || ', ' || all_types(i));
END LOOP;
END;
/ DROP TABLE my_objects;
Related Topics
DELETE Statement,FETCH Statement,INSERT Statement
Trang 8Sample PL/SQL Programs A-1
A
Sample PL/SQL Programs
This appendix tells you where to find collections of sample PL/SQL programs, foryour own study and testing
Where to Find PL/SQL Sample Programs
You can find some sample programs in the PL/SQL demo directory For the location ofthe directory, see the Oracle installation guide for your system These samples aretypically older ones based on theSCOTT schema, with itsEMP andDEPT tables
Most examples in this book have been made into complete programs that you can rununder theHR sample schema, with itsEMPLOYEES andDEPARTMENTS tables
The Oracle Technology Network web site has a PL/SQL section with many sampleprograms to download, athttp://otn.oracle.com/tech/pl_sql/ Theseprograms demonstrate many language features, particularly the most recent ones Youcan use some of the programs to compare performance of PL/SQL across databasereleases
For examples of calling PL/SQL from other languages, see Oracle Database Java Developer's Guide and Pro*C/C++ Programmer's Guide.
Exercises for the Reader
Here are some PL/SQL programming constructs that are helpful to know Afterlearning from the sample programs in this book and on the web, check to see that youare familiar with writing each of these constructs
■ A SQL*Plus script, or a set of scripts called from a master script, that creates a set
of procedures, functions, and packages
Trang 9Exercises for the Reader
A-2 PL/SQL User's Guide and Reference
■ AFORALL statement (instead of a regular loop) to issue multipleINSERT,UPDATE, orDELETE statements
Trang 10Understanding CHAR and VARCHAR2 Semantics in PL/SQL B-1
This appendix contains these topics:
■ Assigning Character Values on page B-1
■ Comparing Character Values on page B-2
■ Inserting Character Values on page B-2
■ Selecting Character Values on page B-3
Assigning Character Values
When you assign a character value to aCHAR variable, if the value is shorter than thedeclared length of the variable, PL/SQL blank-pads the value to the declared length.Information about trailing blanks in the original value is lost In the followingexample, the value assigned tolast_name includes six trailing blanks, not just one:last_name CHAR(10) := 'CHEN '; note trailing blank
If the character value is longer than the declared length of theCHAR variable, PL/SQLaborts the assignment and raises the predefined exceptionVALUE_ERROR PL/SQLneither truncates the value nor tries to trim trailing blanks For example, given thedeclaration
Trang 11Comparing Character Values
B-2 PL/SQL User's Guide and Reference
Comparing Character Values
You can use the relational operators to compare character values for equality orinequality Comparisons are based on the collating sequence used for the databasecharacter set One character value is greater than another if it follows it in the collatingsequence For example, given the declarations
last_name1 VARCHAR2(10) := 'COLES';
last_name2 VARCHAR2(10) := 'COLEMAN';
the following IF condition is true:
IF last_name1 > last_name2 THEN
The SQL standard requires that two character values being compared have equallengths If both values in a comparison have datatypeCHAR, blank-padding semantics
are used: before comparing character values of unequal length, PL/SQL blank-padsthe shorter value to the length of the longer value For example, given the declarationslast_name1 CHAR(5) := 'BELLO';
last_name2 CHAR(10) := 'BELLO '; note trailing blanksthe followingIF condition is true:
IF last_name1 = last_name2 THEN
If either value in a comparison has datatypeVARCHAR2, non-blank-padding semantics
are used: when comparing character values of unequal length, PL/SQL makes noadjustments and uses the exact lengths For example, given the declarationslast_name1 VARCHAR2(10) := 'DOW';
last_name2 VARCHAR2(10) := 'DOW '; note trailing blanksthe followingIF condition is false:
IF last_name1 = last_name2 THEN
If aVARCHAR2 value is compared to aCHAR value, non-blank-padding semantics areused But, remember, when you assign a character value to aCHAR variable, if thevalue is shorter than the declared length of the variable, PL/SQL blank-pads the value
to the declared length Given the declarationslast_name1 VARCHAR2(10) := 'STAUB';
last_name2 CHAR(10) := 'STAUB'; PL/SQL blank-pads valuethe followingIF condition is false because the value oflast_name2 includes fivetrailing blanks:
IF last_name1 = last_name2 THEN
All string literals have datatypeCHAR If both values in a comparison are literals,blank-padding semantics are used If one value is a literal, blank-padding semanticsare used only if the other value has datatypeCHAR
Inserting Character Values
When you insert the value of a PL/SQL character variable into an Oracle databasecolumn, whether the value is blank-padded or not depends on the column type, not onthe variable type
Trang 12Selecting Character Values
Understanding CHAR and VARCHAR2 Semantics in PL/SQL B-3
When you insert a character value into aCHAR database column, Oracle does not striptrailing blanks If the value is shorter than the defined width of the column, Oracleblank-pads the value to the defined width As a result, information about trailingblanks is lost If the character value is longer than the defined width of the column,Oracle aborts the insert and generates an error
When you insert a character value into aVARCHAR2 database column, Oracle does notstrip trailing blanks If the value is shorter than the defined width of the column,Oracle does not blank-pad the value Character values are stored intact, so noinformation is lost If the character value is longer than the defined width of thecolumn, Oracle aborts the insert and generates an error
Note: The same rules apply when updating
When inserting character values, to ensure that no trailing blanks are stored, use thefunctionRTRIM, which trims trailing blanks An example follows:
DECLARE
my_name VARCHAR2(15);
BEGIN
my_ename := 'LEE '; note trailing blanks INSERT INTO emp
VALUES (my_empno, RTRIM(my_ename), ); inserts 'LEE' END;
Selecting Character Values
When you select a value from an Oracle database column into a PL/SQL charactervariable, whether the value is blank-padded or not depends on the variable type, not
on the column type
When you select a column value into aCHAR variable, if the value is shorter than thedeclared length of the variable, PL/SQL blank-pads the value to the declared length
As a result, information about trailing blanks is lost If the character value is longerthan the declared length of the variable, PL/SQL aborts the assignment and raisesVALUE_ERROR
When you select a column value into aVARCHAR2 variable, if the value is shorter thanthe declared length of the variable, PL/SQL neither blank-pads the value nor stripstrailing blanks Character values are stored intact, so no information is lost
For example, when you select a blank-paddedCHAR column value into aVARCHAR2variable, the trailing blanks are not stripped If the character value is longer than thedeclared length of theVARCHAR2 variable, PL/SQL aborts the assignment and raisesVALUE_ERROR
Note: The same rules apply when fetching
Trang 13Selecting Character Values
B-4 PL/SQL User's Guide and Reference
Trang 14Obfuscating Source Code with the PL/SQL Wrap Utility C-1
This appendix contains these topics:
■ Advantages of Wrapping PL/SQL Procedures on page C-1
■ Running the PL/SQL Wrap Utility on page C-1
■ Limitations of the PL/SQL Wrap Utility on page C-3
Advantages of Wrapping PL/SQL Procedures
■ By hiding application internals, the wrap utility makes it difficult for otherdevelopers to misuse your application, or business competitors to see youralgorithms
■ Your code is not visible through theUSER_SOURCE,ALL_SOURCE, orDBA_
SOURCE data dictionary views
■ SQL*Plus can process wrapped files You can obfuscate source files that createPL/SQL procedures and packages
■ The Import and Export utilities accept wrapped files You can back up or movewrapped procedures
Running the PL/SQL Wrap Utility
To run the wrap utility, enter thewrap command at your operating system promptusing the following syntax:
wrap iname=input_file [oname=output_file]
Note: Do not use any spaces around the equal signs
input_file is the name of a file containing SQL statements, that you typically runusing SQL*Plus If you omit the file extension, an extension of.sql is assumed Forexample, the following commands are equivalent:
wrap iname=/mydir/myfile wrap iname=/mydir/myfile.sqlYou can also specify a different file extension:
Trang 15Running the PL/SQL Wrap Utility
C-2 PL/SQL User's Guide and Reference
wrap iname=/mydir/myfile.src
output_file is the name of the obfuscated file that is created Theoname option isoptional, because the output file name defaults to that of the input file and itsextension defaults to.plb For example, the following commands are equivalent:wrap iname=/mydir/myfile
wrap iname=/mydir/myfile.sql oname=/mydir/myfile.plbYou can use the optiononame to specify a different file name and extension:
wrap iname=/mydir/myfile oname=/yourdir/yourfile.out
Input and Output Files for the PL/SQL Wrap Utility
The input file can contain any combination of SQL statements Most statements arepassed through unchanged.CREATEstatements that define subprograms, packages, orobject types are obfuscated; their bodies are replaced by a scrambled form that thePL/SQL compiler understands
The following CREATE statements are obfuscated:
CREATE [OR REPLACE] FUNCTION function_name CREATE [OR REPLACE] PROCEDURE procedure_name CREATE [OR REPLACE] PACKAGE package_name CREATE [OR REPLACE] PACKAGE BODY package_name CREATE [OR REPLACE] TYPE type_name AS OBJECT CREATE [OR REPLACE] TYPE type_name UNDER type_name CREATE [OR REPLACE] TYPE BODY type_name
Note: TheCREATE [OR REPLACE] TRIGGER statement, andBEGIN END
anonymous blocks, are not obfuscated.
All other SQL statements are passed unchanged to the output file Most comment linesare deleted C-style comments (delimited by/* */) are preserved when they occur inthe middle of a SQL statement Comments are also preserved when they occur
immediately after theCREATE statement, before the obfuscated body starts
The output file is a text file, which you can run in SQL*Plus to set up your PL/SQLprocedures, functions, and packages:
SQL> @wrapped_file_name.plb;
Tips:
■ When wrapping a package or object type, wrap only the body, not the spec Thatway, other developers see the information they need to use the package or type,but they do not see its implementation
■ PL/SQL source inside wrapped files cannot be edited To change wrappedPL/SQL code, edit the original source file and wrap it again You can either holdoff on wrapping your code until it is ready for shipment to end-users, or includethe wrapping operation as part of your build environment
■ To be sure that all the important parts of your source code are obfuscated, view thewrapped file in a text editor before distributing it
Trang 16Limitations of the PL/SQL Wrap Utility
Obfuscating Source Code with the PL/SQL Wrap Utility C-3
Limitations of the PL/SQL Wrap Utility
■ Although wrapping a compilation unit helps to hide the algorithm and makesreverse-engineering hard, Oracle Corporation does not recommend it as a securemethod for hiding passwords or table names
■ Because the source code is parsed by the PL/SQL compiler, not by SQL*Plus, youcannot include substitution variables using the SQL*PlusDEFINE notation insidethe PL/SQL code You can use substitution variables in other SQL statements thatare not obfuscated
■ The wrap utility does not obfuscate the source code for triggers To hide theworkings of a trigger, you can write a one-line trigger that calls a wrappedprocedure
■ Some, but not all, comments are removed in wrapped files
■ If your PL/SQL compilation units contain syntax errors, the wrap utility detectsand reports them The wrap utility does not detect semantic errors, such as tables
or views that do not exist Those errors are detected when you run the output file
in SQL*Plus
■ The Wrap Utility is upward-compatible between Oracle releases, but is notdownward-compatible For example, you can load files processed by the V8.1.5wrap utility into a V8.1.6 Oracle database, but you cannot load files processed bythe V8.1.6 wrap utility into a V8.1.5 Oracle database
Trang 17Limitations of the PL/SQL Wrap Utility
C-4 PL/SQL User's Guide and Reference
Trang 18How PL/SQL Resolves Identifier Names D-1
D
How PL/SQL Resolves Identifier Names
This appendix explains how PL/SQL resolves references to names in potentiallyambiguous SQL and procedural statements
This appendix contains these topics:
■ What Is Name Resolution? on page D-1
■ Examples of Qualified Names and Dot Notation on page D-2
■ Differences in Name Resolution Between SQL and PL/SQL on page D-3
■ Understanding Capture on page D-3
■ Avoiding Inner Capture in DML Statements on page D-4
■ Qualifying References to Object Attributes and Methods on page D-5
■ Calling Parameterless Subprograms and Methods on page D-5
■ Name Resolution for SQL Versus PL/SQL on page D-6
What Is Name Resolution?
During compilation, the PL/SQL compiler determines which objects are associatedwith each name in a PL/SQL subprogram A name might refer to a local variable, atable, a package, a procedure, a schema, and so on When a subprogram is recompiled,that association might change if objects have been created or deleted
A declaration or definition in an inner scope can hide another in an outer scope In thefollowing example, the declaration of variableclienthides the definition of datatypeClient because PL/SQL names are not case sensitive:
BEGIN <<block1>>
DECLARE TYPE Client IS RECORD ( );
TYPE Customer IS RECORD ( );
BEGIN DECLARE client Customer; hides definition of type Client in outer scope
lead1 Client; not allowed; Client resolves to the variable client
lead2 block1.Client; OK; refers to type Client BEGIN
NULL;
END;
Trang 19Examples of Qualified Names and Dot Notation
D-2 PL/SQL User's Guide and Reference
CREATE TYPE manager AS OBJECT (dept NUMBER);
/ CREATE TYPE person AS OBJECT (manager NUMBER, mgr manager);
/
Examples of Qualified Names and Dot Notation
During name resolution, the compiler can encounter various forms of referencesincluding simple unqualified names, dot-separated chains of identifiers, indexedcomponents of a collection, and so on For example:
FUNCTION f1 (p1 NUMBER) RETURN t1;
FUNCTION f2 (q1 NUMBER) RETURN t2;
n := pkg1.f1.p1; (3) dot-separated chain of identifiers (package name used as scope qualifier followed by function name also used as scope qualifier followed by parameter name)
n := v1.a; (4) dot-separated chain of identifiers (variable name followed by
component selector)
n := pkg1.v1.a; (5) dot-separated chain of identifiers (package name used as scope qualifier followed by variable name followed by component selector)
n := v2(10).a; (6) indexed name followed by component selector
n := f1(10).a; (7) function call followed by component selector
n := f2(10)(10).a; (8) function call followed by indexing followed by component selector
n := scott.pkg1.f2(10)(10).a;
(9) function call (which is a
Trang 20dot-Understanding Capture
How PL/SQL Resolves Identifier Names D-3
separated chain of identifiers, including schema name used as scope qualifier followed by package name used as scope qualifier followed by function name) followed by component selector of the returned result followed by indexing followed by component selector
n := scott.pkg1.f1.n;
(10) dot-separated chain of identifiers (schema name used as scope qualifier followed by package name also used as scope qualifier followed by function name also used as scope qualifier followed by local variable name)
Differences in Name Resolution Between SQL and PL/SQL
When the PL/SQL compiler processes a SQL statement, such as a DML statement, ituses the same name-resolution rules as SQL For example, for a name such asSCOTT.FOO, SQL matches objects in theSCOTT schema first, then packages, types,tables, and views in the current schema
PL/SQL uses a different order to resolve names in PL/SQL statements such asassignments and procedure calls In the case of a nameSCOTT.FOO, PL/SQL searchesfirst for packages, types, tables, and views namedSCOTT in the current schema, thenfor objects in theSCOTT schema
Understanding Capture
When a declaration or type definition in another scope prevents the compiler fromresolving a reference correctly, that declaration or definition is said to "capture" thereference Usually this is the result of migration or schema evolution There are threekinds of capture: inner, same-scope, and outer Inner and same-scope capture applyonly in SQL scope
Inner Capture
An inner capture occurs when a name in an inner scope no longer refers to an entity in
an outer scope:
■ The name might now resolve to an entity in an inner scope
■ The program might cause an error, if some part of the identifier is captured in aninner scope and the complete reference cannot be resolved
If the reference points to a different but valid name, you might not know why theprogram is acting differently