Wednesday 19 September 2007

Get IP Address and Hostname

There are legitimate times when you want your procedural code to gather the current host name or IP address and Oracle has several ways to do this:
The utl_inaddr procedure:
SQL> select utl_inaddr.get_host_address('www.detik.com')
2 hostname from dual;

HOSTNAME
-----------------
203.190.241.41

The sys_context procedure:
SQL> select SYS_CONTEXT('USERENV', 'IP_ADDRESS', 15) ipaddr from dual;

IPADDR
------------------
172.16.1.78

Tuesday 18 September 2007

Retrieving Only the Nth Row From a Table

How are we suppose to retrieve only the Nth row from a table?

SELECT * FROM table
WHERE rowid = (
SELECT rowid FROM table
WHERE rownum <= N
MINUS
SELECT rowid FROM table
WHERE rownum < N
);

Sunday 16 September 2007

Analytic Features - Grouping Sets

Grouping Sets - Instead of a UNION ALL statement (that would require multiple table scans), define a grouping set - the new syntax will result in only a single pass over the base table.
Grouping Sets are specified in the GROUP BY clause
Syntax:

SELECT group_function(column1), column2, group_function(column3)...
FROM table_list
[WHERE conditions]
GROUP BY GROUPING SETS (group_by_list)

SELECT group_function(column1), column2, group_function(column3)...
FROM table_list
[WHERE conditions]
GROUP BY CUBE (group_by_list)

SELECT group_function(column1), column2, group_function(column3)...
FROM table_list
[WHERE conditions]
GROUP BY ROLLUP (group_by_list)

Examples:
Instead of this UNION query...


SELECT
manager_id, null hire_date, count(*)
FROM
employees
GROUP BY manager_id, 2
UNION ALL
SELECT
null, hire_date, count(*)
FROM
employees
GROUP BY 1, hire_date

The above rewritten as a Grouping Set...

SELECT
manager_id, hire_date, count(*)
FROM
employees
GROUP BY GROUPING SETS (manager_id, hire_date);

The GROUPING SET clause allows you to specify the EXACT groups.

CUBE
Where a large number of groupings are needed then the CUBE and ROLLUP statements extend this idea by calculating multiple groupings in a single statement.

e.g. GROUP BY CUBE (hire_date, manager_id, product) will produce 2^3 =8 groupings
1) hire_date, manager_id, product
2) hire_date, manager_id
3) hire_date, product
4) manager_id, product
5) hire_date
6) manager_id
7) product
8) Grand Total

GROUP BY CUBE always calculates ALL the combinations - which may be far more than needed.

ROLLUP
e.g. GROUP BY ROLLUP (hire_date, manager_id, product) will produce 4 groupings
1) hire_date, manager_id, product
2) hire_date, manager_id
3) hire_date,
4) Grand Total

GROUP BY ROLLUP calculates all combinations for the first column listed in the ROLLUP clause.

This can be further tuned by using parenthesis to remove some of the combinations

e.g. GROUP BY ROLLUP (hire_date, (manager_id, product)) will produce
1) hire_date, manager_id, product
2) hire_date
3) Grand Total

Grouping function
CUBE and ROLLUP will generate NULLs for each dimension at the subtotal levels.
The Grouping() function can be used to identify these rows, which can be very useful when performing additional calculations such as Ranking within a group.

The values returned by grouping() are:
0 for NULL data values
1 for NULL indicating a dimension subtotal

The results of Grouping() can be passed into a decode() e.g.
SELECT .. PARTITION BY GROUPING(column1) ..
SELECT .. PARTITION BY DECODE(GROUPING(column1), 1, ‘My SubTotal’, column1)) …

Combining (concatenating) Groupings
The CUBE and ROLLUP clauses can be combined as part of a standard GROUP BY clause
e.g. GROUP BY manager_id, ROLLUP (hire_date, product)

Notes
Grouping sets are typically 80 - 90% more efficient at producing sub-totals than equivalent SQL code.

ROLLUP/CUBE can be used with all aggregate functions (MAX, MIN, AVG, etc.)

A HAVING clause will apply to all the data returned.

Oracle CASE SQL

Oracle SQL allows you to add "Boolean logic" and branching using the decode and CASE clauses. The case statement is a more flexible extension of the Decode statement. In its simplest form the Oracle CASE function is used to return a value when a match is found:

SELECT last_name, commission_pct,
(CASE commission_pct
WHEN 0.1 THEN ‘Low’
WHEN 0.15 THEN ‘Average’
WHEN 0.2 THEN ‘High’
ELSE ‘N/A’
END ) Commission
FROM employees ORDER BY last_name;

A more complex version is the Searched CASE expression where a comparison expression is used to find a match:

SELECT last_name, job_id, salary,
(CASE
WHEN job_id LIKE 'SA_MAN' AND salary < 12000 THEN '10%'
WHEN job_id LIKE 'SA_MAN' AND salary >= 12000 THEN '15%'
WHEN job_id LIKE 'IT_PROG' AND salary < 9000 THEN '8%'
WHEN job_id LIKE 'IT_PROG' AND salary >= 9000 THEN '12%'
ELSE 'NOT APPLICABLE'
END ) Raise
FROM employees;

Character Functions

