Archive for lang

Oracle PL/SQL (10.2)

Block Structure

 
[DECLARE
  -- declarations]
BEGIN
[EXCEPTION
  -- handlers]
END;
 

Variables

Declaring Variables

* SQL data types

 
DECLARE
  part_no NUMBER(6);
  part_name VARCHAR2(20);
  in_stock BOOLEAN;
  part_price NUMBER(6,2);
  part_desc VARCHAR2(50);
 

* %TYPE, %ROWTYPE

 
v_last_name employees.last_name%TYPE;
dept_rec departments%ROWTYPE;
 
 
DECLARE
  CURSOR c1 IS
  SELECT last_name, salary, hire_date, job_id FROM employees
  WHERE employee_id = 120;
  -- declare record variable that represents a row fetched from the employees table
  employee_rec c1%ROWTYPE;
BEGIN
  -- open the explicit cursor and use it to fetch data into employee_rec
  OPEN c1;
  FETCH c1 INTO employee_rec;
  DBMS_OUTPUT.PUT_LINE('Employee name: ' || employee_rec.last_name);
END;
 

Declaring Constants

Use 'CONSTANT' qualifier.

 
credit_limit CONSTANT NUMBER := 5000.00;
 

Assign Values to Variables

* Use assignment operator ':='

 
DECLARE
  wages NUMBER;
  hours_worked NUMBER := 40;
  hourly_salary NUMBER := 22.50;
  bonus NUMBER := 150;
  country VARCHAR2(128);
  counter NUMBER := 0;
  done BOOLEAN;
  valid_id BOOLEAN;
  emp_rec1 employees%ROWTYPE;
  emp_rec2 employees%ROWTYPE;
  TYPE commissions IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
  comm_tab commissions;
 

* Use select into

 
DECLARE
  bonus NUMBER(8,2);
  emp_id NUMBER(6) := 100;
BEGIN
  SELECT salary * 0.10 INTO bonus FROM employees
  WHERE employee_id = emp_id;
END;

* Pass values into PL/SQL as OUT or IN OUT parameters

 
DECLARE
  new_sal NUMBER(8,2);
  emp_id NUMBER(6) := 126;
PROCEDURE adjust_salary(emp_id NUMBER, sal IN OUT NUMBER) IS
  emp_job VARCHAR2(10);
  avg_sal NUMBER(8,2);

Bind Variables

Use bind variables to reuse SQL statements.

 
'DELETE FROM employees WHERE employee_id = :id' USING emp_id;
 

Control Structures

IF THEN ELSE And CASE

 
DECLARE
  jobid employees.job_id%TYPE;
  empid employees.employee_id%TYPE := 115;
  sal employees.salary%TYPE;
  sal_raise NUMBER(3,2);
BEGIN
  SELECT job_id, salary INTO jobid, sal FROM employees WHERE employee_id = empid;
  CASE
    WHEN jobid = 'PU_CLERK' THEN
      IF sal < 3000 THEN sal_raise := .12;
      ELSE sal_raise := .09;
      END IF;
    WHEN jobid = 'SH_CLERK' THEN
      IF sal < 4000 THEN sal_raise := .11;
      ELSE sal_raise := .08;
      END IF;
    WHEN jobid = 'ST_CLERK' THEN
      IF sal < 3500 THEN sal_raise := .10;
      ELSE sal_raise := .07;
      END IF;
    ELSE
      BEGIN
        DBMS_OUTPUT.PUT_LINE('No raise for this job: ' || jobid);
      END;
  END CASE;
  UPDATE employees SET salary = salary + salary * sal_raise
    WHERE employee_id = empid;
  COMMIT;
END;

FOR LOOP

 
CREATE TABLE sqr_root_sum (num NUMBER, sq_root NUMBER(6,2),
  sqr NUMBER, sum_sqrs NUMBER);
DECLARE
  s PLS_INTEGER;
BEGIN
  FOR i IN 1..100 LOOP
    s := (i * (i + 1) * (2*i +1)) / 6; -- sum of squares
    INSERT INTO sqr_root_sum VALUES (i, SQRT(i), i*i, s );
  END LOOP;
END;

WHILE LOOP

 
WHILE sal <= 15000 LOOP -- loop until sal > 15000
  SELECT salary, manager_id, last_name INTO sal, mgr_id, lname
  FROM employees WHERE employee_id = mgr_id;
END LOOP;

EXIT WHEN

 
LOOP
  counter := counter + 1;
  total := total + counter * counter;
  -- exit loop when condition is true
  EXIT WHEN total > 25000;