Character Functions accept character input.
The input may come from a column in a table or from any expression.
Character Functions List

  1. ASCII(x) returns the ASCII value of the character x.
  2. CHR(x) returns the character with the ASCII value of x.
  3. CONCAT(x, y) concatenates y to x and return the appended string.
  4. INITCAP(x) converts the initial letter of each word in x to uppercase and returns that string.
  5. INSTR(x, find_string [, start] [, occurrence]) searches for find_string in x and returns the position at which find_string occurs.
  6. INSTRB(x) returns the location of a string within another string, but returns the value in bytes for a single-byte character system.
  7. LENGTH(x) returns the number of characters in x.
  8. LENGTHB(x) returns the length of a character string in bytes, except that the return value is in bytes for single-byte character sets.
  9. LOWER(x) converts the letters in x to lowercase and returns that string.
  10. LPAD(x, width [, pad_string]) pads x with spaces to left, to bring the total length of the string up to width characters.
  11. LTRIM(x [, trim_string]) trims characters from the left of x.
  12. NANVL(x, value) returns value if x matches the NaN special value (not a number), otherwise x is returned.
  13. NLS_INITCAP(x) Same as the INITCAP function except that it can use a different sort method as specified by NLSSORT.
  14. NLS_LOWER(x) Same as the LOWER function except that it can use a different sort method as specified by NLSSORT.
  15. NLS_UPPER(x) Same as the UPPER function except that it can use a different sort method as specified by NLSSORT.
  16. NLSSORT(x) Changes the method of sorting the characters. Must be specified before any NLS function; otherwise, the default sort will be used.
  17. NVL(x, value) returns value if x is null; otherwise, x is returned.
  18. NVL2(x, value1, value2) returns value1 if x is not null; if x is null, value2 is returned.
  19. REPLACE(x, search_string, replace_string) searches x for search_string and replaces it with replace_string.
  20. RPAD(x, width [, pad_string]) pads x to the right.
  21. RTRIM(x [, trim_string]) trims x from the right.
  22. SOUNDEX(x) returns a string containing the phonetic representation of x.
  23. SUBSTR(x, start [, length]) returns a substring of x that begins at the position specified by start. An optional length for the substring may be supplied.
  24. SUBSTRB(x) Same as SUBSTR except the parameters are expressed in bytes instead of characters to handle single-byte character systems.
  25. TRIM([trim_char FROM) x) trims characters from the left and right of x.
  26. UPPER(x) converts the letters in x to uppercase and returns that string.

Monday 10 September 2007

Bigfile Tablespace

A bigfile tablespace (BFT) is a tablespace containing a single file that can have a very large size.

Bigfile Tablespace Overview
The traditional tablespace is referred to as a smallfile tablespace (SFT). A smallfile tablespace contains multiple, relatively small files. The bigfile tablespace has the following characteristics:

  • An Oracle database can contain both bigfile and smallfile tablespaces.
  • System default is to create the traditional smallfile tablespace.
  • The SYSTEM and SYSAUX tablespaces are always created using the system default type.
  • Bigfile tablespaces are supported only for locally managed tablespaces with automatic segment-space management.
There are two exceptions when bigfile tablespace segments are manually managed:
  • Locally managed undo tablespace
  • Temporary tablespace
Bigfile tablespaces are intended to be used with Automated Storage Management (ASM) (see Chapter 1) or other logical volume managers that support RAID.

However, you can also use it without ASM.

Bigfile Tablespace Benefits
Bigfile tablespace has the following benefits:
  • It simplifies large database tablespace management by reducing the number of datafiles needed.
  • It simplifies datafile management with Oracle-managed files and Automated Storage Management (ASM) by eliminating the need for adding new datafiles and dealing with multiple files.
  • It allows you to create a bigfile tablespace of up to eight exabytes (eight million terabytes) in size, and significantly increase the storage capacity of an Oracle database.
  • It follows the concept that a tablespace and a datafile are logically equivalent.
Maximum Database Size

The BFT extended the maximum size of tablespace and database. Let’s take a look at the two formulas that calculate the maximum size of data file and database.

The maximum data file size is calculated by:

Maximum datafile size = db_block_size * maximum number of blocks

The maximum amount of data in an Oracle database is calculated by:

Maximum database size = maximum datafile size * maximum number of datafile

The maximum number of datafiles in Oracle9i and Oracle 10g Database is 65,536. However, the maximum number of blocks in a data file increase from 4,194,304 (4 million) blocks to 4,294,967,296 (4 billion) blocks.

The maximum amount of data for a 32K block size database is eight petabytes (8,192 Terabytes) in Oracle9i.
The maximum amount of data for a 32K block size database is eight exabytes (8,388,608 Terabytes) in Oracle 10g.
As you can see, with the new BFT addressing scheme, Oracle 10g can contain astronomical amounts of data within a single database.

Sunday 9 September 2007

Oracle Listener security

The first thing to do is to put a password on your listener. By default the listener comes with no password, and anyone can change listener settings through the lsnrctl tool.
To password protect your listener, perform the following as your Oracle user:

$ lsnrctl
LSNRCTL> change_password
Old password:
New password:
Reenter new password:


If you have done all of this correctly, you will see the following:

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))
Password changed for
The command completed successfully


Just as a note, if the listener you are protecting does not have the default name of LISTENER, you must do set cur before issuing the change_password command.

At this point, save the configuration of the listener to the file system. If you are on 10g, it will save with no problems:

LSNRCTL> save_config
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))
Saved configuration parameters.
Listener Parameter File /listener.ora
Old Parameter File /listener.bak
The command completed successfully


And you have a password protected listener.

However, this does not happen on 9i. If you perform a save_config, you will see the following:

LSNRCTL> save_config
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))
TNS-01169: The listener has not recognized the password


The reason is this: in Oracle 10g, operating system authentication for the listener has been implemented. The listener checks to make sure you are part of the privileged dba group, and if so it will grant you access to change the password, save configuration, stop the listener, etc. In 9i, we must do the following at this point:

LSNRCTL> set password
Password:
The command completed successfully


At this point, you can now perform a save_config.

So what is the result of this? In 9i, you will now require a password whenever you wish to stop the listener or any other "destructive" listener actions. In 10g, if you are not logged into the operating system with a privileged account, you will have to enter a password as well. A typical listener stop may look like this:

$ lsnrctl
LSNRCTL> stop
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))
TNS-01169: The listener has not recognized the password
LSNRCTL> set password
Password:
The command completed successfully
LSNRCTL> stop
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))
The command completed successfully


You are now protected against unauthorized shutdowns of your listener. This protects you from a whole range of possible security breaches. Remember that "set password" is how you enter your password for authentication; change_password is how it is changed.

Cursors

Implicit cursors
Whenever a SQL statement is issued the Database server opens an area of memory in which the command is parsed and executed. This area is called a cursor. Microsoft tends to refer to cursors as datasets throughout much of their databse product documentation..

When the executable part of a PL/SQL block issues a SQL command, PL/SQL creates an implicit cursor which has the identifier SQL. PL/SQL manages this cursor for you.

PL/SQL provides some attributes which allow you to evaluate what happened when the implicit cursor was last used. You can use these attributes in PL/SQL statements like functions but you cannot use then within SQL statements.
The SQL cursor attributes are :

  • %ROWCOUNT:The number of rows processed by a SQL statement.
  • %FOUND: TRUE if at least one row was processed.
  • %NOTFOUND: TRUE if no rows were processed.
  • %ISOPEN:TRUE if cursor is open or FALSE if cursor has not been opened or has been closed. Only used with explicit cursors