END LOOP;

Subprograms: Procedures and Functions

* Subprograms can be procedures and functions.
- Functions can return a value, procedure not. Procedures can only have OUT parameters.
- Function can be used in a select statement, procedures not.

Packages

* Packages related types and procedures together.
* Define package

 
CREATE OR REPLACE PACKAGE emp_actions AS -- package specification
  PROCEDURE hire_employee (employee_id NUMBER, last_name VARCHAR2,
    first_name VARCHAR2, email VARCHAR2, phone_number VARCHAR2,
    hire_date DATE, job_id VARCHAR2, salary NUMBER, commission_pct NUMBER,
    manager_id NUMBER, department_id NUMBER);
  PROCEDURE fire_employee (emp_id NUMBER);
  FUNCTION num_above_salary (emp_id NUMBER) RETURN NUMBER;
END emp_actions;
/
 
CREATE OR REPLACE PACKAGE BODY emp_actions AS -- package body
  -- code for procedure hire_employee
  PROCEDURE hire_employee (employee_id NUMBER, last_name VARCHAR2,
    first_name VARCHAR2, email VARCHAR2, phone_number VARCHAR2, hire_date DATE,
    job_id VARCHAR2, salary NUMBER, commission_pct NUMBER,
    manager_id NUMBER, department_id NUMBER) IS
  BEGIN
    INSERT INTO employees VALUES (employee_id, last_name, first_name, email,
    phone_number, hire_date, job_id, salary, commission_pct, manager_id,
    department_id);
  END hire_employee;
 
  -- code for procedure fire_employee
  PROCEDURE fire_employee (emp_id NUMBER) IS
    BEGIN
    DELETE FROM employees WHERE employee_id = emp_id;
  END fire_employee;
 
  -- code for function num_above salary
  FUNCTION num_above_salary (emp_id NUMBER) RETURN NUMBER IS
    emp_sal NUMBER(8,2);
    num_count NUMBER;
  BEGIN
    SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
    SELECT COUNT(*) INTO num_count FROM employees WHERE salary > emp_sal;
    RETURN num_count;
  END num_above_salary;
END emp_actions;

* Use package

 
CALL emp_actions.hire_employee(300, 'Belden', 'Enrique', 'EBELDEN',
  '555.111.2222', '31-AUG-04', 'AC_MGR', 9000, .1, 101, 110);
BEGIN
  DBMS_OUTPUT.PUT_LINE( 'Number of employees with higher salary: ' ||
  TO_CHAR(emp_actions.num_above_salary(120)));
  emp_actions.fire_employee(300);
END;

Data Abstraction

Cursors

* Points to a private SQL area.

 
DECLARE
  CURSOR c1 IS
    SELECT last_name, salary, hire_date, job_id FROM employees
    WHERE employee_id = 120;
  -- declare record variable that represents a row fetched from the employees table
  employee_rec c1%ROWTYPE;
BEGIN
  -- open the explicit cursor and use it to fetch data into employee_rec
  OPEN c1;
  FETCH c1 INTO employee_rec;
  DBMS_OUTPUT.PUT_LINE('Employee name: ' || employee_rec.last_name);
END;

Collections

* Ordered group of elements, all of the same type.
* Declare using TYPE definition.

VARRAY

* PL/SQL equivalent of an Array
* Can not have gaps in subscripts, i.e. is dense.

 
TYPE Calendar IS VARRAY(366) OF DATE;

Nested Table

* PL/SQL equivalent of a Set
* One dimension array with no declared number of elements.
* Can have gaps in subscripts.
* Can be stored in database column.

 
TYPE nested_type IS TABLE OF VARCHAR2(30);

Associative Array

* aka index-by tables
* PL/SQL equivalent of Hashtable
* Can not be stored in database column.

 
DECLARE
  TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE
    INDEX BY PLS_INTEGER;
  emp_tab EmpTabTyp;
BEGIN
  /* Retrieve employee record. */
  SELECT * INTO emp_tab(100) FROM employees WHERE employee_id = 100;
END;
/
 
DECLARE
  TYPE staff_list IS TABLE OF employees.employee_id%TYPE;
  staff staff_list;
  lname employees.last_name%TYPE;
  fname employees.first_name%TYPE;