Example:
DECLARE
ROW_DEL_NO NUMBER;
BEGIN
DELETE * FROM JD11.SECTION;
ROW_DEL_NO := SQL%ROWCOUNT;
END;


Explicit cursors
SELECT statements that occur within PL/SQL blocks are known as embedded, they must return one row and may only return one row. To get around this you can define a SELECT statement as a cursor (an area of memory), run the query and then manipulate the returned rows within the cursor. Cursors are controlled via four command statements.
They are :
  • DECLARE:Defines the name and structure of the cursor together with the SELECT statement that will populate the cursor with data. The query is validated but not executed.
  • OPEN: Executes the query that populates the cursor with rows.
  • FETCH:Loads the row addressed by the cursor pointer into variables and moves the cursor pointer on to the next row ready for the next fetch.
  • CLOSE:Releases the data within the cursor and closes it. The cursor can be reopened to refresh its data.
Cursors are defined within a DECLARE section of a PL/SQL block. For example:
DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;


The cursor is defined by the CURSOR keyword followed by the cursor identifier (MYCUR in this case) and then the SELECT statement used to populate it, the SELECT statement can be any legal query.

Cursors are opened with the OPEN statement, this populates the cursor with data.
DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
BEGIN
OPEN MYCUR;
END;


To access the rows of data within the cursor we use the FETCH statement.

DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
THISISBN NUMBER(10);
THISCOST NUMBER(10,2);
BEGIN
OPEN MYCUR;
FETCH MYCUR INTO THISISBN, THISCOST;
END;


The FETCH statement reads the column values for the current cursor row and puts them into the specified variables. The cursor pointer is updated to point at the next row. If the cursor has no more rows the variables will be set to null on the first FETCH attempt, subsequent FETCH attempts will raise an exception.

The CLOSE statement releases the cursor and any rows within it, you can open the cursor again to refresh the data in it.

DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
THISISBN NUMBER(10);
THISCOST NUMBER(10,2);
BEGIN
OPEN MYCUR;
FETCH MYCUR INTO THISISBN, THISCOST;
CLOSE MYCUR;
END;


To process all the rows within a cursor we simply need to place the FETCH statement in a loop and check the cursor NOTFOUND attribute to see if we successfully fetched a row or not.

DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
THISISBN NUMBER(10);
THISCOST NUMBER(10,2);
BEGIN
OPEN MYCUR;
LOOP
FETCH MYCUR INTO THISISBN, THISCOST;
EXIT WHEN MYCUR%NOTFOUND;
END LOOP;
CLOSE MYCUR;
END;


PL/SQL records may be based on a cursor. This is very convenient for processing rows from the active data set. An example follows :

DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
PARTBOOK MYCUR%ROWTYPE;
BEGIN
OPEN MYCUR;
LOOP
FETCH MYCUR INTO PARTBOOK;
EXIT WHEN MYCUR%NOTFOUND;
IF PARTBOOK.ISBN = 21 THEN
PARTBOOK.COST = 19.10;
END IF;
END LOOP;
CLOSE MYCUR;
END;


You can use the WHERE CURRENT OF clause to execute DML commands against the current row of a cursor, this makes it easier to update rows. An example is below :

DECLARE
CURSOR MYCUR IS SELECT ISBN, COST FROM JD11.BOOK;
PARTBOOK MYCUR%ROWTYPE;
BEGIN
OPEN MYCUR;
LOOP
FETCH MYCUR INTO PARTBOOK;
EXIT WHEN MYCUR%NOTFOUND;
IF PARTBOOK.ISBN = 21 THEN
DELETE FROM JD11.BOOK WHERE CURRENT OF MYCUR;
END IF;
END LOOP;
CLOSE MYCUR;
END;

Note that I didn’t need to explicitly specify the row that I want deleted, PL/SQL supplies the required row identifier from the current record in the cursor ensuring that only the correct row is deleted.

It’s possible to vary the returned result set by using parameters, parameters allow you to specify the query selection criteria when you open the cursor.

DECLARE
CURSOR MYCUR (PARAM1 NUMBER) IS SELECT ISBN, COST FROM JD11.BOOK WHERE ISBN = PARAM1;
PARTBOOK MYCUR%ROWTYPE;
BEGIN
OPEN MYCUR(21);
FETCH MYCUR INTO PARTBOOK;
CLOSE MYCUR;
OPEN MYCUR(101);
FETCH MYCUR INTO PARTBOOK;
CLOSE MYCUR;
END;

Thursday 6 September 2007

Blocking Oracle access by IP Address

Now comes the fun part: keeping people out of your database! While IP-based blocking is not as suitable as a full firewall, you are able to block clients based on their IP address or hostname.

The secret lies in the SQLNET.ORA file. This file can be found in your $ORACLE_HOME/network/admin directory along with your tnsnames.ora and listener.ora. Open it up and insert the following line:

tcp.validnode_checking = yes

This turns on the hostname/IP checking for your listeners. After this, you can supply lists of nodes to enable/disable, as such:

tcp.invited_nodes = (hostname1, hostname2)
tcp.excluded_nodes = (172.16.1.3)

Note that if you only specify invited nodes, all others will be excluded, so there is really no reason to do both. The same goes for excluded nodes: exclude a list of clients, invite all others.

Even though this will not protect you against advanced attacks (IP and hostname are easy to spoof) it still serves as a deterrent against hacking attempts.

Here are some rules for entering invited/excluded nodes:

  • You cannot use wildcards in your specifications.
  • You must put all invited nodes in one line; likewise for excluded nodes.
  • You should always enter localhost as an invited node.
Once you have set up your rules and enabled valid node checking, you must restart your listeners to reap the benefits.Here is an example:

PayrollDB is a database server, accessed by Payroll
BankingDB is a database server, accessed by Banking
BApp1, BApp2, andBApp3 are application servers using the BankingDB
PApp1, PApp2, and PApp3 are application servers using the PayrollDB

The sqlnet.ora on PayrollDB would look like this:

tcp.validnode_checking = yes
tcp.invited_nodes = (localhost, PayrollDB, PApp1, PApp2, PApp3)

The sqlnet.ora on SalesDB would look like this:

tcp.validnode_checking = yes
tcp.invited_nodes = (localhost, BankingDB, BApp1, BApp2, BApp3)

Once this has been done, restart the listener.

$ lsnrctl

LSNRCTL> set password
Password:

The command completed successfully

LSNRCTL> stop
The command completed successfully

LSNRCTL> start


Now PApp1, PApp2, and PApp3 can access PayrollDB but not BankingDB; the same goes for the Banking application servers' access to PayrollDB.

PL/SQL Records

A PL/SQL record is a variable that contains a collection of separate fields. Each field is individually addressable. You can reference the field names in both assignments and expressions. The fields within a record may have different datatypes and sizes, like the columns of a database table. Records are a convenient way of storing a complete fetched row from a database table.

Use the %ROWTYPE attribute to declare a record based upon a collection of database columns from a table or view. The fields within the record take their names and datatypes from the columns of the table or view.

Declare the record in the DECLARE section along with any other required variables and constants. An example follows :
DECLARE
REC1 JD11.BOOK%ROWTYPE;
REC4 JD11.BOOK%ROWTYPE;

The above declaration sets the object REC1 to be a record object holding fields that match the columns in the BOOK table. It doesn't hold any values until it is populated.

Assign values into a PL/SQL record by naming the record after the INTO keyword of a SELECT statement. The INTO keyword defines the name specification for the storage area(s) of queried value(s).
BEGIN
SELECT * FROM JD11.BOOK INTO REC1 WHERE ISBN = 21;
END;

You can assign all the record values from one record to another provided that the record definitions are the same.

BEGIN
REC4 := REC1;
END;

Reference the field values within a PL/SQL record like this :

BEGIN
REC4 := REC1;
IF REC4.COST > 0 THEN
REC4.SECTION_ID := 10;
ELSE
REC4.SECTION_ID := 7;
END IF;
END;

Discovering PL/SQL Errors

PL/SQL does not always tell you about compilation errors. Instead, it gives you a cryptic message such as "procedure created with compilation errors". If you don't see what is wrong immediately, try issuing the command

show errors procedure ;

Alternatively, you can type, SHO ERR (short for SHOW ERRORS) to see the most recent compilation error.

Note that the location of the error given as part of the error message is not always accurate!

Control Flow in PL/SQL

PL/SQL allows you to branch and create loops in a fairly familiar way.
An IF statement looks like:

IF THEN ELSE END IF;

The ELSE part is optional. If you want a multiway branch, use:

IF THEN ...

ELSIF THEN ...
... ...
ELSIF THEN ...

ELSE ...

END IF;

Loops are created with the following:

LOOP
/* A list of statements. */
END LOOP;

At least one of the statements in should be an EXIT statement of the form

EXIT WHEN ;

The loop breaks if is true.
Some other useful loop-forming statements are:

  • EXIT by itself is an unconditional loop break. Use it inside a conditional if you like.
  • A WHILE loop can be formed with
    WHILE LOOP

    END LOOP;
  • A simple FOR loop can be formed with:
    FOR IN .. LOOP

    END LOOP;
    Here, can be any variable; it is local to the for-loop and need not be declared. Also, and are constants.

Wednesday 5 September 2007

Variables and Types

Information is transmitted between a PL/SQL program and the database through variables. Every variable has a specific type associated with it. That type can be :

  • One of the types used by SQL for database columns
  • A generic type used in PL/SQL such as NUMBER
  • Declared to be the same as the type of some database column
The most commonly used generic type is NUMBER. Variables of type NUMBER can hold either an integer or a real number. The most commonly used character string type is VARCHAR(n), where n is the maximum length of the string in bytes. This length is required, and there is no default. For example, we might declare:

DECLARE
price NUMBER;
myBeer VARCHAR(20);

Note that PL/SQL allows BOOLEAN variables, even though Oracle does not support BOOLEAN as a type for database columns.
Types in PL/SQL can be tricky. In many cases, a PL/SQL variable will be used to manipulate data stored in a existing relation. In this case, it is essential that the variable have the same type as the relation column. If there is any type mismatch, variable assignments and comparisons may not work the way you expect. To be safe, instead of hard coding the type of a variable, you should use the %TYPE operator. For example:

DECLARE
myBeer Beers.name%TYPE;

gives PL/SQL variable myBeer whatever type was declared for the name column in relation Beers.
A variable may also have a type that is a record with several fields. The simplest way to declare such a variable is to use %ROWTYPE on a relation name. The result is a record type in which the fields have the same names and types as the attributes of the relation. For instance:

DECLARE
beerTuple Beers%ROWTYPE;

makes variable beerTuple be a record with fields name and manufacture, assuming that the relation has the schema Beers(name, manufacture).
The initial value of any variable, regardless of its type, is NULL. We can assign values to variables, using the ":=" operator. The assignment can occur either immediately after the type of the variable is declared, or anywhere in the executable portion of the program. An example:

DECLARE
a NUMBER := 3;
BEGIN
a := a + 1;
END;
.

run;

This program has no effect when run, because there are no changes to the database.

Scope of Block Objects

The scope of an object defines where it is visible, it is the area of the program logic that can legally refer to a given object.

A variable or object's (cursor, constant Etc.) scope is determined by the block that it is declared in. It is only available until the block it is defined in ends execution. Remember that block variables are defined under the DECLARE keyword.

For nested blocks an object defined in a parent block is available within all its child (nested blocks). The reverse is not true, objects defined in a child block are not visible to the parent.

If a nested block defines an object with the same name as an object in its parent block then only the local object is visible. Unlike Java there is no method provided to get at the parent object in this circumstance.

Basic PL/SQL Block Structure

PL/SQL stands for Procedural Language/SQL. PL/SQL extends SQL by adding constructs found in procedural languages, resulting in a structural language that is more powerful than SQL. The basic unit in PL/SQL is a block. All PL/SQL programs are made up of blocks, which can be nested within each other. Typically, each block performs a logical action in he program. A block has the following structure:

DECLARE

Definition of any variables or objects that are used within the declared block.

BEGIN

Statements that make up the block.

EXCEPTION

All exception handlers.

END;