BEGIN
  staff := staff_list(100, 114, 115, 120, 122);
  FOR i IN staff.FIRST..staff.LAST LOOP
    SELECT last_name, first_name INTO lname, fname FROM employees
    WHERE employees.employee_id = staff(i);
    DBMS_OUTPUT.PUT_LINE ( TO_CHAR(staff(i)) || ': ' || lname || ', ' || fname );
  END LOOP;
END;
/
 
DECLARE
  TYPE nested_type IS TABLE OF VARCHAR2(30);
  TYPE varray_type IS VARRAY(5) OF INTEGER;
  TYPE assoc_array_num_type IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
  TYPE assoc_array_str_type IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER;
  TYPE assoc_array_str_type2 IS TABLE OF VARCHAR2(32) INDEX BY VARCHAR2(64);
  v1 nested_type;
  v2 varray_type;
  v3 assoc_array_num_type;
  v4 assoc_array_str_type;
  v5 assoc_array_str_type2;
BEGIN
  -- an arbitrary number of strings can be inserted v1
  v1 := nested_type('Shipping','Sales','Finance','Payroll');
  v2 := varray_type(1, 2, 3, 4, 5); -- Up to 5 integers
  v3(99) := 10; -- Just start assigning to elements
  Defining Collection Types AND Declaring Collection VARIABLES
  5-8 Oracle DATABASE PL/SQL User’s Guide AND Reference
  v3(7) := 100; -- Subscripts can be any integer values
  v4(42) := 'Smith'; -- Just start assigning to elements
  v4(54) := 'Jones'; -- Subscripts can be any integer values
  v5('Canada') := 'North America'; -- Just start assigning to elements
  v5('Greece') := 'Europe'; -- Subscripts can be string values
END;

Records

* Composite data structures (like C struct)
* Fields can have different data types.
* Use %ROWTYPE to declare a record that represents a row in a table.

 
DECLARE
  TYPE timerec IS RECORD (hours SMALLINT, minutes SMALLINT);
  TYPE meetin_typ IS RECORD (
    date_held DATE,
    duration timerec, -- nested record
    location VARCHAR2(20),
    purpose VARCHAR2(50));
BEGIN
  -- NULL does nothing but allows unit to be compiled and tested
  NULL;
END;
/

Object Types

* Contains both data (attributes) and functions (methods).

 
CREATE TYPE bank_account AS OBJECT (
  acct_number NUMBER(5),
  balance NUMBER,
  STATUS VARCHAR2(10),
 
  MEMBER PROCEDURE open (SELF IN OUT NOCOPY bank_account, amount IN NUMBER),
  MEMBER PROCEDURE close (SELF IN OUT NOCOPY bank_account, num IN NUMBER, amount OUT NUMBER),
  MEMBER PROCEDURE deposit (SELF IN OUT NOCOPY bank_account, num IN NUMBER, amount IN NUMBER),
  MEMBER PROCEDURE withdraw (SELF IN OUT NOCOPY bank_account, num IN NUMBER, amount IN NUMBER),
  MEMBER FUNCTION curr_bal (num IN NUMBER) RETURN NUMBER );
/

Exceptions

* Use RAISE statement to throw user defined exceptions.
* Use EXCEPTION to catch the exceptions.

 
EXCEPTION -- exception-handling part starts here
  WHEN comm_missing THEN
    DBMS_OUTPUT.PUT_LINE('This employee does not receive a commission.');
    commission := 0;
  WHEN OTHERS THEN
    NULL; -- for other exceptions do nothing

References

* PL/SQL User's Guide and Reference 10g Release 2 (10.2)

XML Naming Conventions

Here is great page summarizing various XML related naming specifications.
* Use of Camel Case for Naming XML and XML-Related Components
* FEDERAL XML NAMING AND DESIGN RULES
* Global Justice XML Data Model Naming and Design Rules

A Simple Java TLV Parser

* Read here for an explanation of TLV.
* In the following sample code, all found tag values are returned as a byte array containing individual tag values, each of which is itself a byte array.

 
    /**
     * Reads TLV values for a given hex string.
     */
    public static byte[][] readTLV(String tlvHexString, int tag) {
        return readTLV(hexStringToByteArray(tlvHexString), tag);
    }
 
    /**
     * Reads TLV values for a given byte array.
     */
    public static byte[][] readTLV(byte[] tlv, int tag) {
        if (tlv == null || tlv.length < 1) {
            throw new IllegalArgumentException("Invalid TLV");
        }
 
        int c = 0;
        ArrayList al = new ArrayList();
 
        ByteArrayInputStream is = null;
        try {
             is = new ByteArrayInputStream(tlv);
 
             while ((c = is.read()) != -1) {
                if (c == tag){
                    log.debug("Got tag");
                    if ((c = is.read()) != -1){
                        byte[] value = new byte[c];
                        is.read(value,0,c);
                        al.add(value);
                    }
                }
            }
        } finally {
            if (is != null) {
                try{
                    is.close();
                }catch (IOException e){
                    log.error(e);
                }
            }
        }
        log.debug("Got " + al.size() + " values for tag "
            + Integer.toHexString(tag));
        byte[][] vals = new byte[al.size()][];
        al.toArray(vals);
        return vals;
    }
 
    /**
     * Converts a hex string to byte array.
     */
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
 