example:
DECLARE
TEMP_COST NUMBER(10,2);
BEGIN
SELECT COST FROM JD11.BOOK INTO TEMP_COST WHERE ISBN = 21;
IF TEMP_COST > 0 THEN
UPDATE JD11.BOOK SET COST = (TEMP_COST*1.175) WHERE ISBN = 21;
ELSE
UPDATE JD11.BOOK SET COST = 21.32 WHERE ISBN = 21;
END IF;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO JD11.ERRORS (CODE, MESSAGE) VALUES(99, 'ISBN 21 NOT FOUND');
END;

As you can see there are several elements in the example that haven't been covered in SQL , these elements are the PL/SQL extensions. They include:
- Variables and Constants
- SQL Support
- Composite Datatypes
- Flow Control
- Built In Functions
- Cursor Handling
- Exception Handling
- Code Storage

The rules of block structure are :

  1. Every unit of PL/SQL must constitute a block. As a minimum there must be the delimiting words BEGIN and END around the executable statements.
  2. SELECT statements within PL/SQL blocks are embedded SQL (an ANSI category). As such they must return one row only. SELECT statements that return no rows or more than one row will generate an error. If you want to deal with groups of rows you must place the returned data into a cursor. The INTO clause is mandatory for SELECT statements within PL/SQL blocks (which are not within a cursor definition), you must store the returned values from a SELECT.
  3. If PL/SQL variables or objects are defined for use in a block then you must also have a DECLARE section.
  4. If you include an EXCEPTION section the statements within it are only processed if the condition to which they refer occurs. Block execution is terminated after an exception handling routine is executed.
  5. PL/SQL blocks may be nested, nesting can occur wherever an executable statement could be placed (including the EXCEPTION section).

Oracle DBA : Poor Oracle Performance

For an Oracle DBA, here are some reasons that was consider as the most common root-causes of poor Oracle performance:

  1. Bad Design – The number one offender to poor performance is over-normalization of Oracle tables, excessive (unused indexes) and 15-way table joins for what should be a simple fetch.
  2. Bad disk I/O configuration – Inappropriate use of RAID5, disk channel bottlenecks and poor disk striping.
  3. Object contention – Failing to set ASSM, freelists or freelist_groups for DML-active tables and indexes can cause very slow DML performance.
  4. Non-reentrant SQL – All SQL should use host variables/cursor_sharing=force to make SQL reusable within the library cache.
  5. Excessive nested loop joins – In 64-bit Oracle systems we have gigabytes available for RAM sorts and hash joins. Failing to set pga_aggregate_target to allow the CBO to choose hash joins can result in very slow SQL performance.
  6. Poor server optimization – Setting the server kernel parameters and I/O configuration (e.g. direct I/O) has a profound impact on Oracle performance.
  7. Poor Optimizer Statistics – Prior to Oracle 10g (automatic statistics), a common cause of poor SQL performance was missing/stale CBO statistics and missing histograms.
  8. Under-allocated RAM regions – Not allocating enough RAM for shared_pool_size, pga_aggregate_target and db_cache_size can cause an I/O-bound database.
  9. Un-set initialization parameters – Many of the initialization parameters are made to be set by the DBA (db_file_multiblock_read_count, optimizer_index_caching) and failing to set these parameters properly results in poorly optimized execution plans.
  10. Human Misfeasance – The DBA’s failure to monitor their database (STATSPACK/AWR), set-up exception reporting alerts (OEM) and adjusting their instance to match changing workloads is a major cause of poor performance.

Oracle temporary tablespace groups (10g)

A temporary tablespace group consists of only temporary tablespace, and has the following properties:

  1. It contains one or more temporary tablespaces.
  2. It contains only temporary tablespace.
  3. It is not explicitly created. It is created implicitly when the first temporary tablespace is assigned to it, and is deleted when the last temporary tablespace is removed from the group.
Temporary tablespace group has the following benefits:
  1. It allows multiple default temporary tablespaces to be specified at the database level.
  2. It allows the user to use multiple temporary tablespaces in different sessions at the same time.
  3. It allows a single SQL operation to use multiple temporary tablespaces for sorting.
Using a tablespace with a temporary tablespace group will result in the following select statement. However, using a tablespace without a temporary tablespace group will not return the select statement below.
select
tablespace_name, group_name
from
DBA_TABLESPACE_GROUPS;
TABLESPACE_NAME GROUP_NAME
--------------- -----------
TEMP01 TEMPGROUP_A
TEMP02 TEMPGROUP_A
TEMP03 TEMPGROUP_B

Example:
- Create a temporary tablespace and implicitly add it to a temporary tablespace group.

CREATE TEMPORARY TABLESPACE temp01
TEMPFILE ‘/u02/oradata/temp01.dbs’ SIZE 500M
TABLESPACE GROUP tempgroup_a;

- Create a temporary tablespace without assigning it to a temporary tablespace group.

The following two statements are exactly equivalent:

CREATE TEMPORARY TABLESPACE temp04
TEMPFILE ‘/u02/oradata/temp04.dbs’ SIZE 200M
TABLESPACE GROUP ‘’;

CREATE TEMPORARY TABLESPACE temp04
TEMPFILE ‘/u02/oradata/temp04.dbs’ SIZE 200M;

- Remove a temporary tablespace from a temporary tablespace group.

This statement will remove temporary tablespace temp04 from its original temporary tablespace group:

ALTER TABLESPACE temp04 TABLESPACE GROUP ‘‘;
- Add a temporary tablespace to a temporary tablespace group.

ALTER TABLESPACE temp03 TABLESPACE GROUP tempgroup_b;

- Assign a user to a default temporary tablespace group.

ALTER USER USER TEMPORARY TABLESPACE tempgroup_A;

In this case, user 'USER' will have multiple default temporary tablespaces (see Figure). A single SQL operation by 'USER' can use more than one temporary tablespace for sorting.

Killing Oracle Session

One of the most common mistakes are DBA's killing the wrong session. When killing a session, carefully review the session, process and SQL associated with the offensive task. Before killing the session, the DBA may decide to view the SQL being executed by the session.
Killing session with Oracle can be a challenge and different procedures exist within Windows and UNIX. Here are the steps that I use to kill an Oracle session:
1. Gather session information from Oracle
2. Kill the session at the OS-level
3. Kill the session within Oracle using the "alter system kill session" command:

  • UNIX - I always locate the Server PID (SPID) from v$process and issue the UNIX kill -9 command.
  • The Windows command to kill this session would be as follows:
    C:\oracle9i\bin>orakill ORCL92 768
In this example, the windows thread corresponding to the Oracle session can be killed in the operating system without ever logging into the database.
Here are the Oracle scripts example to gather information before killing a session:

session.sql script

rem session.sql - displays all connected sessions
set echo off;
set termout on;
set linesize 80;
set pagesize 60;
set newpage 0;

select
rpad(c.name||':',11)||rpad(' current logons='||
(to_number(b.sessions_current)),20)||'cumulative logons='||
rpad(substr(a.value,1,10),10)||'highwater mark='||
b.sessions_highwater Information
from
v$sysstat a,
v$license b,
v$database c
where
a.name = 'logons cumulative'
;

ttitle "dbname Database|UNIX/Oracle Sessions";

set heading off;
select 'Sessions on database '||substr(name,1,8) from v$database;
set heading on;

select
substr(a.spid,1,9) pid,
substr(b.sid,1,5) sid,
substr(b.serial#,1,5) ser#,
substr(b.machine,1,6) box,
substr(b.username,1,10) username,
-- b.server,
substr(b.osuser,1,8) os_user,
substr(b.program,1,30) program
from
v$session b,
v$process a
where
b.paddr = a.addr
and type='USER'
order by spid;
ttitle off;
set heading off;
select 'To kill, enter SQLPLUS> ALTER SYSTEM KILL SESSION',
''''||'SID, SER#'||''''||';' from dual;
spool off;

Oracle ORA-03113: end-of-file on communication channel

The ORA-03113: end-of-file on communication channel error is a generic error. The ORA-03113 error when connecting suggests that the connection was established, but lost later, like a timeout.
There are many possible causes for the ORA-03113 error.
For example, ORA-3113 could be signaled for any of these scenarios:
- Server machine crashed
- Your server process was killed at O/S level
- Network problems
- Oracle internal errors / aborts on the server
- Client incorrectly handling multiple connections
- Etc

It goes on to note that the ORA-03113 End-Of-File error often has additional messages:
It is common for this error to be accompanied by other errors such as:
- ORA-1041 internal error. hostdef extension doesn't exist
- ORA-3114 not connected to ORACLE
- ORA-1012 not logged on

To find more details, check for a trace file in your USER_DUMP_DEST and BACKGROUND_DMP_DEST directory.

Monday 3 September 2007

ORA-00054: resource busy and acquire with NOWAIT specified

When You get an ORA-00054, it's usually impossible to do the DDL unless You spend hours inconveniencing end-users by nuking their sessions.

ORA-00054: resource busy and acquire with NOWAIT specified
Cause: Resource interested is busy.
Action: Retry if necessary.

You have choices for avoiding the ORA-00054 error:

  • Re-run the change late at night when the database is idle.
  • Do all DDL during a maintenance window with all end-users locked-out.
  • Kill the sessions that are preventing the exclusive lock.
Oracle has several views for showing lock status, some of which show the username:
  • DBA_BLOCKERS – Shows non-waiting sessions holding locks being waited-on
  • DBA_DDL_LOCKS – Shows all DDL locks held or being requested
  • DBA_DML_LOCKS - Shows all DML locks held or being requested
  • DBA_LOCK_INTERNAL – Displays 1 row for every lock or latch held or being requested with the username of who is holding the lock
  • DBA_LOCKS - Shows all locks or latches held or being requested
  • DBA_WAITERS - Shows all sessions waiting on, but not holding waited for locks
The DBA_LOCK_INTERNAL view used to show locks for a specific user, and you can specify the query in the form:

SELECT
NVL(b.username,'SYS') username,
session_id,lock_type,mode_held,
mode_requested,lock_id1,lock_id2
FROM
sys.dba_lock_internal a,
sys.v_$session b
where . . .

You can also query v$access and v$locked_object to see specific locks:

select s.sid, s.serial#, p.spid
from
v$session s,
v$process p
where
s.paddr = p.addr
and
s.sid in (select SESSION_ID from v$locked_object);

You can simply kill the session if you're sure:
ALTER SYSTEM KILL SESSION ('sid,serial#');

ORA-12154: TNS: could not resolve service name

The ORA-21254 is a very common error, always related to your local copy of the tnsnames.ora file, your listener configuration and your database name aliases.

  • Make sure that your listener is listening for the same service name that you are using.
  • Your service name might have an alias, so check for global (world) entries and local entries. Check $ORACLE_HOME/network/admin/tnsnames.ora.
  • Check your global_name setting with this SQL:
    SQL>SELECT * FROM GLOBAL_NAME;
The query value should match your init.ora parms for db_name and db_domain, You can change the global_name with an alter database commend, as follows:

SQL>alter database rename global_name to xxx;

Sunday 2 September 2007

Methods for Moving Datafiles

Depending on the type of tablespace, the database administrator can move datafiles using one of the following two methods :

The ALTER TABLESPACE Command
Precondition :
- Tablespace must be offline
- Target datafiles must be exist

Example of usage:
ALTER TABLESPACE userdata RENAME
DATAFILE '/u01/oradata/userdata01.dbf'
TO '/u02/oradata/userdata01.dbf';

Step to rename a datafile:
- Take the tablespace offline
- Use an OS command to move or copy the files
- Execute the ALTER TABLESPACE RENAME DATAFILES command
- Bring the tablespace online
- Use an OS command to delete the old file if necessary

The ALTER DATABASE Command
The ALTER DATABASE command can be used to move any type of datafile
Precondition:
- Database must be mounted
- Target datafile must exist

Example of usage:
ALTER DATABASE RENAME
FILE '/u01/oradata/system01.dbf'
TO '/u02/oradata/system01.dbf';

Because of the SYSTEM tablespace cannot be taken offline, you must use this method to move datafiles in the SYSTEM tablespace.

Use the following steps to rename files in tablespaces that cannot be taken offline:
- Shut down the database.
- Use an OS Command to move the files.
- Mount the database.
- Execute the ALTER DATABASE RENAME FILE command.
- Open the database

Delete Without Rollback ?

A few people asking me, is there a a way to delete a table record 'permanently' without using the rollback segments? In some cases if the table have 'so many records' and if there are no more space in the rollback segment, deleting records would be fail.
Indeed there is a way ....
Using the "TRUNCATE" command will bypass the rollback segments when
deleting records. For example, "TRUNCATE TABLE Table_Name;" will
delete all records.
Note that no triggers that may exist get fired. Also, do not do this to a
table that is a master snapshot.

Locally vs. Dictionary Managed Tablespaces

By declaring a tablespace as DICTIONARY managed, you are specifying that extent management for segments in this tablespace will be managed using the following dictionary tables:

sys.fet$ Every extent for a particular segment is represented by a row in the sys.fet$ dictionary table. sys.fet$ is actually clustered in the C_TS# cluster.
sys.uet$ Data dictionary view used to store used extents. sys.uet$ is actually clustered in the C_FILE#_BLOCK# cluster.

Oracle updates the above tables in the data dictionary whenever an extent is allocated, or freed for reuse.

To Create Dictionary Managed Tablespaces you can use the following example:

CREATE TABLESPACE users
DATAFILE '/u10/app/oradata/TESTDB/user01.dbf' SIZE 50M
EXTENT MANAGEMENT DICTIONARY
DEFAULT STORAGE (
INITIAL 64K
NEXT 64K
MINEXTENTS 2
MAXEXTENTS 121
PCTINCREASE 0);

A Locally Managed Tablespace is a tablespace that manages its own extents by maintaining a bitmap in each datafile to keep track of the free or used status of blocks in that datafile. Each bit in the bitmap corresponds to a block or a group of blocks. When the extents are allocated or freed for reuse, Oracle simply changes the bitmap values to show the new status of the blocks. These changes do not generate rollback information because they do not update tables in the data dictionary (except for tablespace quota information). Some of the benefits of using a locally managed tablespace are:
  • Reduced recursive space management.
  • Reduced contention on data dictionary tables.
  • No rollback generated.
  • No coalescing required.
The following statement creates a locally managed tablespace named USERS, where AUTOALLOCATE causes Oracle to automatically manage extent size.

CREATE TABLESPACE users
DATAFILE '/u10/app/oradata/TESTDB/user01.dbf' SIZE 50M
EXTENT MANAGEMENT LOCAL AUTOALLOCATE;

Alternatively, this tablespace could be created specifying the UNIFORM clause. In this example, a 512K extent size is specified. Each 512K extent (which is equivalent to 64 Oracle blocks of 8K) is represented by a bit in the bitmap for this file.

CREATE TABLESPACE users
DATAFILE '/u10/app/oradata/TESTDB/user01.dbf' SIZE 50M
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 512K;

Advantages in using Locally Managed Tablespaces Over Dictionary Managed Tablespaces :
  • Because locally managed tablespaces do not record free space in data dictionary, it reduces contention on these tables.
  • Local management of extents automatically tracks adjacent free space, eliminating the need to coalesce free extents.
  • Avoids recursive space management operations, which can occur in dictionary-managed tablespaces if consuming or releasing space in an extent results in another operation that consumes or releases space in a rollback segment or data dictionary table.
  • Sizes of extents that are managed locally can be determined automatically by the system. Alternatively, all extents can have the same size in a locally managed tablespace.
  • Changes to the extent bitmaps do not generate rollback information because they do not update tables in the data dictionary (except for special cases such as tablespace quota information).
  • Reduced fragmentation .

Oracle Database Shutdown Stages

What happens during the different Oracle shutdown options?

Database Shutdown options:

  • NORMAL - No new connections, waits for all users to disconnect, closes and dismounts database before instance shutdown, no instance recovery required upon next db startup.
  • IMMEDIATE - Rolls back all current uncommitted transactions and disconnects users, closes and dismounts database before instance shutdown, no instance recovery required upon next db startup.
  • TRANSACTIONAL - No new connections, users disconnected when their current transaction is completed, when all "current transactions are complete shutdown immediate is executed.
  • ABORT - All transactions are terminated, no transactions are rolled back, instance terminated without closing the data files, next startup will require instance recovery.

Resizing Temporary Tablespace

Sometimes, in many database configuration, the DBA will choose to allow their temporary tablespace to AUTOEXTEND. A runaway query or sort can easily chew up valuable space on the disk as the tempfiles(s) extends to accommodate the request for space.
If the increase in size of the temporary tablespace (the tempfiles) gets exceedingly large because of a particular anomaly, the DBA will often want to resize the temporary tablespace to a more reasonable size in order to reclaim that extra space.
The obvious action would be to resize the tempfiles using the following statement:

SQL> alter database tempfile '/u02/oradata/TESTDB/temp01.dbf' resize 250M;
alter database tempfile '/u02/oradata/TESTDB/temp01.dbf' resize 250M
*
ERROR at line 1:
ORA-03297: file contains used data beyond requested RESIZE value

The best practice are:
- create another temporary tablespace
- make the new temporary tablespace as the default temporary tablespace
or if you want to use the old tablespace name
- drop the old temporary tablespace, and recreate it, set it as the default temporary tablespace
- drop the other temporary tablespace

Example:
SQL> DROP TABLESPACE temp;
drop tablespace temp
*
ERROR at line 1:
ORA-12906: cannot drop default temporary tablespace

SQL> CREATE TEMPORARY TABLESPACE temp2
2 TEMPFILE '/u02/oradata/TESTDB/temp2_01.dbf' SIZE 5M REUSE
3 AUTOEXTEND ON NEXT 1M MAXSIZE unlimited
4 EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M;

Tablespace created.

SQL> ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp2;

Database altered.


SQL> DROP TABLESPACE temp INCLUDING CONTENTS AND DATAFILES;

Tablespace dropped.

SQL> CREATE TEMPORARY TABLESPACE temp
2 TEMPFILE '/u02/oradata/TESTDB/temp01.dbf' SIZE 500M REUSE
3 AUTOEXTEND ON NEXT 100M MAXSIZE unlimited
4 EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M;

Tablespace created.


SQL> ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp;

Database altered.


SQL> DROP TABLESPACE temp2 INCLUDING CONTENTS AND DATAFILES;

Tablespace dropped.

NOTE:
On some platforms , it is possible for the tempfile to be deleted from DBA_TEMP_FILES but not from the hard drive of the server.

If this occurs, simply delete the file using regular O/S commands.

Creating Tablespace

Types of Tablespace
1. SYSTEM Tablespace
- Created with the database
- Contains the data dictionary
- Contains the SYSTEM undo segment
2. Non-SYSTEM Tablespace
- Separate segments
- Eases space administration
- Controls amount of space allocated to a user

Create a tablespace with the CREATE TABLESPACE command:

CREATE TABLESPACE tablespace
[DATAFILES clause]
[MINIMUM EXTENT integer [K|M] ]
[BLOCKSIZE integer [K] ]
[LOGGING | NOLOGGING]
[DEFAULT storage_clause]
[ONLINE | OFFLINE ]
[PERMANENT | TEMPORARY]
[extent_management_clause]
[segment_management_clause]

Example:

CREATE TABLESPACE userdb
DATAFILE '/u01/oradata/userdb01.dbf' SIZE 100M
AUTOEXTEND ON NEXT 5M MAXSIZE 200M;

For locally managed tablespace:

CREATE TABLESPACE userdb
DATAFILE '/u01/oradata/userdb01.dbf' SIZE 100M
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 128K;

Creating Database

To create a database, use the following SQL command :

CREATE DATABASE [database]
[CONTROLFILE REUSE]
[LOGFILE [GROUP integer] filespec
[MAXLOGFILES integer]
[MAXLOGMEMBERS integer]
[MAXLOGHISTORY integer]
[MAXDATAFILES integer]
[MAXINSTACES integer]
[ARCHIVELOG |NOARCHIVELOG]
[CHARACTER SET charset]
[NATIONAL CHARACTER SET charset]
[DATAFILES filespec [autoextend_clause]
filespec :== 'filename' [SIZE integer] [K|M] [REUSE]
autoextend_clause :==
[AUTOEXTEND {OFF | ON [NEXT integer [K|M] ] [MAXSIZE {UNLIMMITED | integer [K|M] } } ]
[DEFAULT TEMPORARY TABLESPACE tablespace filespec [temp_tablespace_extend_clause]
temp_tablespace_extend_clause :==
EXTENT MANAGEMENT LOCAL UNIFORM [SIZE integer] [K|M] ]

[UNDO TABLESPACE tablespace DATAFILE filespec [autoextend_clause] ]
[SET TIME_ZONE [time_zone_region] ]

Example:
CREATE DATABASE userdb
LOGFILE
GROUP 1 ('/$HOME/ORADATA/u01/redo1.log') SIZE 100M,
GROUP 2 ('/$HOME/ORADATA/u02/redo1.log') SIZE 100M,
GROUP 3 ('/$HOME/ORADATA/u03/redo1.log') SIZE 100M
MAXLOGFILES 5
MAXLOGMEMBERS 5
MAXLOGHISTORY 1
MAXDATAFILES 100
MAXINSTANCES 1
DATAFILE '/$HOME/ORADATA/u01/system01.dbf' SIZE 300M
UNDO TABLESPACE undotbs
DATAFILE '/$HOME/ORADATA/u02/undotbs01.dbf' SIZE 300M
AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED
DEFAULT TEMPORARY TABLESPACE temp
CHARACTER SET US7ASCII
NATIONAL CHARACTER SET AL16UTF16
SET TIME_ZONE = 'America/New_York'

The Dual Table

Dual Table is a table that contais a single row.
The dual table has one VARCHAR2 column named dummy.
Dual contains a single row with the value X.

Oracle has created this since it makes some calculations more convenient.

SQL> describe dual;
Name Type Nullable Default Comments
----- ----------- -------- ------- --------
DUMMY VARCHAR2(1) Y

SQL> select * from dual;

DUMMY
-----
X

You can use it for math :

SQL> Select (202*44)/4 from dual;

(202*44)/4
----------
2222

You can use it to increment sequences :

SQL> select seq_no_tx.nextval from dual;

NEXTVAL
----------
1402

Saturday 1 September 2007

Privacy Policy

PRIVACY POLICY
If you require any more information or have any questions about our privacy policy, please feel free to contact us by email at sprpopo@yahoo.com.

At oracletipstricks.blogspot.com, the privacy of our visitors is of extreme importance to us. This privacy policy document outlines the types of personal information is received and collected by oracletipstricks.blogspot.com and how it is used.

Log Files
Like many other Web sites, oracletipstricks.blogspot.com makes use of log files. The information inside the log files includes internet protocol ( IP ) addresses, type of browser, Internet Service Provider ( ISP ), date/time stamp, referring/exit pages, and number of clicks to analyze trends, administer the site, track user’s movement around the site, and gather demographic information. IP addresses, and other such information are not linked to any information that is personally identifiable.

Cookies and Web Beacons
oracletipstricks.blogspot.com does use cookies to store information about visitors preferences, record user-specific information on which pages the user access or visit, customize Web page content based on visitors browser type or other information that the visitor sends via their browser.

Some of our advertising partners may use cookies and web beacons on our site. Our advertising partners include Google Adsense, Kontera.

Oracle Tips & Tricks utilizes certain services from Google for ad serving and web traffic analysis. Please review Google's privacy policy for more information on how Google AdSense and Google Analytics stores your personal information. These Google servies may place and read cookies on your browser, or use web beacons to collect information, in the course of ads being served on the Oracle Tips & Tricks website. Additionally, Google uses the DART cookie to enables it to serve ads to based on your visits to Oracle Tips & Tricks and other sites on the Internet. You may opt out of the use of the DART cookie by visiting the Google ad and content network privacy policy.

These third-party ad servers or ad networks use technology to the advertisements and links that appear on oracletipstricks.blogspot.com send directly to your browsers. They automatically receive your IP address when this occurs. Other technologies ( such as cookies, JavaScript, or Web Beacons ) may also be used by the third-party ad networks to measure the effectiveness of their advertisements and / or to personalize the advertising content that you see.

oracletipstricks.blogspot.com has no access to or control over these cookies that are used by third-party advertisers.

You should consult the respective privacy policies of these third-party ad servers for more detailed information on their practices as well as for instructions about how to opt-out of certain practices. oracletipstricks.blogspot.com's privacy policy does not apply to, and we cannot control the activities of, such other advertisers or web sites.

If you wish to disable cookies, you may do so through your individual browser options. More detailed information about cookie management with specific web browsers can be found at the browsers' respective websites.

Oracle Ebook Download

  1. Advance Oracle PL/SQL Programming with Packages
  2. Developing Client-Server Application with Oracle
  3. High Performance Oracle Database Applications
  4. Learning Oracle PL/SQL
  5. Oracle SQL Programming
  6. Performance Tuning Oracle Applications