Velocity Template

Configuration Properties

General Properties

 
input.encoding
output.encoding
parser.pool.size
runtime.interpolate.literals
runtime.introspector.uberspect
 

Logging Properties

 
# Log file location. Default to velocity.log in the execution path
runtime.log
# Which log system to use. Defaults to Avalon LogKit
runtime.log.logsystem.class=org.apache.velocity.runtime.log.SimpleLog4JLogSystem
# Output stack trace
runtime.log.xxx.stacktrace=true | false
# Long invalid references in template. Default to true. Should be turned off in prod.
runtime.log.invalid.references= true | false
 

Resource Loader Properties

 
resource.loader=file, class, jar
 
# File Resource Loader
file.resource.loader.class= org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path=./src/templates/ch2
file.resource.loader.cache=true
file.resource.loader.modificationCheckInterval=2
 
# Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
 
# JAR Resource Loader
jar.resource.loader.class = org.apache.velocity.runtime.resource.loader.JarResourceLoader
jar.resource.loader.path = jar:file:/tmp/ResourceLoader2.jar
 
# DataSourceResourceLoader
 

Directive Properties

 
directive.include.out-put.errormsg.start
directive.include.output.errormsg.end
 
## Maximum depth of parse (default to 10)
directive.parse.maxdepth
 
## default to velocityCount
directive.foreach.counter.name
## default to 1
directive.foreach.counter.initial.value
 

Macro Properties

 
velocimacro.library=macroLibrary.vm
velocimacro.permissions.allow.inline=true | false
velocimacro.permissions.allow.inline .to.replace.global=true | false
## If true, changes to variables inside macro are visible only inside macro
## Default to false
velocimacro.context.localscope=true | false
## Default to false
velocimacro.library.autoreload=true | false
## Determines whether an inline macro is visible outside the defining template
velocimacro.permissions.allow.inline.local.scope=true | false
 

Velocity Template Language (VTL)

* Comments

 
## Single line comment
#* Multiple
line comments *#
 

* Escape char

 
## Escape character is \
\$myName = $myName
 

* Variables

 
## Variable is prefixed with a dollar sign
$myName
 
## Formal reference of variables
${myName}
 
## Quiet reference which will not be displayed if not set
$!undefinedVar
 
## Access object method
$myDate.getDate()
$myDate.getMonth()
 
## Access Java bean variables
$myDate.Date
$myDate.Month
 
## Access Map variables
$myMap.firstName
 
## Create variables in a template
#set($msg = "Hello world!")
I have a message: $msg
 
#set($str = "A string")
#set($num = 123)
#set($bool = true)
 

* Performing arithmetic
- Supports + - * / %
* Logical operators
AND: &&
OR: ||
NOT: !

Directives

* Include

 
## include template as is, no parsing
#include("footer.vm")
 
## included template needs to be parsed
#parse("footer.vm")
 

* If/else
Comparison operators: ==, !=, <, >, <=, >=

 
#set($myBool = true)
#if($myBool)
It is true
#else
It is false
#end
 
#if ($myName == "John")
    Hello John!
#elseif ($myName == "Jane")
    Hello Jane!
#else
    Hello world!
#end
 

* Access collections with #foreach

 
## Define Velocity array
#set($myArray = ["one", "two", "three"])
#foreach($item in $myArray)
    List Item: $item
#end
 
## Use range
#foreach($num in [1..9])
    List number: $num
#end
 

* Macros

 
#macro(myMacro $param1 $param2)
     \$param1: $param1
     \$param2: $param2
    #foreach($num in [1..9])
        List number: $num
    #end
#end
Call macro
#myMacro("John", "Jane")
 

References

* http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html
* VTL Reference Guide
* Pro Jakarta Velocity: From Professional to Expert by Rob Harrop Apress © 2004