Download IBM DB2 9.7 PostgreSQL to DB2 porting guide

Document related concepts

Microsoft Jet Database Engine wikipedia , lookup

Database wikipedia , lookup

Ingres (database) wikipedia , lookup

Microsoft SQL Server wikipedia , lookup

Functional Database Model wikipedia , lookup

Entity–attribute–value model wikipedia , lookup

Clusterpoint wikipedia , lookup

Open Database Connectivity wikipedia , lookup

SQL wikipedia , lookup

Extensible Storage Engine wikipedia , lookup

Relational model wikipedia , lookup

Database model wikipedia , lookup

PL/SQL wikipedia , lookup

PostgreSQL wikipedia , lookup

Transcript
IBM DB2 9.7
PostgreSQL to DB2
porting guide
Prepared by:
IM Partner Technologies - DB2 LUW – Americas
Information Management, IBM Software Group
January 2010
Table of Contents
1.
INTRODUCTION....................................................................................................... 5
2.
ENABLEMENT OVERVIEW ..................................................................................... 6
2.1
2.2
2.3
2.4
3.
What is PostgreSQL? ......................................................................................................... 6
What is DB2 Express-C?.................................................................................................... 7
Architectural similarities...................................................................................................... 7
What to expect during the process..................................................................................... 9
DATA TYPE MAPPING .......................................................................................... 11
3.1
3.2
3.3
3.4
4.
PostgreSQL data types .................................................................................................... 11
DB2 data types ................................................................................................................. 13
Comparison of data types................................................................................................. 14
Some important differences.............................................................................................. 16
3.4.1 Boolean.................................................................................................................... 16
3.4.2 CHARACTER VARYING(n) and VARCHAR(n) limits ............................................. 17
3.4.3 TEXT data type ........................................................................................................ 17
3.4.4 Support of NUMERIC data type............................................................................... 17
DATA DEFINITION LANGUAGE (DDL)................................................................. 19
4.1
Tables ............................................................................................................................... 19
4.1.1 SERIAL columns...................................................................................................... 20
4.1.2 Specifying a TABLESPACE location ....................................................................... 20
4.1.3 Specifying storage USING INDEX TABLESPACE .................................................. 20
4.1.4 WITH and WITHOUT OIDS Clause......................................................................... 21
4.1.5 Constraints............................................................................................................... 21
4.1.5.1 CHECK constraint.............................................................................................. 21
4.1.5.2 NOT NULL constraint......................................................................................... 21
4.1.5.3 UNIQUE constraint ............................................................................................ 22
4.1.5.4 PRIMARY KEY constraint.................................................................................. 22
4.1.5.5 FOREIGN KEY constraint.................................................................................. 23
4.1.5.6 Column default values ....................................................................................... 25
4.2 Temporary tables.............................................................................................................. 26
4.3 Data partitioning ............................................................................................................... 28
4.3.1 Table partitioning in PostgreSQL............................................................................. 28
4.3.2 Range partitioning in DB2........................................................................................ 31
4.3.3 Physical design and partitioning options in DB2...................................................... 34
4.4 Indexes ............................................................................................................................. 34
4.4.1 CONCURRENTLY option for CREATE INDEX ....................................................... 35
4.4.2 Create index specification USING method .............................................................. 35
4.4.3 CREATE INDEX ON (expression) ........................................................................... 35
4.4.4 CREATE INDEX ON (opclass) ................................................................................ 36
4.4.5 ASC, DESC and NULLS FIRST, NULLS LAST....................................................... 36
4.4.6 Creating an index WITH storage attributes.............................................................. 37
4.4.7 Specifying an index table space location................................................................. 38
4.4.8 CREATE INDEX using a WHERE predicate ........................................................... 38
4.5 Views ................................................................................................................................ 39
4.5.1 View compatibility .................................................................................................... 39
4.5.2 Temporary views...................................................................................................... 40
4.5.3 Updateable views..................................................................................................... 40
4.6 Sequence objects ............................................................................................................. 40
4.7 Comments on database objects ....................................................................................... 41
2
2
5.
DATA MANIPULATION LANGUAGE (DML) ......................................................... 43
5.1
5.2
5.3
5.4
INSERT statement............................................................................................................ 43
UPDATE statement .......................................................................................................... 44
DELETE statement........................................................................................................... 46
SELECT statement (queries)............................................................................................ 47
5.4.1 Inner and Outer joins ............................................................................................... 47
5.4.2 Type casting in queries ............................................................................................ 47
5.4.3 CASE expression in queries .................................................................................... 48
5.4.4 Sorting NULL values ................................................................................................ 48
5.4.5 Restricting results with LIMIT and OFFSET ............................................................ 49
5.4.6 Values list................................................................................................................. 49
5.4.7 Recursive queries .................................................................................................... 50
5.4.8 PERFORM statement .............................................................................................. 51
5.5 SQL Function Mapping..................................................................................................... 51
5.5.1 Numeric function mapping ....................................................................................... 51
5.5.2 Character function mapping..................................................................................... 52
5.5.3 Date and Time function mapping............................................................................. 53
5.5.4 Sample UDFs........................................................................................................... 54
5.5.4.1 INITCAP in DB2 ................................................................................................. 54
5.5.4.2 LPAD in DB2...................................................................................................... 55
6.
SQL PROCEDURAL LANGUAGES....................................................................... 56
6.1
6.2
6.3
6.4
6.5
6.6
6.7
Stored procedures and functions...................................................................................... 56
Comparison of PL/pgSQL and SQL PL syntax ................................................................ 56
Block labeling ................................................................................................................... 58
RETURNS statement ....................................................................................................... 58
LANGUAGE statement..................................................................................................... 60
PL/pgSQL specific attributes ............................................................................................ 60
Working with variables...................................................................................................... 61
6.7.1 Variable names ........................................................................................................ 61
6.7.2 Declaring variables .................................................................................................. 61
6.7.3 Using an ALIAS for parameters ............................................................................... 62
6.7.4 %TYPE .................................................................................................................... 63
6.7.5 %ROWTYPE............................................................................................................ 63
6.8 Basic Statements.............................................................................................................. 64
6.8.1 SET assignment....................................................................................................... 64
6.8.2 VALUES statement .................................................................................................. 64
6.8.3 NULL statement ....................................................................................................... 64
6.8.4 RETURN statement ................................................................................................. 64
6.9 Control Structures............................................................................................................. 66
6.9.1 IF and CASE statements ......................................................................................... 66
6.9.2 The difference between ELSIF and ELSEIF............................................................ 66
6.9.3 LOOP statement ...................................................................................................... 67
6.9.4 Records and cursors................................................................................................ 67
6.9.5 Working with DB2 cursors and result sets ............................................................... 68
6.10
Condition Handling....................................................................................................... 69
6.10.1
RAISE Statement ................................................................................................ 69
6.10.2
EXCEPTION Statement Block............................................................................. 70
6.10.3
GET DIAGNOSTICS Statement.......................................................................... 70
6.10.4
DECLARE HANDLER Statement........................................................................ 71
6.10.5
SIGNAL Statement .............................................................................................. 72
6.11
Using Dynamic SQL ..................................................................................................... 73
6.12
Triggers ........................................................................................................................ 74
6.12.1
FOR EACH ROW and FOR EACH STATEMENT............................................... 75
3
3
6.12.2
Classified as BEFORE or AFTER ....................................................................... 75
6.12.3
Multiple events on a single object ....................................................................... 75
6.12.4
Multiple triggers for a single event type............................................................... 75
6.12.5
Cascading triggers............................................................................................... 76
6.12.6
Access to transition data and values................................................................... 76
6.12.7
Enabling PostgreSQL triggers in DB2 ................................................................. 77
6.13
PostgreSQL Rules........................................................................................................ 80
7.
BASIC SECURITY .................................................................................................. 82
7.1
7.2
7.3
7.4
8.
Authentication ................................................................................................................... 82
Authorization..................................................................................................................... 83
Privileges .......................................................................................................................... 83
Data Control Language (DCL).......................................................................................... 83
7.4.1 Creating a RESTRICTIVE database in DB2............................................................ 83
7.4.2 Instance administrative authority ............................................................................. 84
7.4.3 Database administrative authority ........................................................................... 84
7.4.4 Creating a new database user and granting user privileges ................................... 84
MIGRATION ISSUES ............................................................................................. 85
8.1
8.2
8.3
8.4
8.5
8.6
8.7
8.8
8.9
8.10
8.11
8.12
8.13
8.14
9.
Name identifiers................................................................................................................ 85
Database name length ..................................................................................................... 85
Column default derived from function............................................................................... 86
TYPE declarations in functions and procedures .............................................................. 86
SUBSTR restrictions......................................................................................................... 86
DEFAULT parameters in functions................................................................................... 87
Boolean variables and IF statements ............................................................................... 87
INTERVAL data type ........................................................................................................ 88
Un-typed NULL values in a SELECT list .......................................................................... 89
Combined action triggers ............................................................................................. 89
BEFORE triggers that modify the database................................................................. 89
Using a function’s expression as an index key ............................................................ 90
Limitation on table row width........................................................................................ 90
Disabling triggers.......................................................................................................... 91
ADDITIONAL RESOURCES .................................................................................. 92
9.1
9.2
9.3
9.4
Education and learning..................................................................................................... 92
Download products and technologies .............................................................................. 93
Discussion groups and forums ......................................................................................... 93
References ....................................................................................................................... 93
9.4.1 PostBooks: An Open Source ERP........................................................................... 93
9.4.2 PostgreSQL Documentation .................................................................................... 93
9.4.3 DB2 Documentation................................................................................................. 93
9.4.4 developerWorks Articles .......................................................................................... 94
APPENDIX A - USING THE IBM DATA MOVEMENT TOOL (IDMT) ............................ 95
4
4
1.
Introduction
0B
This document is a technical guide describing the process of enabling a PostgreSQL
database application to operate under IBM DB2 Version 9.7 for Linux, UNIX, and Windows
(LUW).
This guide is intended to be used to visualize the scope of effort and assist the porting
effort by addressing technical issues and identifying the differences between PostgreSQL
and DB2 both in functionality and syntax.
While this document contains content that targets a specific migration from a PostgreSQL
8.3 database to DB2 9.7 Express-C, this material can be a useful reference for all
development between the two database servers regardless of version.
Regardless of whether a porting effort will be completely manual or if tools will be utilized,
this document can provide value. Obviously, if the port is performed manually, this guide
will provide the greatest value. If the port will utilize tools, then analysis can be performed
using this guide to determine how much of the application the tools will convert, and how
much must be converted manually. In any case, this guide is intended to be used to both
visualize the scope of a porting effort and to assist in the porting effort by exploring the
technical issues.
This document is intended to be a living document. Errors of omission, suggestions
regarding more effective solutions as well as all other suggestions should be sent to Sam
Marino ([email protected]) and Sreeni Paidi ([email protected]) so they might be
incorporated into future revisions.
H
H
H
H
Authors
Sam Marino, Enablement Consultant, IM Technical Enablement, IBM Software Group
Sreeni Paidi, Enablement Consultant, IM Technical Enablement, IBM Software Group
Contributors
Ted Wasserman, for content from his developerWorks article titled Leverage your
PostgreSQL V8.1 skills to learn DB2, Version 8.2
Reviewers
Chris Braudy, Migration Consultant, WW Migration Center, IBM Software Group
5
2.
Enablement Overview
1B
2.1
What is PostgreSQL?
10B
PostgreSQL is an open source object-relational database system. It has more than 15
years of active development and a proven architecture that has earned it a strong
reputation for reliability, data integrity, and correctness. It runs on all major operating
systems, including Linux, UNIX (AIX, BSD, HP-UX, SGI IRIX, Mac OS X, Solaris, Tru64),
and Windows. It is fully ACID compliant, has full support for foreign keys, joins, views,
triggers, and stored procedures (in multiple languages). It includes most SQL92 and
SQL99 data types, including INTEGER, NUMERIC, BOOLEAN, CHAR, VARCHAR, DATE,
INTERVAL, and TIMESTAMP. It also supports storage of binary large objects, including
pictures, sounds, or video. It has native programming interfaces for C/C++, Java, .Net,
Perl, Python, Ruby, Tcl, ODBC and others.
An enterprise class database, PostgreSQL boasts sophisticated features such as MultiVersion Concurrency Control (MVCC), point in time recovery, table spaces, asynchronous
replication, nested transactions (savepoints), online/hot backups, a sophisticated query
planner/optimizer, and write ahead logging for fault tolerance. It supports international
character sets, multi-byte character encodings, Unicode, and it is locale-aware for sorting,
case-sensitivity, and formatting. It is highly scalable both in the sheer quantity of data it can
manage and in the number of concurrent users it can accommodate. There are active
PostgreSQL systems in production environments that manage in excess of 4 terabytes of
data. Some general PostgreSQL limits are included in the table below.
Limit
Value
Maximum Database Size
Unlimited
Maximum Table Size
32 TB
Maximum Row Size
1.6 TB
Maximum Field Size
1 GB
Maximum Rows per Table
Unlimited
Maximum Columns per Table
250 - 1600 depending on column types
Maximum Indexes per Table
Unlimited
6
2.2
What is DB2 Express-C?
1B
H
H
IBM DB2 Express-C 9.7 is a no-charge version of DB2 Express 9 database server. It is
designed to be up and running in minutes, is easy-to-use and embed, includes selfmanagement features, and embodies all of the core capabilities of DB2 for Linux, UNIX,
and Windows such as pureXML. DB2 Express-C offers the same core data server base
features as other DB2 Express editions and provides a solid base to build and deploy
applications developed using C/C++, Java, .NET, PHP, Ruby on Rails, Python and other
programming languages.
H
H
Community based assistance is available at the DB2 Express-C developerWorks forum.
You can optionally choose to purchase a low-cost yearly subscription (Fixed Term License
or FTL) that comes with full technical support, access to software updates (i.e. fixpacks),
and includes additional features like High Availability clustering and Data Replication.
H
H
ISVs and business partners who want to embed a no-charge database with their solutions
can distribute DB2 Express-C without paying any fees or royalties to IBM.
Limit
Value
Maximum Database Size
Unlimited
Maximum Table Size
512 GB in regular tablespace and 16384
GB in a large DMS tablespace.
Maximum Row Size
1.6 TB
Maximum Rows per Table
128 x 1010
Maximum Columns per Table
500 – 1012 (depends on the page size)
Maximum Indexes per Table
32767
2.3
Architectural similarities
12B
There are some similarities in the architectural design of PostgreSQL and DB2. Both
database systems are based on a client-server architecture, where the client tier is
independent of the server. In both cases, a client application wishing to use a database
makes a request over the network and is served by a process on the server (postmaster
on PostgreSQL, db2agent on DB2). PostgreSQL uses a simple process-per-user
client/server model in which one client process connects to exactly one server process.
The main process, called postmaster, listens at a specified TCP/IP port for incoming
connections and spawns a new server process called postgres every time a connection is
requested. The PostgreSQL processes communicate with each other using semaphores
and shared memory to ensure data integrity during concurrent data access. Database files
are accessed through shared disk buffers.
7
Figure 1: PostgreSQL Architecture
Server Processes
Client Processes
Client Application
Initial
Connection
Request and
Authentication
DB Requests and
Results via Library
API
Client
Interface
Library
Postmaster
Daemon Process
Create
Shared
Memory
Operating
System
Shared
Disk
Buffers
Kernel
Disk
Buffers
Spawn
Server
Process
Disk
Storage
Postgres Server
(Backend)
SQL Queries
and Results
Read /
Write
Shared
Tables
In DB2, coordinator agents (db2agent) coordinate the work on behalf of an application and
communicate to other agents, using inter-process communication (IPC) or remote
communication protocols. All connection requests from client applications, whether they
are local or remote, are allocated a corresponding coordinator agent. When intra-partition
parallelism is enabled, extra worker agents, called subagents (db2agentp) are spawned by
the coordinator agent to help perform the work in parallel. DB2 accesses database files
through buffer pools. It has the ability to fetch data into the buffer pools and move data out
of the buffer pool asynchronously using prefetcher (db2pfchr) and page cleaner (db2pclnr)
processes. The log writer process (db2loggw) flushes log records from the log buffer to the
log files on disk, while the log reader process (db2loggr) reads the database log files
during transaction processing (in other words, rollback), restart recovery, and roll-forward
operations.
Figure 2: DB2 Architecture
8
Clients
Client
Application
Client
Application
DB2 Client Library
Shared memory and semaphores,
TCPIP, Named Pipes. NetBIOS,
SNA, IPX/SPX
DB2 Server
Logical Agent Pool
Log Buffer
Coordinator Agent
Subagents
Coordinator Agent
Subagents
Buffer Pool(s)
Logger
Prefetchers
Log
Hard Disk
Hard Disk
Page Cleaners
Please refer to the following two developerWorks articles for complete overview and
comparison of PostgreSQL and DB2 architectures:
Leverage your PostgreSQL V8.1 skills to learn DB2, Version 8.2
http://www.ibm.com/developerworks/data/library/techarticle/dm-0603wasserman2/index.html
HU
Migrate from MySQL or PostgreSQL to DB2 Express-C
http://www.ibm.com/developerworks/data/library/techarticle/dm-0606khatri/
HU
2.4
U
What to expect during the process
13B
Both DB2 and PostgreSQL take pride in standards compliance. Both database’s SQL
implementation strongly conforms to the ANSI-SQL 92/99 standards. This provides a
significant advantage to your enablement.
Keep in mind is that most relational database vendors implement a similar set of features,
for example all have tables, views, indexes, triggers, all support the SQL language, and so
on. In fact, the database definition language, or DDL syntax used to define and create the
objects is very similar across the different database vendors. However, there are
sometimes slight variations you need to take into account. For example, there may be
some behavioral differences between how a particular feature or object is implemented.
Maybe the same feature exists in both, but is used in a different way. Maybe the feature is
9
proprietary, in other words it does not conform to any standard, in which case some type of
workaround is required.
Typically though, SQL syntax conforming to the SQL standard is portable to DB2 without
many changes. It is the proprietary syntax or extensions that require workarounds.
Generally speaking, most proprietary extensions encountered in by enablement efforts
have acceptable workarounds.
Applications that are written using a standards-based interface driver, for example JDBC
interfaces usually require few changes to work with DB2 apart from SQL syntax
modifications. That is because the driver interface methods are fairly standard across
different database vendors.
10
3.
Data Type Mapping
2B
Relational databases implement most of the data types based on the SQL ANSI standard.
However, not every database platform supports each and every data type defined by the
standards committees. Furthermore, vendor data types of a given name may be
implemented differently from what the standard may specify and even differently from all
other database vendors. As a result, although many PostgreSQL and DB2 data types are
similar in either their name or meaning or both, many differences can be noted as well.
Let us look at commonly used data types in PostgreSQL and DB2.
3.1
PostgreSQL data types
14B
Data Type
Remark
BIGSERIAL, SERIAL8
Stores an auto-incrementing unique integer value up to
8 bytes of data
BIT
A fixed-length bit string
BITVARYING(n), VARBIT(n)
A variable-length bit string n bits in length
BOOLEAN
Stores a logical Boolean (true/false/unknown) value of
either TRUE, t, true, y, yes and 1; FALSE, f, false, n, no
and 0.
BYTEA
Raw binary data used to store large binary objects such
as graphics. Uses 4 bytes plus the length of the binary
string for storage
CHAR(n), CHARACTER(n)
Contains a fixed-length character string padded with
spaces up to a length of n.
DATE
Holds a calendar date (year, month, day) in a 4-byte
storage space
DATETIME
Holds a calendar date and time of day
NUMERIC(p,s),
Stores exact numeric values with a precision (p) and a
scale (s) of 0 or higher. Precision can be up to 1000
digits.
DECIMAL(p,s)
NUMERIC
Without any precision or scale creates a column in
which numeric values of any precision and scale can be
11
Data Type
Remark
stored, up to the implementation limit on precision.
NUMERIC(p)
Stores numeric values with the given precision and a
scale or 0.
Data Type
Remark
FLOAT4, REAL
Stores floating-point numbers with a precision of 8 or
less and 6 decimal places
FLOAT8,
DOUBLE PRECISION
Stores floating-point numbers with a precision of 16 or
less and 15 decimal places
SMALLINT
Stores signed or unsigned 2-byte integers
INTEGER
INT8
BIGINT
Stores signed or unsigned 4-byte integers
Stores signed or unsigned 8-byte integers
SERIAL, SERIAL4
Stores an auto-incrementing unique integer value using
up to 4 bytes of its storage.
TEXT
Stores large, variable-length, character-string data up to
1 GB. PostgreSQL automatically compresses TEXT
strings.
TIME (WITHOUT TIME
ZONE | WITH TIME ZONE)
Holds the time of day and stores either no time zone in
8 bytes of storage or the time zone of the database
server using 12 bytes of storage.
TIMESTAMP (WITHOUT
TIME ZONE |WITH TIME
ZONE)
Stores the date and time and stores either no time zone
or the time zone of the database server and uses 8
bytes of storage.
VARCHAR(n),
CHARACTER VARYING(n),
CHARACTER VARYING
Stores variable-length character strings up to a length
of n. Trailing spaces are not stored.
12
3.2
DB2 data types
15B
Data Type
BIGINT
BLOB
BLOB(n)
Remark
A big integer is an eight-byte integer with a precision of
19 digits. The range of big integers is 9 223 372 036 854 775 808 to
+9 223 372 036 854 775 807.
Holds variable-length binary data up to 2 GB in length.
Lengths over 1 GB are not logged
CHAR(n), CHARACTER(n)
Holds fixed-length character data up to 254 bytes in
length. Uses 'n' bytes of storage
CHAR(n) FOR BIT DATA
Holds fixed-length binary values
CLOB, CLOB(n)
Holds variable-length character data up to 2 GB in
length. Lengths over 1 GB are not logged
DATE
Holds a calendar date without time of day. Uses 4 bytes
of storage
DEC(p,s),
DECIMAL(p,s),
NUM(p,s),
NUMERIC(p,s)
Holds a precision (p) of 1 to 31 and a scale (s) of 0 to
31. Uses (p/2) +1 bytes of storage. The maximum
range is -1031+1 to 1031-1.
DECFLOAT(p)
A decimal floating-point value is an IEEE 754r number
with a decimal point. The position of the decimal point is
stored in each decimal floating-point value. The
maximum precision is 34 digits. The range of a decimal
floating-point number is either 16 or 34 digits of
precision, and an exponent range of 10-383 to 10+384
or 10-6143 to 10+6144, respectively.
DOUBLE,
DOUBLE PRECISION,
FLOAT
Holds floating point numbers and uses 8 bytes of
storage.
FLOAT(p)
Holds a precision (p) of 1 to 53. If p <= 24 then a
synonym for REAL. If p >= 25 then is a synonym for
DOUBLE PRECISION
13
Data Type
GRAPHIC(n)
INT
INTEGER
Remark
Used for National Language Support (NLS) and fixedlength character strings (usually DBCS) up to 127 bytes
in length. Uses n*2 bytes of storage for double-byte
character sets or n bytes of storage for single-byte
character sets.
A large integer is a four-byte integer with a precision of
10 digits. The range of large integers is -2 147 483 648
to +2 147 483 647.
A single-precision floating-point number is a 32-bit
approximation of a real number. The number can be
zero or can range from:
REAL
1.1754943508222875e-38 to
3.4028234663852886e+38.
SMALLINT
A small integer is a two-byte integer with a precision of
5 digits. The range of small integers is -32 768 to
32 767.
TIME
Holds the time of day and uses 3 bytes of storage
TIMESTAMP
Stores the date (year, month, day) and time (hour,
minute, second) with up to a precision of 6 for
microseconds. Uses 10 bytes of storage
VARCHAR(n),
CHAR VARYING(n),
CHARACTER VARYING(n)
Holds variable length character data up to 32,672 bytes
in length. Uses n+2 bytes of storage
VARCHAR(n) FOR BIT DATA
Stores binary data in variable-length. Uses n bytes of
storage
VARGRAPHIC(n)
Holds variable-length double-byte character data up to
16,336 characters in length. Uses (n*2)+2 bytes of
storage
3.3
Comparison of data types
16B
PostgreSQL
BIGSERIAL
SERIAL8
DB2
BIGINT
Remark
Use IDENTITY Attribute to
simulate auto-increment
14
PostgreSQL
DB2
Remark
feature. Refer to section
Error! Reference source not
found. for more on SERIAL
data types
For length up to 254 bytes
BIT
CHAR(n) FOR BIT
DATA
BIT VARYING(n)
VARBIT(n)
VARCHAR(n) FOR BIT
DATA
BYTEA
BLOB
BOOLEAN
-
DB2 doesn’t have a Boolean
data type. See section 3.4.1
for more information.
CHAR(n)
CHARACTER (n)
CHAR(n)
Up to 254 bytes
DATE
DATE
Use the CURRENT
TIMEZONE special register to
transform the date.
DATETIME
TIMESTAMP
Use the CURRENT
TIMEZONE special register to
transform the date.
DECIMAL(p,s)
NUMERIC(p,s)
DECIMAL(p,s)
For precision > 31, Use
DOUBLE
SMALLINT, BIGINT,
Use if up to 32,672 bytes
Can be used if between 32K
and 2GB bytes
X
X
INTEGER
Use appropriate data type
based on the precision.
NUMERIC
DECFLOAT(34)
See section 3.4.4.
FLOAT4
REAL
REAL
Can use either NUMERIC or
FLOAT
FLOAT8
DOUBLE PRECISION
DOUBLE PRECISION
Use DOUBLE PRECISION
for large number or use
NUMERIC if precision < 31
NUMERIC(p)
X
X
15
PostgreSQL
DB2
SMALLINT
SMALLINT
INTEGER
INTEGER
INT8
BIGINT
BIGINT
VARCHAR(n)
CHARACTER VARYING(n)
CHARACTER VARYING
SERIAL, SERIAL4
TEXT
Remark
VARCHAR(n)
If 'n' is 32K or less. DB2
requires you to specify 'n'
while postgres does not
enforce a value for 'n'
INTEGER
Use with IDENTITY attribute.
See section Error!
Reference source not
found. for more information.
VARCHAR(n), CLOB
Use VARCHAR if length is
less than 32K bytes otherwise
use BLOB if size is more than
32K bytes. See section 3.4.3.
X
TIME WITHOUT TIME ZONE
TIME WITH TIME ZONE
TIME
DB2 doesn’t include time
zone.
TIMESTAMP
DB2 doesn’t include time
zone.
TIMESTAMP
WITHOUT TIME ZONE
TIMESTAMP
WITH TIME ZONE
3.4
3.4.1
X
Some important differences
17B
Boolean
65B
DB2 9.7 does not support BOOLEAN as a column’s data type in a table definition. The
choice of data type is relatively easy; either SMALLINT or CHAR(1). This issue’s greatest
impact is on the application-side, where all code referencing and testing a BOOLEAN
column will need appropriate logic to test the condition and branch procedurally.
In DB2, a BOOLEAN data type can only be used as:
• A local variable in a compound SQL (compiled) statement
• A parameter of an SQL routine
16
• The returns type of an SQL function
• A global variable
3.4.2
CHARACTER VARYING(n) and VARCHAR(n) limits
6B
In Postgres, CHARACTER VARYING(n) and VARCHAR(n) are available for use as
variable size character data. Both of these types can store strings up to n characters (not
bytes) in length. If character varying is used without a length specification the type accepts
strings of any size. Note, the latter characteristic is a PostgreSQL extension. The
VARCHAR data type in DB2 has a maximum length of 32672.
3.4.3
TEXT data type
67B
It is a common practice in PostgreSQL table definitions to use TEXT column with no size
for most of the character and variable length character data.
This introduces a data analysis requirement when porting the table definitions to DB2
because you need to know the maximum possible length of each TEXT column in order to
map it to an appropriate VARCHAR(n) or CLOB(n) column in DB2. Use a DB2 VARCHAR
data type if less than 32K data is ever stored in the column.
PostgreSQL example:
CREATE TABLE accnt
(
…
accnt_number text,
accnt_descrip text,
accnt_comments text,
accnt_profit text,
accnt_sub text,
…)
DB2 syntax:
CREATE TABLE accnt
(
…
accnt_number varchar(10),
accnt_descrip varchar(30),
accnt_comments clob(100000),
accnt_profit varchar(10),
accnt_sub varchar(10),
…)
3.4.4
Support of NUMERIC data type
68B
PostgreSQL allows use of NUMERIC data type with no precision and scale for the numeric
data columns. This presents a data analysis requirement when porting to DB2 because
you need to know what type of data is stored in that column (interger, or a real number)
and you also need to know the maximum possible value of the column in order to map it to
an appropriate column data type in DB2. Choose the appropriate data type in DB2 based
17
on the type and maximum length of the value stored in the column. DECFLOAT(34) is
probably the best choice in most cases.
PostgreSQL example:
CREATE TABLE flrpt
(
…
flrpt_beginning numeric,
flrpt_ending numeric,
flrpt_debits numeric,
…)
DB2 syntax:
CREATE TABLE flrpt
(
flrpt_beginning DECFLOAT(34),
flrpt_ending INTEGER,
flrpt_debits BIGINT,
…)
18
4.
Data Definition Language (DDL)
3B
In this section, let us take a look at how PostgreSQL and DB2 handle statements to create
and alter database objects such as tables, indexes, views, and sequences.
4.1
Tables
18B
There are two types of tables in PostgreSQL: a regular table and a temporary table.
Regular tables, just like in any other relational databases, are used to store persistent user
data in the database. Temporary tables are used by applications that work with data in the
database, where the results from manipulation of the data need to be stored temporarily in
a table. Temporary tables are automatically dropped at the end of a session or, optionally,
at the end of the current transaction. Any indexes created on a temporary table are
automatically temporary as well.
CREATE TABLE statement is used to create regular and temporary tables in PostgreSQL
and DB2. Let us look at the high level overview of CREATE TABLE syntax in PostgreSQL
and DB2 with an example to create a regular table.
PostgreSQL example:
CREATE TABLE apaccnt
(
apaccnt_id serial NOT NULL,
apaccnt_vendtype_id integer,
apaccnt_vendtype text,
apaccnt_ap_accnt_id integer NOT NULL,
apaccnt_prepaid_accnt_id integer,
apaccnt_discount_accnt_id integer,
CONSTRAINT apaccnt_pkey PRIMARY KEY (apaccnt_id)
USING INDEX TABLESPACE 8KIDXSPC
)
TABLESPACE 8KTBLSPC
WITH (OIDS=TRUE);
DB2 syntax:
CREATE TABLE APACCNT
(
APACCNT_ID INTEGER NOT NULL
GENERATED BY DEFAULT AS IDENTITY
(START WITH 1, INCREMENT BY 1, CACHE 20),
APACCNT_VENDTYPE_ID INTEGER,
APACCNT_VENDTYPE VARCHAR(20),
APACCNT_AP_ACCNT_ID INTEGER NOT NULL,
APACCNT_PREPAID_ACCNT_ID INTEGER,
APACCNT_DISCOUNT_ACCNT_ID INTEGER,
CONSTRAINT apaccnt_pkey PRIMARY KEY (apaccnt_id)
)
IN 8KTBLSPC
19
INDEX IN 8KIDXSPC;
As you can see in the above examples, syntax of the CREATE TABLE statement is very
identical in PostgreSQL and DB2 with a few variations.
Please read the chapter on data type mapping for more information on the data type
substitutions.
4.1.1
SERIAL columns
69B
The data type serial is not a true data type, but it is a unique identifier column.
This is same as an IDENTITY column in DB2. A serial column in PostgreSQL can be
replaced with either an IDENTITY column or a column with a default value assigned from a
sequence.
PostgreSQL SERIAL column definition:
<column_name> SERIAL NOT NULL
DB2 IDENTITY column definition:
<column_name> INTEGER NOT NULL
GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 20)
Note: In PostgreSQL, the type names serial and serial4 are equivalent. They both create
integer columns. The type names BIGSERIAL and serial8 work the same way, except that
they create a BIGINT column.
4.1.2
Specifying a TABLESPACE location
70B
TABLESPACE clause defines name of the tablespace in which the newly created table
resides.
This is same as the IN clause in DB2. TABLESPACE clause in PostgreSQL should be
replaced with IN clause in DB2.
PostgreSQL:
TABLESPACE <tablespace_name>
DB2:
IN <tablespace_name>
4.1.3
Specifying storage USING INDEX TABLESPACE
71B
USING INDEX TABLESPACE clause allows selection of the tablespace in which the index
associated with a UNIQUE or PRIMARY KEY constraint will be created. If not specified,
the default_tablespace is will be the location, or the PostgreSQL temp_tablespaces if the
table is temporary.
20
This clause should be replaced with INDEX IN clause in DB2. In DB2, INDEX IN clause
specifies name of the tablespace in which indexes of the given table are created.
PostgreSQL:
USING INDEX TABLESPACE <tablespace_name>
DB2 definition:
INDEX IN <tablespace_name>
4.1.4
WITH and WITHOUT OIDS Clause
72B
The WITH OIDS=TRUE (or WITH OIDS) clause specifies that the rows of the new table
should have OIDs (object identifiers) assigned to them. OIDS=FALSE (or WITHOUT
OIDS) specifies that the rows should not have OIDs. If OIDS is not specified, the default
setting depends upon the default_with_oids configuration parameter in PostgreSQL.
H
H
PostgreSQL community doesn't recommend using OIDs in new applications. It is
recommended to use a SERIAL or other sequence generator as the table's primary key.
If a table is defined WITH OIDS=TRUE clause and if the application does make use of
OIDs to identify specific rows of a table, it is recommended in DB2 to create an additional
identity column (or a column with a sequence generator) with a unique constraint enforced
on the column.
4.1.5
Constraints
73B
Databases allow you to define constraints on columns and tables. Constraints give you as
much control over the data in your tables as you wish. If a user attempts to store data in a
column that would violate a constraint, an error is raised. This applies even if the value
came from the default value definition.
Both PostgreSQL and DB2 allow you to define the following types of constraints on the
columns and the tables with slight or no differences:
4.1.5.1 CHECK constraint
134B
A check constraint allows you to specify that the value in a certain column must satisfy a
Boolean expression. There is no difference in the way a check constraint is defined in
PostgreSQL and DB2.
PostgreSQL example:
price numeric CHECK (price > 0)
DB2 example:
price decimal(10,2) CHECK (price > 0)
4.1.5.2 NOT NULL constraint
135B
A not-null constraint specifies that a column must not assume the null value. It is defined
exactly the same way in PostgreSQL and DB2.
21
PostgreSQL example:
aropen_docdate date NOT NULL
DB2 example:
aropen_docdate date NOT NULL
4.1.5.3 UNIQUE constraint
136B
PostgreSQL allows null values in columns defined as UNIQUE or the columns used in a
composite UNIQUE constraint. Hence in PostgreSQL, two null values are not considered
equal. That means even in the presence of a unique constraint it is possible to store
duplicate rows that contain a null value in at least one of the constrained columns.
This behaviour is not allowed in DB2. DB2 doesn’t allow null values in the columns defined
as UNIQUE or the columns used in a composite UNIQUE constraint. NOT NULL constraint
must be explicitly enforced on these columns.
PostgreSQL example:
CREATE TABLE budghead
(
budghead_id serial NOT NULL,
budghead_name text,
budghead_descrip text,
CONSTRAINT budghead_pkey PRIMARY KEY (budghead_id),
CONSTRAINT budghead_budghead_name_key UNIQUE (budghead_name)
) WITH (OIDS=FALSE);
DB2 example:
CREATE TABLE budghead
(
budghead_id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (start with 2,
increment by 1, cache 20),
budghead_name varchar(100) NOT NULL,
budghead_descrip varchar(200),
CONSTRAINT budghead_pkey PRIMARY KEY (budghead_id),
CONSTRAINT budghead_budghead_name_key UNIQUE (budghead_name)
);
4.1.5.4 PRIMARY KEY constraint
137B
A primary key is unique and not null. Both in PostgreSQL and DB2, a table can have at
most one primary key. It indicates that a column or group of columns can be used as a
unique identifier for rows in the table. A primary key is defined exactly the same way in
PostgreSQL and DB2.
PostgreSQL example:
CREATE TABLE addr
(
addr_id serial NOT NULL,
…
CONSTRAINT addr_pkey PRIMARY KEY (addr_id)
22
);
DB2 example:
CREATE TABLE ADDR
(
ADDR_ID INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 8,
INCREMENT BY 1, CACHE 20),
…
CONSTRAINT addr_pkey PRIMARY KEY (addr_id)
);
4.1.5.5 FOREIGN KEY constraint
138B
A foreign key constraint maintains referential integrity between two tables.
Implementing Foreign Key in PostgreSQL
Let us first look at how foreign key is implemented in PostgreSQL.
One of the following two syntaxes can be used to define a foreign key in PostgreSQL.
Column Constraint:
REFERENCES reftable [ ( refcolumn ) ] [ MATCH matchtype ] [ ON DELETE
action ] [ ON UPDATE action ] (column constraint)
Table Constraint:
FOREIGN KEY ( column [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [
MATCH matchtype ] [ ON DELETE action ] [ ON UPDATE action ]
(table constraint)
These clauses specify a foreign key constraint, which requires that a group of one or more
columns of the new table must only contain values that match values in the referenced
column(s) of some row of the referenced table. If refcolumn is omitted, the primary key of
the reftable is used. The referenced columns must be the columns of a unique or primary
key constraint in the referenced table. Note that foreign key constraints cannot be defined
between temporary tables and permanent tables.
• The MATCH clause specifies how value(s) inserted into the referencing column(s) is
matched against the values of the referenced table and referenced columns using
the given match type. There are three match types: MATCH FULL, MATCH
PARTIAL, and MATCH SIMPLE, which is also the default. MATCH FULL will not
allow one column of a multicolumn foreign key to be null unless all foreign key
columns are null. MATCH SIMPLE allows some foreign key columns to be null while
other parts of the foreign key are not null. MATCH PARTIAL is not yet implemented.
• The ON DELETE clause specifies the action to perform when a referenced row in
the referenced table is being deleted.
• The ON UPDATE clause specifies the action to perform when a referenced column
in the referenced table is being updated to a new value.
• Following are the possible actions for ON DELETE and ON UPDATE.
23
• NO ACTION or RESTRICT - Either these produce an error indicating that the
deletion or update would create a foreign key constraint violation. NO ACTION is the
default action.
• CASCADE - Delete any rows referencing the deleted row, or update the value of the
referencing column to the new value of the referenced column, respectively.
• SET NULL - Set the referencing column(s) to null.
• SET DEFAULT - Set the referencing column(s) to their default values.
Implementing Foreign Key in DB2
Now let us take a look at how foreign keys are implemented in DB2.
One of the following two syntaxes can be used to define a foreign key in DB2.
Column Constraint:
REFERENCES reftable [ ( refcolumn ) ] [ ON DELETE action ] [ ON UPDATE action ]
Table Constraint:
FOREIGN KEY ( column [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [
ON DELETE action ] [ ON UPDATE action ]
There is no MATCH clause in DB2 when defining foreign key. However, when multicolumn
foreign key is defined on a table in DB2, its MATCH behaviour is equivalent to MATCH
SIMPLE in PostgreSQL. That means DB2 doesn’t support MATCH FULL.
Following are the possible actions for ON DELETE in DB2.
• NO ACTION (default)
• RESTRICT
• CASCADE
• SET NULL
As you can see, DB2 doesn’t have SET DEFAULT as a possible ON DELETE action.
When porting to DB2, remember to change your ON DELETE action to a supported action
if you are using SET DEFAULT in PostgreSQL.
Following are the only possible ON UPDATE actions in DB2.
• NO ACTION (default)
• RESTRICT
DB2 doesn’t have CASCADE, SET NULL, and SET DEFAULT as the possible ON
UPDATE actions. Likewise, when porting to DB2, it will be necessary to change the ON
UPDATE to a supported action if any of the unsupported actions are in use.
24
4.1.5.6 Column default values
139B
PostgreSQL uses DEFAULT clause and DB2 uses WITH DEFAULT clause to assign a
default value for a column in the create table statement. The keyword WITH in WITH
DEFAULT is optional in DB2.
PostgreSQL example:
DEFAULT default_expr
DB2 syntax:
[WITH] DEFAULT default_expr
The value is any variable-free expression. The data type of the default expression must
match the data type of the column.
The default expression will be used in any insert operation that does not specify a value for
the column. If there is no default for a column, then the default is NULL if the column
accepts NULL values.
DB2 accepts the following default values:
• A constant
• Datetime-special-registers (CURRENT DATE, CURRENT TIME, or CURRENT
TIMESTAMP)
• User-special-registers (CURRENT USER, SESSION_USER, SYSTEM_USER)
• CURRENT SCHEMA special register
• GENERATED column value
• EMPTY_CLOB(), EMPTY_DBCLOB(), or EMPTY_BLOB() - Specifies a zero-length
string as the default for the column. The column must have the data type that
corresponds to the result data type of the function.
In DB2, a cast-function can be applied on the default value in the default clause, when the
column is defined as a distinct type, BLOB or datetime (DATE, TIME or TIMESTAMP) data
type.
Things to watch for when porting from PostgreSQL:
Unlike PostgreSQL, DB2 doesn’t allow assigning the return value of a user-defined
function as a default value.
For example, the following assignment is not allowed in DB2:
arapply_curr_id integer DEFAULT basecurrid()
PostgreSQL allows using system-defined type-conversion functions like bpchar, text etc.
Remove type-casting or use equivalent function when porting to DB2.
25
PostgreSQL example:
flhead_type character(1) NOT NULL DEFAULT 'A'::bpchar
DB2 syntax:
flhead_type character(1) NOT NULL DEFAULT 'A'
Use appropriate special registers in DB2
PostgreSQL example:
bankrec_created timestamp without time zone NOT NULL
DEFAULT ('now'::text)::timestamp(6) with time zone
DB2 syntax:
bankrec_created timestamp NOT NULL DEFAULT CURRENT TIMESTAMP
4.2
Temporary tables
19B
In this section, let’s talk about how the temporary tables are implemented in PostgreSQL
and DB2 and any changes that need to be made when porting to DB2.
Temporary Table implementation in PostgreSQL
Following is the syntax of CREATE TABLE command used to create a temporary table in
PostgreSQL.
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
(columns_definition)
[ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP }]
PostgreSQL requires each session to issue its own CREATE TEMPORARY TABLE
command for each temporary table to be used. This allows different sessions to use the
same temporary table name for different purposes.
PostgreSQL's behavior of temporary tables is similar to that of DB2. PostgreSQL will
accept the GLOBAL and LOCAL keywords in a temporary table declaration, but they have
no effect.
Existing permanent tables with the same name are not visible to the current session while
the temporary table exists, unless they are referenced with schema-qualified names. Any
indexes created on a temporary table are automatically temporary.
Temporary table implementation in DB2
Following is the syntax of CREATE / DECLARE TABLE command used to create a
temporary table in DB2.
{CREATE | DECLARE} GLOBAL TEMPORARY TABLE table_name (columns_definition)
[ON COMMIT { PRESERVE ROWS | DELETE ROWS }]
[NOT LOGGED {ON ROLLBACK DELETE ROWS | ON ROLLBACK PRESERVE ROWS} | LOGGED]
[WITH REPLACE]
26
[IN tablespace-name]
In DB2 9.7, either you can either create or declare a global temporary table. (Created
temporary tables are new in DB2 9.7.)
The definition of a CREATED temporary table is stored persistently in the DB2 catalog.
Although the contents of a created temporary table is private to a session (just like
DECLARED temporary tables), its definition is shared across all concurrent sessions. The
persistent storage of the created temporary table definition results in the following
operational differences:
After an application session defines a created temporary table, concurrently running
sessions do not have to redefine it.
You can reference a created temporary table in SQL functions, triggers, and views.
Any connection can refer to a created temporary table at any time without the need for a
setup script to initialize the created temporary table.
Just as with a DECLARED temporary table, each session that selects from a created
temporary table retrieves only rows that the same session has inserted. When the session
terminates, the rows of the table associated with the session are deleted.
The DECLARE GLOBAL TEMPORARY TABLE statement also defines a temporary table
for the current session. However, the declared temporary table description does not
appear in the system catalog. It is not persistent and cannot be shared with other sessions.
Each session that defines a declared global temporary table of the same name has its own
unique description of the temporary table. When the session terminates, the rows of the
table are deleted, and the description of the temporary table is dropped. Any compiled
program accessing a DECLARED temporary table must have a definition of the table in the
program to allow the program to be compiled.
ON COMMIT specifies the action taken on the global temporary table when a COMMIT
operation is performed. The default is DELETE ROWS.
LOGGED or NOT LOGGED specifies whether operations for the table are logged. The
default is LOGGED.
ON ROLLBACK specifies the action that is to be taken on the not logged global temporary
table when a ROLLBACK (or ROLLBACK TO SAVEPOINT) operation is performed. The
default is DELETE ROWS.
WITH REPLACE indicates that, in the case that a declared temporary table already exists
with the specified name, the existing table is replaced with the temporary table defined by
this statement (and all rows of the existing table are deleted). When WITH REPLACE is
not specified, then the name specified must not identify a declared temporary table that
already exists in the current session
IN tablespace-name identifies the table space in which the declared temporary table will be
instantiated. The table space must exist and be a USER TEMPORARY table space. If this
clause is not specified, a table space for the table is determined by choosing the USER
TEMPORARY table space with the smallest sufficient page size over which the
authorization ID of the statement has USE privilege.
27
Things to watch for when porting:
The default ON COMMIT action in DB2 is DELETE ROWS where as the default in
PostgreSQL is PRESERVE ROWS.
There is no ON COMMIT DROP option available in DB2.
Make sure there is a user temporary tablespace created with sufficient page size for the
temporary table and the authorization ID..
4.3
Data partitioning
20B
Data partitioning is an organizational scheme in which table data is divided across multiple
data partitions according to values in one or more partitioning columns of the table. A
typical table partitioning column is a date column; each partition is then defined in DDL to
encompass a meaningful date range (e.g., each partition holds rows for one month, one
quarter, or one year). Data from a given table is partitioned into multiple storage objects,
which can be in different table spaces.
There are many benefits of table partitioning:
• Improved query performance
• Increased table capacity
• Bulk loads and deletes can be handled by easily attaching to and detaching data
from a table
4.3.1
Table partitioning in PostgreSQL
74B
PostgreSQL supports partitioning via table inheritance. Each partition must be created as a
child table of a single parent table. The parent table itself is normally empty; it exists just to
represent the entire data set.
The following forms of partitioning can be implemented in PostgreSQL:
• Range Partitioning - The table is partitioned into "ranges" defined by a key column
or set of columns, with no overlap between the ranges of values assigned to
different partitions. For example one might partition by date ranges.
• List Partitioning -= The table is partitioned by explicitly listing which key values
appear in each partition.
There is no difference in syntax between range and list partitioning; those terms are
descriptive only.
Implementing Partitioning in PostgreSQL – with an example
Implementing table partitioning in PostgreSQL is a long process. You will see how simple it
is to implement partitioning in DB2 in the following section. But first, let us look at how it is
done in PostgreSQL
Create the master table, from which all of the partitions will inherit.
28
This is an empty table and data is never inserted into this table. Do not define any check
constraints on this table, unless you intend them to be applied equally to all partitions. You
shouldn’t create any indexes or unique constraints on this table either since it is an empty
table.
For example:
CREATE TABLE orders
(
orderkey
NUMERIC NOT NULL,
partkey
NUMERIC,
suppkey
NUMERIC,
linenumber
NUMERIC,
quantity
NUMERIC,
extendedprice NUMERIC,
shipdate
DATE
);
Create the child tables that each inherit from the master table. Call them partition tables.
These partition tables will not add any columns to the set that is inherited from the master.
Add table constraints to the partition tables to define the allowed key values in each
partition. Ensure that the constraints guarantee that there is no overlap between the key
values permitted in different partitions.
In the following example, the master orders table will be partitioned on the shipdate column
to store 12 months data for 2009, each month in a separate partition. We have to create
12 partition tables by inheriting the above defined master table.
CREATE TABLE orders_y2009_jan ( CHECK
( shipdate >= DATE '2009-01-01' AND shipdate < DATE '2009-02-01' )
) INHERITS (orders);
CREATE TABLE orders_y2009_feb (
( shipdate >= DATE '2009-02-01'
) INHERITS (orders);
.
.
CREATE TABLE orders_y2009_dec (
( shipdate >= DATE '2009-12-01'
) INHERITS (orders);
CHECK
AND shipdate < DATE '2009-03-01' )
CHECK
AND shipdate < DATE '2010-01-01' )
Each of these partitions are complete tables in their own right, but they inherit their
definitions from the orders table.
You probably need to create indexes on the key columns too.
CREATE INDEX orders_y2009_jan_shipdate
ON orders_y2009_jan (shipdate);
CREATE INDEX orders_y2009_feb_shipdate
ON orders_y2009_feb (shipdate);
.
29
.
CREATE INDEX orders_y2009_dec_shipdate
ON orders_y2009_dec (shipdate);
In order to have the data to be redirected into the appropriate partition table when your
application inserts into the master table, define triggers to locate the partition into which the
row should be added. Do this with a complex trigger function, for example:
CREATE OR REPLACE FUNCTION orders_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.shipdate >= DATE '2009-01-01' AND
NEW.shipdate < DATE '2009-02-01' ) THEN
INSERT INTO orders_y2009_jan VALUES (NEW.*);
ELSIF ( NEW.shipdate >= DATE '2006-02-01' AND
NEW.shipdate < DATE '2009-03-01' ) THEN
INSERT INTO orders_y2009_feb VALUES (NEW.*);
...
ELSIF ( NEW.shipdate >= DATE '2009-12-01' AND
NEW.shipdate < DATE '2010-01-01' ) THEN
INSERT INTO orders_y2009_dec VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the or
ders_insert_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
After creating the function, create a trigger which calls the trigger function:
CREATE TRIGGER insert_orders_trigger
BEFORE INSERT ON orders
FOR EACH ROW
EXECUTE PROCEDURE orders_insert_trigger();
Note: When adding a new partition, you must redefine the trigger function. This is a sizable
maintenance task. However, the trigger definition does not need to be updated.
Managing Partitions in PostgreSQL – with an example
Now let us look at how an existing partition can be dropped and a new partition can be
added in PostgreSQL.
Dropping a partition
The simplest option for removing old data is to drop the partition that is no longer
necessary:
DROP TABLE orders_y2009_jan;
30
Another option that is often preferable is to remove the partition from the partitioned table
but retain access to it as a table in its own right:
ALTER TABLE orders_y2009_jan NO INHERIT orders;
Note: In both these cases, you can update the trigger function to remove the code related
to the dropped / detached partition.
Adding a new partition
Add a new partition to handle new data. Create an empty partition in the partitioned table
just as the original partitions were created above:
CREATE TABLE orders_y2010_jan (
CHECK ( shipdate >= DATE '2010-01-01'
AND shipdate < DATE '2010-02-01' )
) INHERITS (orders);
As an alternative, create the new table outside the partition structure, and make it a proper
partition later. This allows the data to be loaded, checked, and transformed prior to it
appearing in the partitioned table:
CREATE TABLE orders_y2010_jan
(LIKE orders INCLUDING DEFAULTS INCLUDING CONSTRAINTS);
ALTER TABLE orders_y2010_jan ADD CONSTRAINT y2010_jan
CHECK ( shipdate >= DATE '2010-01-01'
AND shipdate < DATE '2010-02-01' );
copy orders_y2010_jan from 'c:\data\jan2010data';
ALTER TABLE orders_y2010_jan INHERIT orders;
4.3.2
Range partitioning in DB2
75B
Range partitioning in DB2 is also referred to as table partitioning or data partitioning. This
data organization scheme is one in which table data is divided across multiple storage
objects called data partitions or ranges according to values in one or more table columns.
Each data partition is stored separately and can be in different table spaces.
Implementing Range Partitioning in DB2 – with an example
In the following example we demonstrate the method for porting the PostgreSQL table
partitions discussed in section 5.1.3.1 to a DB2 partitioned table.
CREATE TABLE orders
(
orderkey
DECIMAL(10,0) NOT NULL,
partkey
INTEGER,
suppkey
INTEGER,
linenumber
INTEGER,
quantity
DECIMAL(12,2),
extendedprice DECIMAL(12,2),
shipdate
DATE
) PARTITION BY RANGE(shipdate)
31
PARTITION
PARTITION
PARTITION
…
PARTITION
y2009_jan STARTING '1/1/2009',
y2009_feb STARTING '2/1/2009',
y2009_mar STARTING '3/1/2009',
y2009_dec STARTING '12/1/2009'
ENDING ‘12/31/2009'
);
No other actions are necessary. Child tables and triggers are not needed.
Managing Partitions in DB2 – with an example
Now let us look at how an existing partition can be dropped and a new partition can be
added in DB2.
Dropping a partition
Drop a partition in DB2 by simply detaching (rolling-out) a partition as shown below.
ALTER TABLE orders DETACH PARTITION y2009_jan INTO orders_y2009_jan;
Adding a new partition
Attaching (rolling-in) data as a new data partition in a table is just as easy. The data that is
to be rolled-in is first loaded into a separate (staging) table, transformed or cleansed if
needed, and then attached to an existing table as shown in the following example.
CREATE TABLE y2010_jan_orders . . .
-- load / insert desired data into y2010_jan_orders
-- transform or cleanse new data if neeeded
ALTER TABLE orders
ATTACH PARTITION y2010_jan
STARTING '01/01/2010'
ENDING
'01/31/2010'
FROM TABLE y2010_jan_orders;
COMMIT;
SET INTEGRITY . . .
COMMIT;
Note: Before the rolled-in data is visible to applications, a SET INTEGRITY statement
needs issued (to validate the new data and perform maintenance for global indexes) and
the work committed.
More partitioning examples in DB2:
Example 1:
32
In the following example, we are going to use a “shorthand” notation that automatically
generates 12 partitions of uniform size; that is, one partition for each month over a oneyear period. Note that MINVALUE and MAXVALUE will accept any values that fall below
and above the defined ranges.
CREATE TABLE orders
(
orderkey
DECIMAL(10,0) NOT NULL,
…
shipdate
DATE
)
PARTITION BY RANGE(shipdate)
(STARTING MINVALUE,
STARTING '1/1/2009' ENDING '12/31/2009'
EVERY 1 MONTH,
ENDING AT MAXVALUE);
Example 2:
The following example illustrates table partitioning using manual syntax, which is required
when the partitioning key is composed of a composite column. This syntax also allows
specification of a different table space for each partition (desired in some implementations
to facilitate backup strategies).
CREATE TABLE sales
(
year INT,
month INT,
…
)
IN tbsp1, tbsp2, tbsp3, tbsp4, tbsp5, tbsp6, tbsp7, tbsp8
PARTITION BY RANGE (year, month)
(STARTING FROM (2001, 1)
ENDING (2001,3) IN tbsp1,
ENDING (2001,6) IN tbsp2,
ENDING (2001,9) IN tbsp3,
ENDING (2001,12) IN tbsp4,
ENDING (2002,3) IN tbsp5,
ENDING (2002,6) IN tbsp6,
ENDING (2002,9) IN tbsp7,
ENDING AT MAXVALUE);
Example 3:
DB2 provides a method of table partitioning that is based on a generated expression of a
column. Depending on the situation, table partitioning on a generated column may be used
in a similar way to list partitioning in PostgreSQL.
CREATE TABLE customer
(
cust_id
INT,
cust_prov
CHAR(2),
cust_prov_gen GENERATED ALWAYS AS
(CASE
WHEN cust_prov = 'AB' THEN 1
WHEN cust_prov = 'BC' THEN 2
33
WHEN
WHEN
...
WHEN
ELSE
cust_prov = 'MB' THEN 1
cust_prov = ‘SA’ THEN 3
cust_prov = 'YT' THEN 13
14
END)
)
IN tbsp_ab, tbsp_bc, tbsp_mb, .... tbsp_remainder
PARTITION BY RANGE (cust_prov_gen)
(STARTING 1 ENDING 14 EVERY 1);
In the previous example, numeric values are generated based on values for CUST_PROV.
The numeric values populate the generated column, CUST_PROV_GEN, on which table
partitioning is based.
Because an automatic version of the syntax is used in this example, it is sufficient to list
the table spaces for each partition with a single IN clause. If the manual version of the
syntax was used and each partition was defined individually, then an IN clause for each
partition would be required.
4.3.3
Physical design and partitioning options in DB2
76B
DB2 can be designed to organize data in many other ways as well. These different data
organization schemes can be specified at the database or table level.
The other data organization methods available on DB2 are:
• Database partitioning (also known as hash partitioning and DPF)
• Multidimensional clustering (also called MDCs)
• Combined organization schemes
While complete coverage of DB2 partitioning features is beyond the scope of this guide,
the following Web sites provide resources to learn about different DB2 data partitioning
features and the best approach to implement each of them:
DB2 partitioning features - An overview for data warehouses
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0608mcinerney/
HU
Introducing DB2 9, Part 2: Table partitioning in DB2 9
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0605ahuja2/
HU
Database Partitioning, Table Partitioning, and MDC for DB2 9
http://www.redbooks.ibm.com/abstracts/sg247467.html
HU
4.4
Indexes
21B
Indexes are of vital importance to the performance of query processing. Indexes are
created to shorten the access path to the data stored within a table and decrease the
amount of I/O required to find and load a set of data.
34
While the basic format is the same and can be processed by either database, the
extensions supported by each provide a number of differences between PostgreSQL and
DB2. The following statement will create a B-tree index based on the column title in the
table films on both databases:
CREATE UNIQUE INDEX title_idx ON films (title);
Both PostgreSQL and DB2 provide a CREATE INDEX statement as an extension of their
supported SQL. There are no provisions for indexes in the SQL standard so differences
are expected. Both databases apply proprietary nuances for efficiencies of storage and
access.
The following options are provided by Postgres and you must addressed these prior to
migration:
4.4.1
CONCURRENTLY option for CREATE INDEX
7B
When this option is used, PostgreSQL will build the index without taking any locks that
prevent concurrent inserts, updates, or deletes on the table. A standard index build locks
out writes (but not reads) on the table until it's done.
CREATE INDEX CONCURRENTLY title_idx ON films (title);
In contrast, DB2 allows read and write access to the table while an index is being created.
No keyword specification is necessary. For the identical behavior in DB2 as Postgres,
simply remove the CONCURRENTLY keyword.
To circumvent DB2’s default behavior, and keep the table locked during index creation use
the DB2 LOCK TABLE statement to explicitly lock the table prior to issuing the CREATE
INDEX statement. The table can be locked in either SHARE or EXCLUSIVE mode, using
SHARE when read access is to be permitted.
LOCK TABLE films IN EXCLUSIVE MODE;
CREATE INDEX CONCURRENTLY title_idx ON films (title);
4.4.2
Create index specification USING method
78B
When creating a PostgreSQL index the CREATE INDEX statement supports and option for
specifying the indexing method for control of the index’s internal structure. Postgres
supports 4 index methods; B-tree, R-tree, hash, or GiST.
All DB2 indexes are created using a balanced tree (b-tree). PostgreSQL’s default method
is btree, which is compatible with DB2.
4.4.3
CREATE INDEX ON (expression)
79B
PostgreSQL supports creating an index using the result of an expression operating on one
or more columns of the table. Expressions can range from the simple to the complex
depending upon the tasks you want to accomplish. One benefit of utilizing indexes based
on expressions is improved performance.
35
A common example of the most prevailing use of an index built on an expression is the use
of the result returned from the UPPER function shifting case of a character column. This is
used to create a case insensitive column and corresponding index key which can be used
by the database’s query optimizer when considering the query’s data access plan.
Expression-based indexes are not supported in DB2. However there is a facility for
emulating this functionality. Refer to the Migration Issues section and Using a Function as
an Index Key for a suggested solution applicable to creating an UPPER (or LOWER)
expression-based index. Alternatively, to support a case insensitive search, you can
define a generated column in DB2 which automatically stores an upper case version of a
table column.
H
H
4.4.4
CREATE INDEX ON (opclass)
80B
In PostgreSQL, an operator class can be specified for each column of an index. The
operator class identifies the operators to be used by the index for that column. For
example, a B-tree index on four-byte integers would use the int4_ops class; this operator
class includes comparison functions for four-byte integers. The main point of having
operator classes is that for some data types, there could be more than one meaningful
ordering. In practice the default operator class for the column's data type is usually
sufficient.
DB2 does not support operator classes.
4.4.5
ASC, DESC and NULLS FIRST, NULLS LAST
81B
When creating an index both PostgreSQL and DB2 can specify the sort order of the
column values included in the index key definition. Both databases use the keywords ASC
for ascending and DESC for descending. When the sort order is not specified both
databases will default to ascending (ASC).
CREATE UNIQUE INDEX itemcost_master_idx ON itemcost
USING btree (
itemcost_item_id ASC,
itemcost_costelem_id DESC,
itemcost_lowlevel ASC
);
PostgreSQL has additional support applying a rule which specifies can modify the
sequence order of data containing NULL values. The keywords NULL FIRST or NULL
LAST can designate where in the requested sort order that NULL values should be
returned. NULLS FIRST specifies that nulls sort before non-nulls. NULLS LAST specifies
that nulls sort after non-nulls.
The Postgres default null handling rule is determined by the sort order. If the sort order is
not specified or specified to be ascending (ASC) then NULLS LAST is the default. With a
descending (DESC) sequence NULLS FIRST is the default.
The matching defaults can assist in migrations. By default, DB2 will sort ASC with NULLS
LAST. When overriding the order to DESC will cause DB2 to sort NULLS FIRST. Both
databases default to the same sorting behavior.
36
CREATE UNIQUE INDEX itemcost_master_idx ON itemcost
USING btree (
itemcost_item_id ASC,
itemcost_costelem_id DESC NULLS LAST,
itemcost_lowlevel ASC
);
PostgreSQL’s default behavior in each default scenario is the same as DB2’s. An item
requiring a custom migration solution would occur if the Postgres database has indexes
with non-default sort ordering of nulls (i.e. NULLS FIRST with an ASC sequence or NULLS
LAST with an ascending sort).
CREATE UNIQUE INDEX itemcost_master_idx ON itemcost
USING btree (
itemcost_item_id ASC NULLS FIRST,
itemcost_costelem_id DESC,
itemcost_lowlevel ASC
);
4.4.6
Creating an index WITH storage attributes
82B
The WITH clause can specify storage attributes for PostgreSQL indexes. Each index
method (i.e. USING method) has it’s own set of allowed characteristics.
The FILLFACTOR for an index is a percentage that determines how full the index method
will try to pack index pages. The leaf pages are filled to this percentage during initial index
build, and also when extending the index at the right (largest key values):
PostgreSQL example:
CREATE UNIQUE INDEX title_idx ON films (title) WITH (FILLFACTOR = 70);
B-tree indexes use a default FILLFACTOR of 90, but any value from 10 to 100 can be
selected. If the table is static then FILLFACTOR 100 is best to minimize the index's
physical size. For heavily updated tables, a smaller FILLFACTOR is better to minimize the
need for page splits.
Any other index method, used in conjunction with a corresponding storage parameter, is
not supported by DB2 and should be removed from index creation DDL.
As DB2 only supports B-tree indexes, only the PostgreSQL FILLFACTOR needs to be
facilitated between the databases for enablement.
DB2’s CREATE INDEX statement supports PCTFREE which is comparable to the
PostgreSQL FILLFACTOR. PCTFREE specifies what percentage of each index page to
leave as free space when building and maintaining the index. Additional entries are placed
in an index page at least integer percent of free space is left on each page. The value of
integer can range from 0 to 99. If a value greater than 10 is specified, only 10 percent free
space will be left in non-leaf pages. The default is 10.
DB2 syntax:
CREATE UNIQUE INDEX title_idx ON films (title) PCTFREE 10;
37
4.4.7
Specifying an index table space location
83B
Postgres’ CREATE INDEX statement supports a designation of the table spaces in which
to create the index. The designation for index location in DB2 is on the CREATE TABLE
statement:
PostgreSQL example:
CREATE INDEX itemcost_master_idx ON itemcost
USING btree (
itemcost_item_id,
itemcost_costelem_id,
itemcost_lowlevel
)
TABLESPACE idxtbsp;
DB2 syntax:
CREATE TABLE itemcost
(
itemcost_id integer NOT NULL DEFAULT,
itemcost_item_id integer NOT NULL,
itemcost_costelem_id integer NOT NULL,
itemcost_stdcost numeric(16,6) NOT NULL DEFAULT 0,
itemcost_posted date,
itemcost_actcost numeric(16,6) NOT NULL DEFAULT 0,
itemcost_updated date,
itemcost_curr_id integer NOT NULL DEFAULT 0,
CONSTRAINT itemcost_pkey PRIMARY KEY (itemcost_id),
CONSTRAINT itemcost_itemcost_costelem_id_fkey
FOREIGN KEY (itemcost_costelem_id)
REFERENCES costelem (costelem_id)
ON UPDATE NO ACTION ON DELETE NO ACTION
)
IN data_tbsp
INDEX IN index_tbsp;
4.4.8
CREATE INDEX using a WHERE predicate
84B
Where a Postgres’ CREATE INDEX includes the use of a WHERE clause, a partial index
is created. The partial index is an index that contains entries for only a portion of a table,
usually a portion that is more useful for indexing than the rest of the table.
DB2 does not support a partial index. The keyword WHERE and the predicate must be
removed. The resulting index will be created on all rows in the table.
DB2 Best Practice: RUNSTATS
Once an index is created and data is loaded into the table, issue a RUNSTATS command
to update statistics collected on the database tables, columns, and indexes. These
statistics are used to determine the optimal access path to the tables. By issuing the
RUNSTATS command, the database manager can determine the characteristics of the
new index.
38
If data has been loaded before the CREATE INDEX statement is issued, it is
recommended that the COLLECT STATISTICS option on the CREATE INDEX statement
be used as an alternative to the RUNSTATS command:
Example 1: Create an index named IDX1 on a table named TAB1, and collect basic index
statistics on index IDX1.
CREATE INDEX IDX1 ON TAB1 (col1) COLLECT STATISTICS
Example 2: Create an index named IDX2 on a table named TAB1, and collect detailed
index statistics on index IDX2:
CREATE INDEX IDX2 ON TAB1 (col2) COLLECT DETAILED STATISTICS
Example 3: Create an index named IDX3 on a table named TAB1, and collect detailed
index statistics on index IDX3 using sampling:
CREATE INDEX IDX3 ON TAB1 (col3) COLLECT SAMPLED DETAILED STATISTICS
4.5
Views
2B
Both PostgreSQL and DB2 implement views in basically the same conceptual
classification. A view is not physically materialized. Instead, the view's underlying query is
run every time the view is referenced in a SQL statement.
Views are implemented in PostgreSQL as a database rule. Internally a SELECT
processed against a view will invoke a rule which substitutes the base tables and columns
from the view’s definition.
4.5.1
View compatibility
85B
Both PostgreSQL and DB2 view definitions adhere to the SQL standard which has
specifications for some additional capabilities applied using the CREATE VIEW statement:
CREATE VIEW name [ ( column_name [, ...] ) ]
AS query
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
The optional clauses are:
• CASCADED - Check for integrity on this view and on any dependent view. The
default is CASCADED when neither CASCADED nor LOCAL is specified.
• LOCAL - Check for integrity on this view
•
CHECK OPTION - This option has to do with updatable views. All INSERT and
UPDATE commands on the view will be checked to ensure data satisfy the viewdefining condition.
View definitions can be converted easily as the syntax of PostgreSQL and DB2 are nearly
identical. In the example below, the only modification needed is to remove any casting of a
resulting column’s data type.
39
PostgreSQL example:
CREATE OR REPLACE VIEW api.itemfile
AS
SELECT item.item_number::character varying AS item_number,
url.url_title AS title,
url.url_url AS url,
‘’::text as ur.url_description
FROM item, url
WHERE item.item_id = url.url_source_id
AND url.url_source = 'I'::text;
DB2 syntax:
CREATE OR REPLACE VIEW api.itemfile
AS
SELECT item.item_number AS item_number,
url.url_title AS title,
url.url_url AS url,
‘’ as url.url_description
FROM item, url
WHERE item.item_id = url.url_source_id
AND url.url_source = 'I';
4.5.2
Temporary views
86B
If specified, a PostgreSQL view can be created as a temporary view. Temporary views are
automatically dropped at the end of the current session.
DB2 does not support temporary views but does support temporary tables. A temporary
table, once populated with data, can represent a temporary view. If any of the tables
referenced by the view are temporary, the view is created as a temporary view (whether
TEMPORARY is specified or not).
4.5.3
Updateable views
87B
Currently, all PostgreSQL views are read only; the system will not allow an insert, update,
or delete on a view. You can get the effect of an updatable view by creating rules that
rewrite inserts, etc. on the view into appropriate actions on other tables. For more
information see the section on PostgreSQL Rules in this document.
X
X
DB2 supports delete-able, insert-able and update-able views. To allow updates, a view
must satisfy a number of requirement which will allow inserts, updates and deletes (e.g.,
based on a single table). When a view is based on multiple tables or of otherwise
sufficient complexity to preclude updates, implement DB2 INSTEAD OF triggers on the
object to make the view operate as updateable.
4.6
Sequence objects
23B
Some minor differences must be addressed to satisfy the DB2 syntax requirements for the
CREATE SEQUENCE statement. DB2 requires additional keywords, B and WITH, to be
included in the sequence object’s specification.
40
Another conversion issue is the result of PostgreSQL allowing a minimum value of 1 when
specifying the CACHE size attribute. The minimum value of cache size for DB2 is 2. The
recommended solution is to remove CACHE 1
PostgreSQL example:
CREATE SEQUENCE accnt_accnt_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 126
CACHE 1;
Required DB2 syntax:
CREATE SEQUENCE accnt_accnt_id_seq
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
START WITH 126
CACHE 2;
-orCREATE SEQUENCE accnt_accnt_id_seq
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
START WITH 126;
4.7
Comments on database objects
24B
Both DB2 and Postgres support the storage of additional description information for select
database objects. The COMMENT ON command modifies a descriptive field for a
database object stored in the database system catalogs. Many objects common across
the two databases can be maintained with a derivative of the COMMENT ON syntax which
specifies the type of object.
Both PostgreSQL and DB2 support the following syntax of the COMMENT ON command
as well as derivatives for a variety of objects:
COMMENT ON TABLE public.addr IS ‘Trading partner address master’
However, DB2 requires a different syntax for maintaining comments on two objects;
databases and views.
COMMENT ON DATABASE
While PostgreSQL allows COMMENT ON DATABASE DB2 supports the CHANGE
DATABASE command for modifying a database’s comment:
PostgreSQL example:
COMMENT ON DATABASE demo IS ‘Test database for demo purposes’
41
DB2 syntax:
CHANGE DATABASE SAMPLE COMMENT WITH "Test database for demo purposes"
COMMENT ON VIEW
PostgreSQL supports COMMENT ON VIEW, while DB2 applies comments to views using
the COMMENT ON TABLE command:
Postgres example:
COMMENT ON VIEW api.accountchar IS 'Account Characteristics view';
DB2 syntax:
COMMENT ON TABLE api.accountchar IS 'Account Characteristics view';
42
5.
Data Manipulation Language (DML)
4B
Migration issues as they apply to DML statements; INSERT, UPDATE, DELETE, and
TRUNCATE statements.
5.1
INSERT statement
25B
Insert command is used to insert new rows into a table in PostgreSQL and DB2.
Syntax of the INSERT statement in PostgreSQL:
INSERT INTO table [ ( column [, ...] ) ]
{
DEFAULT VALUES |
VALUES ( { expression | DEFAULT } [, ...] ) |
Query
}
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
For the most part, insert statement in PostgreSQL looks like an INSERT in the other
relational databases including DB2, with a couple of exceptions that we will discuss in the
following section.
Syntax of the INSERT statement in DB2:
INSERT INTO table [ ( column [, ...] ) ]
{
VALUES ( { expression | DEFAULT } [, ...] ) |
Query [WITH RR | RS | CS | UR]
}
For the most part, insert statement in DB2 also looks like an INSERT in the other relational
databases, except that you can specify isolation level at which select query is executed
when you use insert…select.
When porting to DB2:
When inserting a row consisting entirely of default values, PostgreSQL allows you to use
DEFAULT VALUES clause in the insert statement, provided there is no not-null column
defined in the table without a default. This is not available in DB2. You would have to
provide the column list and use DEFAULT as the value for each column in the values list.
PostgreSQL example:
CREATE TABLE SALES(
43
STORE_ID SMALLINT DEFAULT 1 ,
SALES_DATE DATE DEFAULT NOW(),
TOTAL NUMERIC(8, 2) DEFAULT 0
) ;
INSERT INTO sales DEFAULT VALUES;
DB2 syntax:
CREATE TABLE SALES
(
STORE_ID SMALLINT WITH DEFAULT 1,
SALES_DATE DATE WITH DEFAULT CURRENT DATE,
TOTAL DECIMAL (8, 2) WITH DEFAULT 0
) ;
INSERT INTO sales(store_id, sales_date, total)
VALUES (default, default, default);
The optional RETURNING clause in PostgreSQL causes INSERT to compute and return
value(s) based on each row actually inserted. This is primarily useful for obtaining values
that were supplied by defaults, such as a serial sequence number. However, any
expression using the table's columns is allowed.
For example, the following insert statement returns the value of default SALES_DATE
inserted by the insert statement into the table. Let us assume that it returned 2009-07-17.
INSERT INTO sales VALUES(2, default, 100) RETURNING sales_date;
SALES_DATE
2009-07-17
In DB2, this is accomplished using the "SELECT FROM FINAL TABLE" construct:
SELECT sales_date FROM FINAL TABLE
(INSERT INTO sales VALUES(2, default,100))
5.2
UPDATE statement
26B
An UPDATE statement is used to update one or more rows in a table in PostgreSQL and
DB2.
Syntax of the UPDATE statement in PostgreSQL:
UPDATE [ ONLY ] table [ [ AS ] alias ]
SET { column = { expression | DEFAULT } |
( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) }
[ FROM fromlist ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ]
[, ...] ]
The syntax of UPDATE is similar to the syntax of UPDATE in other relational databases,
including DB2, with a few exceptions that we will cover in the following section.
44
Syntax of the UPDATE statement in DB2:
UPDATE [ ONLY ] table | full-select
SET { column = { expression | DEFAULT } |
( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) }
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[WITH RR | RS | CS | UR]
Let us first look at a couple of things that are DB2 specific. We will then talk about things
that are specific to PostgreSQL and how to handle them when porting to DB2.
DB2 allows full-select as the object of the update operation. In this case the full-select must
be updatable (i.e., no grouping functions, no table joins).
For example:
Update the salary and the commission column of the employee with employee number
000120 to the average of the salary and of the commission of the employees of the
updated row's department, respectively.
UPDATE (SELECT EMPNO, SALARY, COMM,
AVG(SALARY) OVER (PARTITION BY WORKDEPT),
AVG(COMM) OVER (PARTITION BY WORKDEPT)
FROM EMPLOYEE E)
AS E(EMPNO, SALARY, COMM, AVGSAL, AVGCOMM)
SET (SALARY, COMM) = (AVGSAL, AVGCOMM)
WHERE EMPNO = '000120'
The previous statement is semantically equivalent to the following statement, but requires
only one access to the EMPLOYEE table, whereas the following statement specifies the
EMPLOYEE table twice.
UPDATE EMPLOYEE EU
SET (EU.SALARY, EU.COMM)
=
(SELECT AVG(ES.SALARY), AVG(ES.COMM)
FROM EMPLOYEE ES
WHERE ES.WORKDEPT = EU.WORKDEPT)
WHERE EU.EMPNO = '000120'
Using WITH clause in DB2, known as a common table expression, you can also specify
isolation level at which UPDATE statement is executed.
When porting to DB2:
With the FROM clause, PostgreSQL allows columns from other tables to appear in the
WHERE condition and the update expressions.
When a FROM clause is present, the target table is joined to the tables mentioned in the
from list, and each output row of the join represents an update operation for the target
table.
The FROM clause, is not allowed in DB2 update statement. You must use sub-queries to
port UPDATE statements with FROM clause.
45
PostgreSQL example:
UPDATE employees
SET sales_count = sales_count + 1
FROM accounts
WHERE accounts.name = 'Acme Corporation'
AND employees.id = accounts.sales_person;
DB2 syntax (which also works in PostgreSQL):
UPDATE employees
SET sales_count = sales_count + 1
WHERE id = (SELECT sales_person FROM accounts
WHERE name = 'Acme Corporation');
The optional RETURNING clause causes UPDATE to compute and return value(s) based
on each row actually updated. Any expression using the table's columns, and/or columns
of other tables mentioned in FROM, can be computed. The new (post-update) values of
the table's columns are used.
Just like in the INSERT statement in DB2, this is not allowed in the UPDATE statement
either. You would have to issue a select statement to know the value or define a trigger on
the update statement.
5.3
DELETE statement
27B
DELETE statement is used to delete one or more rows in a table in PostgreSQL and DB2.
Syntax of the DELETE statement in PostgreSQL:
DELETE FROM [ ONLY ] table [ [ AS ] alias ]
[ USING usinglist ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ]
[, ...] ]
Syntax of the DELETE statement in DB2:
DELETE FROM [ ONLY ] table | full-select
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[WITH RR | RS | CS | UR]
Let us first look at a couple of things that are DB2 specific. We will then talk about things
that are specific to PostgreSQL and how to handle them when porting to DB2.
DB2 allows full-select as the object of the delete operation. In this case the full-select must
be delete-able.
For example, following statement deletes all the duplicate employee rows from the
EMPLOYEE table. An employee row is considered to be a duplicate if the last names
match. Keep the employee row with the smallest first name in lexical order.
DELETE FROM
(SELECT ROWNUMBER() OVER (PARTITION BY LASTNAME ORDER BY FIRSTNME)
46
FROM EMPLOYEE) AS E(RN)
WHERE RN = 1
Using WITH clause in DB2, you can also specify isolation level at which DELETE
statement is executed.
When porting to DB2:
In PostgreSQL, you can delete rows in a table using information contained in other tables
in the database by specifying additional tables in the USING clause.
This is not allowed in DB2. You can rewrite the delete statement in DB2 using a sub-query.
PostgreSQL example:
DELETE FROM films USING producers
WHERE producer_id = producers.id AND producers.name = 'foo';
DB2 syntax (which also works in PostgreSQL):
DELETE FROM films
WHERE producer_id IN (SELECT id FROM producers WHERE name = 'foo');
5.4
SELECT statement (queries)
5.4.1
28B
Inner and Outer joins
8B
Both PostgreSQL and DB2 support ANSI SQL syntax for all the table expressions
including inner and outer joins.
The following statement is valid in both PostgreSQL and DB2:
SELECT * FROM ORDERS
LEFT OUTER JOIN ORDER_DETAILS
ON ORDERS.ORDERID = ORDER_DETAILS.ORDERID;
5.4.2
Type casting in queries
89B
PostgreSQL allows using system-defined type-conversion functions like bpchar, text etc.
When porting to DB2:
Remove type-casting or use equivalent function when porting to DB2.
PostgeSQL example:
SELECT PACK.PACK_ID AS SOPACK_ID,
PACK.PACK_HEAD_ID AS SOPACK_SOHEAD_ID,
PACK.PACK_PRINTED AS SOPACK_PRINTED,
PACK.PACK_SHIPHEAD_ID AS SOPACK_COSMISC_ID
FROM PACK
WHERE PACK.PACK_HEAD_TYPE = 'SO'::text;
47
DB2 syntax:
SELECT PACK.PACK_ID AS SOPACK_ID,
PACK.PACK_HEAD_ID AS SOPACK_SOHEAD_ID,
PACK.PACK_PRINTED AS SOPACK_PRINTED,
PACK.PACK_SHIPHEAD_ID AS SOPACK_COSMISC_ID
FROM PACK
WHERE PACK.PACK_HEAD_TYPE = 'SO';
5.4.3
CASE expression in queries
90B
Both PostgreSQL and DB2 allow CASE expressions in queries. For example, the following
statement requires no changes when porting to DB2:
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME,
CASE
WHEN EDLEVEL < 15 THEN 'SECONDARY'
WHEN EDLEVEL < 19 THEN 'COLLEGE'
ELSE 'POST GRADUATE'
END
FROM EMPLOYEE;
5.4.4
Sorting NULL values
91B
In PostgreSQL, NULLS FIRST and NULLS LAST options can be used to determine
whether nulls appear before or after non-null values in the sort ordering. By default, null
values sort as if larger than any non-null value, that is, NULLS LAST is the default for ASC
order.
When porting to DB2:
In DB2 sorts also, NULL values are considered the highest value and are therefore
ordered last in ASC sorts and first in DESC sorts. DB2 doesn’t support NULLS FIRST and
NULLS LAST options.
In case where NULLS LAST is used in DESC sorts or NULLS FIRST is used in ASC sorts
in PostgreSQL, when porting to DB2 the NVL function can be used to replace the column
value with the lowest value if the column contains a NULL value.
PostgreSQL example:
SELECT ACCTNO, ACCTTYPE, BALANCE
FROM ACCOUNTS
ORDER BY BALANCE NULLS FIRST;
DB2 syntax:
SELECT ACCTNO, ACCTTYPE, BALANCE
FROM ACCOUNTS
ORDER BY NVL(BALANCE,-1);
Note: In the previous DB2 example, we modify value of BALANCE to-1.
48
5.4.5
Restricting results with LIMIT and OFFSET
92B
In PostgreSQL, LIMIT and OFFSET clauses in a query allow you to retrieve just a portion
of the rows that are generated by the rest of the query.
LIMIT n says return no more than n rows. Similarly, OFFSET n says to skip n rows before
beginning to return rows.
When porting to DB2:
In DB2, you can use FETCH FIRST n ROWS ONLY clause which is equivalent to LIMIT n.
PostgreSQL example:
SELECT * FROM EMPLOYEE
ORDER BY EMPID
LIMIT 10;
DB2 syntax:
SELECT * FROM EMPLOYEE
ORDER BY EMPID
FETCH FIRST 10 ROWS ONLY;
When porting to DB2:
DB2 does not provide a clause that is equivalent to LIMIT n. Use a workaround like the
MINUS operator with FETCH FIRST n ROWS clause.
PostgreSQL example:
SELECT * FROM EMPLOYEE
ORDER BY EMPID
OFFSET 10;
DB2 syntax:
(SELECT * FROM EMPLOYEE ORDER BY EMPID)
MINUS
(SELECT * FROM EMPLOYEE ORDER BY EMPID FETCH FIRST 10 ROWS ONLY);
5.4.6
Values list
93B
In PostgreSQL as well as DB2, VALUES clause derives a result table using the specified
values, using expressions or row expressions, for each column of a row in the result table.
Multiple rows may be specified. This is most commonly used to generate a constant table
within a larger query.
When porting to DB2:
VALUES list in a query can be ported to DB2 with minimal or no change.
PostgreSQL example:
49
UPDATE employee
SET salary = salary * b.increase
FROM (VALUES(1, 1.2), (2, 1.4), (3, 1.6)) AS b (deptid, increase)
WHERE employee.deptid = b.deptid;
DB2 syntax:
UPDATE employee a SET salary =
(select a.salary * b.increase
FROM (VALUES(1, 1.2), (2, 1.4), (3, 1.6)) AS b (deptid, increase)
WHERE a.deptid = b.deptid);
5.4.7
Recursive queries
94B
Recursive queries are supported in PostgreSQL from version 8.4. Recursive queries are
typically used to deal with hierarchical or tree-structured data.
The WITH clause allows for the definition of a named query within a statement, which can
be referred to at a later point in the same statement. This is called a Common Table
Expression (CTE). CTEs are by now supported in most major SQL-based DBMS, including
DB2 and PostgreSQL.
Unlike a regular CTE, a recursive CTE is referred to within its very own definition in
recursive CTE. A recursive CTE consists of two parts combined with a UNION ALL.
When porting to DB2:
Unlike Oracle, both PostgreSQL and DB2 follow SQL Standard for recursive queries.
PostgreSQL uses keyword RECURSIVE to distinguish between non-recursive CTE and a
recursive CTE. When porting to DB2, remove the keyword RECURSIVE from the query.
PostgreSQL example:
WITH RECURSIVE n(empid, name) AS
(SELECT empid, name
FROM emp
WHERE name = 'Goyal'
UNION ALL
SELECT nplus1.empid, nplus1.name
FROM emp as nplus1, n
WHERE n.empid = nplus1.mgrid);
SELECT name FROM n;
DB2 syntax:
WITH n(empid, name) AS
(SELECT empid, name
FROM emp
WHERE name = 'Goyal'
UNION ALL
SELECT nplus1.empid, nplus1.name
FROM emp as nplus1, n
WHERE n.empid = nplus1.mgrid);
SELECT name FROM n;
50
For more information on recursive queries support in DB2, see this developer works article
at: http://www.ibm.com/developerworks/data/library/techarticle/dm-0510rielau/
HU
5.4.8
PERFORM statement
95B
The PERFORM statement in PostgreSQL executes a SQL query but discards the results.
It is typically used to evaluate an expression or SELECT query as a boolean true or false.
PostgreSQL example:
PERFORM 1 FROM EMPLOYEE
WHERE DEPT = 10;
IF FOUND THEN
…
END IF;
When porting to DB2, SQL PL does not support a PERFORM statement. There are two
relatively simple ways to emulate this statement. One, is to issue a SELECT COUNT(*)
against the table, store the row count in a variable and test the variable. The second is to
use SQL PL support for IF EXISTS. See examples of both below:
DB2 syntax (using COUNT):
SELECT COUNT(*) INTO v_count FROM employee WHERE dept = 10;
IF v_count > 0 THEN
…
END IF;
DB2 syntax (using EXISTS):
IF EXISTS (SELECT 1 FROM EMPLOYEE WHERE DEPT = 10) THEN
…
END IF;
5.5
SQL Function Mapping
29B
This section provides a mapping of database SQL functions between PostgreSQL and
DB2. Identified below are some of the most commonly used functions. Please refer to
PostgreSQL and DB2 SQL documentation for more information on each function’s input
requirements and output result:
5.5.1
Numeric function mapping
96B
PostgreSQL
DB2
Comments
ABS
ABS
Returns the absolute value.
ACOS
ACOS
Returns the arc cosine.
ASIN
ASIN
Returns the arc sine.
ATAN
ATAN
Returns the arc tangent.
ATAN2
ATAN2
Returns the arc tangent (two value).
51
CEIL
CEILING
CEIL
CEILING
Returns the smallest integer greater or equal to
the argument.
COS
COS
Returns the cosine.
EXP
EXP
Returns the exponential function of the
argument.
FLOOR
FLOOR
Largest integer not greater than argument.
LN
LN
Returns the natural logarithm.
LOG
LOG
Returns the natural logarithm.
LOG(10,n1)
LOG10(n1)
Returns the common logarithm (base 10).
MOD(y,x)
MOD(y,x)
Remainder of y/x
POWER(x,y)
POWER(x,y)
X raised to the power of y
RANDOM
RAND
Random value in the range 0.0 <= x < 1.0
ROUND(arg1,arg2)
ROUND(arg1,arg2)
Round to arg2 decimal places
SIGN
SIGN
Sign of the argument (-1, 0, +1)
SIN
SIN
Returns the sine.
SINH
SINH
Returns the hyperbolic sine.
SQRT
SQRT
Returns the square root.
TAN
TAN
Returns the tangent.
TRUNC(n[,m])
TRUNC(n[,m])
TRUNCATE(n[,m])
Truncate to m decimal places
5.5.2
Character function mapping
97B
PostgreSQL
DB2
Comments
ASCII
ASCII
Returns the ASCII code of a
character.
CHR
CHR
Returns an ASCII character for
given n
INITCAP
N/A
Returns characters with the first
letter of each word in uppercase
and the reset of letters in
lowercase.
Can be implemented with UDF.
See an example given below.
STRPOS
POSSTR, POSITION, and
LOCATE
Location of specified substring in
string, but note the argument order.
LENGTH
LENGTH
Returns a length of the string.
LPAD(arg1,arg2,arg3)
N/A
Returns arg1, left-padded to length
arg2 characters with the sequence
of characters in arg3.
52
Can be implemented with UDF.
See an example given below.
LTRIM
LTRIM
Removes blanks from the
beginning of a string expression.
REPEAT(arg1,arg2)
REPEAT(arg1,arg2)
Returns a character string
composed of arg1 repeated arg2
times.
REPLACE(arg1,arg2,arg3)
REPLACE(arg1,arg2,arg3)
Replaces all occurrences of srg2 in
arg1 with arg3
RPAD
N/A
Returns the first argument value,
right-padded to the length specified
in the 2nd argument with
characters specified in the third
argument.
Can be implemented with user
defined fun (UDF).
RTRIM
RTRIM
Remove blanks from the end of a
string expression.
SUBSTR
SUBSTR
SUBSTRING
Returns a substring of a string.
TRANSLATE
TRANSLATE
Returns a string in which one or
more characters in a string are
converted to other characters.
POSITION
POSITION
Position function has different
signature in DB2.
5.5.3
Date and Time function mapping
98B
PostgreSQL
DB2
Comments
CURRENT_DATE
CURRENT DATE
Returns the current date.
CURRENT_TIMESTAMP
CURRENT TIMESTAMP
Returns the current date and
time.
Note: in PostgreSQL, the
CURRENT_TIMESTAMP function
also returns time zone.
CURRENT_TIME
CURRENT TIME
Returns the current time.
Note: in PostgreSQL, the
CURRENT_TIME function also
returns time zone.
DOW
DAYOFWEEK
Returns the day of the week from
a value.
Please note the integer value
differences between DB2 and
PostgreSQL:
- in DB2 1 is Sunday 2 is
53
Monday…7 is Saturday
- in PostgreSQL 0 is Sunday, 1 is
Monday… 6 is Saturday.
DOY
DAYOFYEAR
Returns the day of the year from
a value.
EXTRACT()
YEAR(), MONTH(), DAY()
HOUR(), MINUTE(), SECOND(),
MICROSECOND()
Extracts and returns the value of
a specified datetime field from a
datetime expression.
TIMEZONE
CURRENT TIMEZONE
Returns the value of the database
time zone.
Note that PostgreSQL returns the
time zone offset from UTC,
measured in seconds. Positive
values correspond to time zones
east of UTC, negative values to
zones west of UTC.
NOW()
Implement using CURRENT
TIMESTAMP + CURRENT
TIMEZONE
Returns the current timestamp.
AGE (timestamp, timestamp)
N/A
Subtract arguments, producing a
"symbolic" result that uses years
and months. For example,
age(timestamp '2001-04-10',
timestamp '1957-06-13') is 43
years 9 months 27 days.
Can be implemented with UDF.
AGE (timestamp)
N/A
Subtract from
CURRENT_DATE (at midnight).
Can be implemented with UDF.
5.5.4
Sample UDFs
9B
5.5.4.1 INITCAP in DB2
140B
----------------------------------------------------------------------- DB2 UDB UDF(User-Defined Function) Samples for Migration
-- Description: Convert first character of each word to uppercase
-and other characters to lowercase.
-Words are separated by non-alphanumeric character(s).
---------------------------------------------------------------------CREATE FUNCTION INITCAP (C1 VarChar(4000))
RETURNS VarChar(4000)
SPECIFIC INITCAPPostgreSQL
LANGUAGE SQL
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
54
BEGIN ATOMIC
DECLARE AN Char(62) DEFAULT
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE C1L Integer;
DECLARE Pos, Flag, NewFlag Integer;
DECLARE RetVal VarChar(4000);
SET C1L = LENGTH(C1);
SET (Pos, Flag, RetVal) = (1, 0, '');
WHILE Pos <= C1L DO
SET NewFlag = SIGN(LOCATE(SUBSTR(C1,Pos,1),AN));
SET RetVal = RetVal ||
CASE
WHEN Flag = 0 AND NewFlag = 1 THEN UPPER(SUBSTR(C1,Pos,1))
WHEN Flag = 1 AND NewFlag = 1 THEN LOWER(SUBSTR(C1,Pos,1))
ELSE SUBSTR(C1,Pos,1)
END;
SET (Pos, Flag) = (Pos + 1, NewFlag);
END WHILE;
RETURN RetVal;
END
5.5.4.2 LPAD in DB2
14B
-------------------------------------------------------------------- DB2 UDB UDF(User-Defined Function) Samples for Migration
-- Description: Add repeatedly C2 to the left of parameter 1 (C1 or I1)
-and return N byte.
------------------------------------------------------------------CREATE FUNCTION LPAD (C1 VarChar(4000), N integer, C2 VarChar(4000))
RETURNS VARCHAR(4000)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
NO EXTERNAL ACTION
RETURN
CASE
WHEN N > length(C1)
THEN substr(repeat(C2,(N-length(C1)+length(C2))/(length(C2)+1sign(length(C2)))),1,N-length(C1)) || C1
ELSE substr(C1,1,N)
END;
END
55
6.
SQL Procedural Languages
5B
In this chapter we will discuss differences between PostgreSQL’s Procedural Language
(PL/pgSQL) and DB2’s SQL Procedural Language (SQL PL), which are used for server
side programming.
PL/pgSQL and SQL PL are both block-structured languages with many similarities.
Assignments, loops, and conditional statements are very similar in both the languages.
6.1
Stored procedures and functions
30B
Stored procedures and functions are the programs developed in a procedural language
that are stored in the database server and executed on demand.
• There are many benefits of routines. A few benefits are:
• Code will be parsed at the time of procedure creation which eliminates the need to
re-parse the statements every time you execute the statements in the program.
• Network traffic between client and database server is reduced.
• Code can be efficiently reused by multiple users and client programs.
• Routines improve overall performance of the database management system by
enabling application functionality to be performed on the database server.
6.2
Comparison of PL/pgSQL and SQL PL syntax
31B
In PL/pgSQL, CREATE FUNCTION statement is used to create both stored procedures
and functions. IDB2 has separate create statements for procedures and functions.
PL/pgSQL CREATE FUNCTION Syntax:
CREATE OR REPLACE FUNCTION function-name (parameter(s)-declaration)
[RETURNS data-type(s)] AS
[ label ]
[ DECLARE
declarations ]
BEGIN
statements
END; [ label ]
LANGUAGE language
[attributes];
DB2 CREATE FUNCTION syntax:
CREATE OR REPLACE FUNCTION function-name (parameter(s)-declaration)
[RETURNS data-type(s) | ROW column-list | TABLE column-list]
LANGUAGE language
[ label: ] BEGIN
56
[declarations]
statements
END [ label ] [function-terminator]
DB2 CREATE PROCEDURE syntax:
CREATE OR REPLACE PROCEDURE procedure-name (parameter(s)-declaration)
LANGUAGE language
[ label: ] BEGIN
[declarations]
statements
END [ label ] [procedure-terminator]
Compare the structures of PL/pgSQL and SQL PL with a simple user defined function
example.
PL/pgSQL in PostgreSQL:
CREATE OR REPLACE FUNCTION avgcost(integer)
RETURNS numeric AS
$BODY$
DECLARE
pItemsiteid ALIAS FOR $1;
_value NUMERIC;
_qoh NUMERIC;
BEGIN
SELECT itemsite_value, itemsite_qtyonhand
INTO _value, _qoh
FROM itemsite
WHERE(itemsite_id=pItemsiteid);
IF (_qoh = 0) THEN
RETURN 0;
END IF;
RETURN _value / _qoh;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
SQL PL in DB2:
CREATE OR REPLACE FUNCTION avgcost (pItemsiteid integer)
RETURNS DECFLOAT(34)
LANGUAGE SQL
P1: BEGIN
DECLARE p_value DECFLOAT(34);
DECLARE p_qoh DECFLOAT(34);
SELECT itemsite_value, itemsite_qtyonhand
INTO p_value, p_qoh
FROM public.itemsite
WHERE(itemsite_id=pItemsiteid);
IF (p_qoh = 0) THEN
RETURN 0;
END IF;
RETURN p_value / p_qoh;
57
END P1
As the above example shows, routines in PL/pgSQL and SQL PL have very similar body
structure with some variations. See some variations in the following sections.
6.3
Block labeling
32B
The code of a PL/pgSQL function is specified in CREATE FUNCTION as a string literal.
Generally, one writes the function body as a "dollar-quoted" string literal. In the dollarquoting approach, you choose a different dollar-quoting delimiter for each level of nesting.
In the above example, $BODY$ is used to label the function body.
In DB2, it is not required to label a block of a routine but one can label the body with a
unique label name, if needed to uniquely identify each block in the routine. The above DB2
example used label P1. Note the difference in the way the body is labeled in PL/pgSQL
and SQL PL.
6.4
RETURNS statement
3B
Both in PL/pgSQL and SQL PL, RETURNS statement is used to specify data type and
order of returning data. Both PostgreSQL and SQL PL can return result sets to the calling
program.
Syntax of RETURNS statement in PostgreSQL:
RETURNS [ return-data-type | SETOF result-set | TABLE column-definition ]
Where:
RETURNS return-data-type specifies the data type of a single value the function returns.
RETURNS SETOF result-set is used when a function returns a result-set with the definition
that either matches a user table or a user defined record.
RETURNS TABLE column-definition can also be used in the place of SETOF record when
the function returns more than one row, where the definition of the record doesn’t match
any existing user tables.
CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int)
RETURNS SETOF record AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;
CREATE FUNCTION sum_n_product_with_tab (int)
RETURNS TABLE (sum int, product int) AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;
Syntax of RETURNS statement in DB2:
RETURNS [ return-data-type | ROW column-definition | RECORD | TABLE columndefinition ]
58
Where:
RETURNS return-data-type specifies that the function returns a single value with the given
data type.
RETURNS ROW column-definition specifies that the output of the function is a single row.
RETURNS RECORD specifies that the output of the function is a single row. It is similar to
row-type variables, but it has no predefined structure.
RETURNS TABLE column-definition specifies that the function returns more than one row.
When porting to DB2:
Returning single value:
Syntax is exactly same in PostgreSQL and SQL PL when the function returns a single
value. Replace the data type in PostgreSQL with an equivalent data type supported by
DB2.
PL/pgSQL:
CREATE OR REPLACE FUNCTION avgcost(integer)
RETURNS numeric AS…
SQL PL:
CREATE OR REPLACE FUNCTION avgcost (pItemsiteid integer)
RETURNS DECFLOAT(34)
Returning set of values:
RETURNS SETOF result set in PL/pgSQL should be replaced with either RETURNS ROW
or RETURNS TABLE in SQL PL.
Result set can be name of a user table in PL/pgSQL where it implicitly copies the columndefinition of the user table. This is not allowed in SQL PL. Be sure to explicitly provide the
column definition.
PL/pgSQL example:
CREATE FUNCTION bomitem(integer, integer)
RETURNS SETOF bomitem AS…
DB2 SQL PL syntax:
CREATE FUNCTION bomitem (pItemid integer, pRevid integer)
RETURNS TABLE (bomitem_id integer, bomitem_parent_item_id integer…)
Returning RECORD:
RETURNS RECORD in PL/pgSQL should be replaced with RETURNS TABLE in DB2
SQL PL.
PL/pgSQL example:
59
CREATE OR REPLACE FUNCTION timestamp_parts(timestamp without time zone)
RETURNS record
LANGUAGE 'plpgsql'
AS
$$
DECLARE
p_time_stamp ALIAS FOR $1;
l_rec
record;
BEGIN
SELECT to_char(p_time_stamp, 'YYYY')::integer AS p_year,
to_char(p_time_stamp, 'Q')::integer AS p_quarter,
to_char(p_time_stamp, 'MM')::integer AS p_month,
to_char(p_time_stamp, 'DD')::integer AS p_day,
to_char(p_time_stamp, 'D')::smallint AS p_dow,
to_char(p_time_stamp, 'HH24')::smallint AS p_hour,
INTO
l_rec;
RETURN l_rec;
END
$$
;
DB2 example:
CREATE OR REPLACE FUNCTION timestamp_parts (p_time_stamp TIMESTAMP)
RETURNS TABLE (p_year INT, p_quarter INT, p_month INT, p_day INT, p_dow
SMALLINT, p_hour SMALLINT)
BEGIN
RETURN
SELECT
TO_CHAR(p_time_stamp, 'YYYY') ,
TO_CHAR(p_time_stamp, 'Q') ,
TO_CHAR(p_time_stamp, 'MM'),
TO_CHAR(p_time_stamp, 'DD'),
TO_CHAR(p_time_stamp, 'D'),
TO_CHAR(p_time_stamp, 'HH24')
FROM SYSIBM.SYSDUMMY1;
END
6.5
LANGUAGE statement
34B
In both database systems, the LANGUAGE statement defines the name of the language
that the function is implemented.
In PL/pgSQL the language can be plpgsql, SQL, C, or the name of a user-defined
procedural language. The name can be enclosed by single quotes. The LANGUAGE
statement appears after the body of the routine i.e after the main block in the routine.
In DB2, the language can be SQL, C/C++, Java, .NET CLR, OLE, OLEDB. The
LANGUAGE statement appears at the beginning of the routine i.e. before the main block in
the routine.
6.6
PL/pgSQL specific attributes
35B
When porting to DB2, PL/pgSQL specific attributes must be removed from the routine.
60
For example, the VOLATILE attribute in the above PL/pgSQL inform the query optimizer
about the behavior of the function. VOLATILE indicates that the function value can change
even within a single table scan, so no optimizations can be made.
Similarly, the COST attribute in the previous function example gives the expected
execution cost of the function.
6.7
Working with variables
6.7.1
36B
Variable names
10B
In PL/pgSQL, a variable name can start with _ (underscore). This is not allowed in DB2.
Replace variable names with no underscore [ _ ] as the starting character.
PL/pgSQL example:
_value NUMERIC;
DB2 SQL PL syntax:
p_value DECFLOAT(34);
6.7.2
Declaring variables
10B
In PL/pgSQL, all the variables must be declared in the declarations section of the block
that starts with DECLARE.
For example:
CREATE OR REPLACE FUNCTION avgcost(integer)
RETURNS numeric AS
$BODY$
DECLARE
pItemsiteid ALIAS FOR $1;
_value NUMERIC;
_qoh NUMERIC;
BEGIN
….
END;
In SQL PL, each variable is declared with a DECLARE statement and all the variables are
declared in the block after the BEGIN statement.
For example:
CREATE OR REPLACE FUNCTION avgcost (pItemsiteid integer)
RETURNS DECFLOAT(34)
LANGUAGE SQL
P1: BEGIN
DECLARE p_value DECFLOAT(34);
DECLARE p_qoh DECFLOAT(34);
…
END P1
61
6.7.3
Using an ALIAS for parameters
102B
In PL/pgSQL, parameters passed to functions are named with the identifiers $1, $2, etc.
depending on their position in the calling signature.
Optionally, aliases can be declared for the parameters to increase readability. Either the
alias or the numeric identifier can then be used to refer to the parameter value in the
procedure body.
There are two ways to create an alias. One way, which was the only way available before
PostgreSQL 8.0, is to explicitly declare an alias, using the declaration syntax name ALIAS
FOR $n;
PL/pgSQL example:
CREATE OR REPLACE FUNCTION avgcost(integer)
RETURNS numeric AS
$BODY$
DECLARE
pItemsiteid ALIAS FOR $1;
_value NUMERIC;
_qoh NUMERIC;
BEGIN
….
END;
The preferred way is to give a name to the parameter in the CREATE FUNCTION
command. This is same as how the alias is created in SQL PL. For example, the previous
alias declaration in PL/pgSQL before version 8 can be replaced with the following:
PL/pgSQL example (from version 8)
CREATE OR REPLACE FUNCTION avgcost(pItemsiteid integer)
RETURNS numeric AS
$BODY$
DECLARE
_value NUMERIC;
_qoh NUMERIC;
BEGIN
….
END;
When porting to DB2:
Only the format supported prior to the release of PostgreSQL 8.0 will contain the syntax
which requires conversion. Since version 8, PostgreSQL has supported the naming of
input parameters in the routine’s execution signature in the same way as DB2.
Functions which declare variables as an ALIAS will need to be provided as a named
parameter to the DB2 routine.
Postgres example:
CREATE OR REPLACE FUNCTION checkprivilege(varchar(30))
RETURNS boolean AS
$BODY$
62
DECLARE
pPrivilege ALIAS FOR $1;
….
END;
DB2 syntax:
CREATE OR REPLACE FUNCTION checkprivilege(pPrivilege VARCHAR(30))
RETURNS boolean
BEGIN
….
END;
6.7.4
%TYPE
103B
In PL/pgSQL, %TYPE attribute can be used when declaring a parameter or variable that
will be used to hold column values in a table to ensure that type compatibility between
table columns and PL/pgSQL variables is maintained.
Use of the %TYPE attribute is not supported in DB2 Express-C, Express, and Personal
Editions. You can use ANCHOR DATA TYPE clause to anchor data type of a variable to a
column in a table, just like %TYPE
Syntax:
DECLARE variable ANCHOR DATA TYPE TO schema.tablename.columnname;
For example:
DECLARE p_value ANCHOR DATA TYPE TO PUBLIC.itemsite.itemsite_value;
6.7.5
104B
%ROWTYPE
The %ROWTYPE attribute is used to declare PL/pgSQL variables of type record with fields
that correspond to the columns of a table. When used, each field in the PL/pgSQL record
takes on the data type of the corresponding column in the table.
Use of the %ROWTYPE attribute is also not supported in DB2 Express-C, Express, and
Personal Editions. Here also you can use ANCHOR DATA TYPE TO clause to anchor data
type to a row of a table.
DB2 syntax:
DECLARE variable ANCHOR DATA TYPE
TO ROW OF table-name | view-name | cursor-variable-name;
DB2 example:
DECLARE accnt_row ANCHOR DATA TYPE TO ROW OF PUBLIC.ACCNT;
63
6.8
Basic Statements
6.8.1
37B
SET assignment
105B
In PL/pgSQL, an assignment of a value to a variable is defined as
variable := expression;
PostgreSQL example:
pTotalCost := pCost + pCommission;
In DB2, an assignment is done with a SET statement as shown below.
SET variable = expression;
DB2 example:
SET pTotalCost = pCost + pCommission;
6.8.2
VALUES statement
106B
Alternatively in DB2, an assignment can be done with a VALUES statement to set one or
multiple variables at one time. This is an efficient way set multiple variables in a loop.
For example:
VALUES ( (pCost + pCommission), (pCost + pCount) ) INTO pTotalCost, pAvgCost;
or
VALUES (pCost + pCommission, pCost + pCount) INTO pTotalCost, pAvgCost;
6.8.3
NULL statement
107B
PL/pgSQL allows NULL statement as a placeholder statement that does nothing.
For example:
BEGIN
...
EXCEPTION
WHEN no_data_found THEN
NULL;
END;
In SQL PL there is no NULL statement. Use an empty statement list instead (i.e., remove
the NULL statement).
6.8.4
RETURN statement
108B
The RETURN statement returns data from the function. There are two types of RETURN
statements in PL/pgSQL
64
RETURN Expression
RETURN with an expression terminates the function and returns the value of expression to
the caller. This is the simplest form of return statement and can be easily ported to DB2.
RETURN NEXT and RETURN QUERY
PL/pgSQL functions can also be declared to return a table. RETURN NEXT or RETURN
QUERY is used to return a table in PL/pgSQL.
These statements do not actually exit from the function. They simply append zero or more
rows to the function's result set. Execution then continues with the next statement in the
PL/pgSQL function. As successive RETURN NEXT or RETURN QUERY commands are
executed, the result set is built up. A final RETURN with no argument makes the control
exit the function.
When porting to DB2:
SQL PL in DB2 also supports returning a result set at the end of function execution.
However there are no RETURN NEXT and RETURN QUERY statements in DB2. Modify
the function to return a result set with appropriate result set type.
PL/pgSQL example:
CREATE OR REPLACE FUNCTION bomitem(integer, integer)
RETURNS SETOF bomitem AS
$BODY$
DECLARE
pItemid ALIAS FOR $1;
pRevid ALIAS FOR $2;
_row bomitem%ROWTYPE;
BEGIN
FOR _row IN SELECT * FROM bomitem
LOOP
RETURN NEXT _row;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE 'plpgsql';
DB2 SQL PL syntax:
CREATE OR REPLACE FUNCTION bomitem (pItemid integer, pRevid integer)
RETURNS TABLE (
bomitem_id integer,
bomitem_parent_item_id integer,
bomitem_seqnumber integer,
bomitem_item_id integer,
bomitem_qtyper decimal(20,8)...)
LANGUAGE SQL
BEGIN
RETURN
SELECT * FROM PUBLIC.BOMITEM
65
WHERE bomitem_parent_item_id=pItemid AND bomitem_rev_id=pRevid;
END
If RETURN NEXT statement is used as a place holder to append rows to the result set
before the final result set is returned to the calling program or client, replace RETURN
NEXT functionality in PL/pgSQL with global temporary table in SQL PL.
6.9
Control Structures
6.9.1
38B
IF and CASE statements
109B
Both PL/pgSQL and SQL PL support IF and CASE statements for conditional execution of
statements in a block. No changes are required to the structure of these conditional
statements when porting to DB2.
6.9.2
The difference between ELSIF and ELSEIF
10B
There is no functional difference between PL/pgSQL’s ELSIF statement and DB2’s SQL
PL equivalent ELSEIF, however it will be necessary to manually edit PostgreSQL functions
and substitute syntax to DB2’s supported keyword.
PL/pgSQL example:
. . .
IF (p_per_type = 'quarter') THEN
l_per_type := 'month';
l_per_num := p_per_num * 3;
ELSIF (p_per_type = 'week') THEN
l_per_type := 'day';
l_per_num := p_per_num * 7;
ELSIF (p_per_type IN ('year', 'month', 'day')) THEN
l_per_type := p_per_type;
l_per_num := p_per_num;
ELSE
. . .
DB2 SQL PL syntax:
. . .
IF (p_per_type = 'quarter') THEN
SET l_per_type = 'month';
SET l_per_num = p_per_num * 3;
ELSEIF (p_per_type = 'week') THEN
SET l_per_type = 'day';
SET l_per_num = p_per_num * 7;
ELSEIF (p_per_type IN ('year', 'month', 'day')) THEN
SET l_per_type = p_per_type;
SET l_per_num = p_per_num;
ELSE
. . .
66
6.9.3
LOOP statement
1B
The behavior of Loop statement is exactly same in PL/pgSQL and SQL PL but you might
want to change the way the label is defined when porting to DB2.
PL/pgSQL example:
[ <<label>> ]
LOOP
statements
END LOOP [ label ];
DB2 SQL PL syntax:
[ label :] LOOP
statements
END LOOP [ label ];
6.9.4
Records and cursors
12B
In routines, a cursor makes it possible to define a result set (a set of data rows) and
perform complex logic on a row by row basis. By using the same mechanics, a routine can
also define a result set and return it directly to the caller of the routine or to a client
application.
A cursor can be viewed as a pointer to one row in a set of rows. The cursor references one
row at a time, and can move to other rows of the result set as needed.
To use cursors in PL/pgSQL and SQL PL, you need to do the following:
1. Declare a cursor that defines a result set.
2. Open the cursor to establish the result set.
3. Fetch the data into local variables from the cursor, one row at a time.
4. Close the cursor when done
Both PL/pgSQL and SQL PL support the following statements to work with the cursors;
DECLARE CURSOR, OPEN, FETCH, and CLOSE
A FOR loop can be used to iterate through the rows returned by the cursor. FOR statement
automatically opens the cursor at the beginning of the loop and closes the cursor at the
end of the loop.
In addition to cursors, PostgreSQL also supports a FOR loop to iterate through the resultset of a query, without having to declare a cursor explicitly.
Example:
_row RECORD;
FOR _row IN SELECT *
FROM bomitem
WHERE ((bomitem_parent_item_id=pItemid)
AND (bomitem_rev_id=pRevid))
67
LOOP
RETURN NEXT _row;
END LOOP;
6.9.5
Working with DB2 cursors and result sets
13B
In SQL procedures, cursors can be used to do more than iterate through rows of a result
set. They can also be used to return result sets to the calling program.
Result sets can be retrieved by SQL procedures (in the case of a nested procedure calls)
or client applications programmed in C, Java, CLI, or .NET CLR languages.
To return a result set from an SQL procedure, you must:
1. Specify the DYNAMIC RESULT SETS clause in the CREATE
2. PROCEDURE statement
3. DECLARE the cursor using the WITH RETURN clause
4. Open the cursor in the SQL procedure
5. Keep the cursor open for the client application - do not close it
If the cursor is closed using the CLOSE statement prior to the return of the SQL procedure,
the cursor result set will not be returned to the caller or client application. Multiple result
sets can be returned from an SQL procedure by using multiple cursors.
To return multiple cursors the following must be done:
1. Specify the DYNAMIC RESULT SETS clause in the CREATE PROCEDURE
statement. Specify the maximum possible number of result sets likely to be
returned. The number of results sets actually returned must not exceed this
number.
2. Declare cursors for each of the result sets to be returned that specify the WITH
RETURN clause.
3. Open the cursors to be returned.
4. Keep the cursor open for the client application - do not close them.
5. One cursor is required per result set that is to be returned.
6. Keep the cursor open for the client application - do not close them.
7. One cursor is required per result set that is to be returned.
DB2 SQL PL Procedure syntax (with a dynamic result set):
CREATE OR REPLACE PROCEDURE bomitem (IN pItemid INTEGER, IN pRevid INTEGER)
LANGUAGE SQL
DYNAMIC RESULT SETS 1
BEGIN
DECLARE c1 CURSOR WITH RETURN TO CLIENT
FOR SELECT * FROM PUBLIC.BOMITEM
WHERE bomitem_parent_item_id=pItemid AND bomitem_rev_id=pRevid;
OPEN c1;
68
END
6.10 Condition Handling
39B
An exception is raised if an error occurs when executing an SQL statement in a routine.
Let us look at how you can trap and handle exceptions in PL/pgSQL and SQL PL.
6.10.1 RAISE Statement
14B
In PL/pgSQL you can use RAISE statement to report and handle individual errors.
Syntax of RAISE statement:
RAISE [ level ] 'format' [, expression [, ...]]
[ USING option = expression [, ... ] ];
Where:
• LEVEL specifies the severity of error.
• Allowed levels are DEBUG, LOG, INFO, NOTICE, WARNING, and EXCEPTION.
• EXCEPTION is the default level.
• EXCEPTION raises an error which aborts the current transaction.
• Other levels only generate messages of different priority levels.
• FORMAT is optional simple string literal.
• The format string specifies the error message text to be reported.
The format string can be followed by optional argument expressions to be inserted into the
message.
Inside the format string, % is replaced by the string representation of the next optional
argument's value.
USING followed by option = expression can be used to attach additional information to the
error report. The allowed option keywords are MESSAGE, DETAIL, HINT, and ERRCODE,
while each expression can be any string-valued expression.
Example1: RAISE
RAISE 'Duplicate Employee: %', empid USING ERRCODE = '90001';
Example2: RAISE EXCEPTION
CREATE FUNCTION basecurrid() RETURNS integer
AS $$
DECLARE
returnVal INTEGER;
BEGIN
SELECT curr_id INTO returnVal
FROM curr_symbol
WHERE curr_base = TRUE;
IF NOT FOUND THEN
69
RAISE EXCEPTION 'No base currency found';
END IF;
RETURN returnVal;
END;
$$
LANGUAGE plpgsql;
6.10.2 EXCEPTION Statement Block
15B
An EXCEPTION statement block is used to handle one or more known and unknown
errors in a routine.
Syntax:
EXCEPTION
WHEN condition [OR condition…] THEN
Exception-handler
WHEN condition [OR condition…] THEN
Exception-handler
…
WHEN OTHERS THEN
Exception-handler
END;
Example:
EXCEPTION
WHEN undefined_object THEN
RETURN 0;
WHEN undefined_table OR invalid_schema_name THEN
RETURN 0;
WHEN OTHERS THEN
RAISE EXCEPTION '% %', SQLSTATE, SQLERRM;
END;
6.10.3 GET DIAGNOSTICS Statement
16B
DB2’s GET DIAGNOSTICS statement is used to obtain information about the previously
executed SQL statement. The available options are ROW_COUNT,
DB2_RETURN_STATUS, and EXCEPTION 1.
Syntax:
GET DIAGNOSTICS sql-variable-name = ROW_COUNT | DB2_RETURN_STATUS
GET DIAGNOSTICS EXCEPTION 1 sql-variable-name = message_text
Where:
• The SQL variable name identifies the variable that is the assignment target. If
ROW_COUNT or DB2_RETURN_STATUS is specified, the variable must be an
integer variable, and must not be a global variable. Otherwise, the variable must be
CHAR or VARCHAR.
• ROW_COUNT identifies the number of rows associated with the previous SQL
statement. If the previous SQL statement is a DELETE, INSERT, or UPDATE
70
statement, ROW_COUNT identifies the number of rows that qualified for the
operation. If the previous statement is a PREPARE statement, ROW_COUNT
identifies the estimated number of result rows in the prepared statement.
• DB2_RETURN_STATUS identifies the status value returned from the procedure
associated with the previously executed SQL statement, provided that the statement
was a CALL statement invoking a procedure that returns a status. If the previous
statement is not such a statement, then the value returned has no meaning and
could be any integer.
• The message text identifies any error or warning message text returned from the
previously executed SQL statement. The message text is returned in the language
of the database server where the statement is processed. If the statement
completed with an SQLCODE of zero, an empty string is returned for a VARCHAR
variable or blanks are returned for a CHAR variable.
DB2 example:
CREATE OR REPLACE PROCEDURE sqlprocg (IN deptnbr VARCHAR(3))
LANGUAGE SQL
BEGIN
DECLARE SQLSTATE CHAR(5);
DECLARE rcount INTEGER;
UPDATE CORPDATA.PROJECT
SET PRSTAFF = PRSTAFF + 1.5
WHERE DEPTNO = deptnbr;
GET DIAGNOSTICS rcount = ROW_COUNT;
-- At this point, rcount contains the number of rows --- that were updated.
...
END @
6.10.4 DECLARE HANDLER Statement
17B
In SQL PL, you can also use condition handlers for exception handling. There are three
types of condition handlers: EXIT, CONTINUE, and UNDO.
DB2 syntax:
DECLARE CONTINUE|EXIT|UNDO HANDLER FOR condition <statement or block>
A CONTINUE handler will continue the execution of the statement that immediately follows
the statement that raised the exception.
EXIT handler will execute the SQL PL statements in the handler. After that, the handler
will skip the remaining statements in the current BEGIN-END block. Execution will
continue with the next statement to be executed. If the statement that raised the exception
is in the outer most procedure block, execution will continue in the routine that called the
procedure or control is passed to the DB2 if this is the highest level routine.
UNDO handler also continues with execution at the end of the compound statement in
which it was declared. Each executed statement will be rolled back in this compound
statement.
71
6.10.5 SIGNAL Statement
18B
DB2 will raise a condition automatically if an operation does not complete successfully. In
contrast, the SIGNAL statement can be used to raise a condition manually.
The RESIGNAL Statement is useful in EXIT exception handlers. It lets you pass the
exception encountered to the next higher program block. If that block has an exception
handler, it can take action. If not, the exception is automatically passed up to all higher
level program blocks – and commonly to DB2 when called from a main routine. Use
RESIGNAL to catch an exception, take some action, and then pass the exception to DB2
to stop execution. DB2 will display the exception on the terminal window if the program
was called from the Command Line Processor (CLP).
DB2 syntax:
SIGNAL SQLSTATE sqlstate [SET MESSAGE_TEXT text ]
SQL PL example:
CREATE OR REPLACE FUNCTION basecurrid()
RETURNS integer
BEGIN
DECLARE
DECLARE
DECLARE
DECLARE
returnVal INTEGER;
P_NOT_FOUND INTEGER DEFAULT 0;
SQLCODE INTEGER DEFAULT 0;
EXIT HANDLER FOR NOT FOUND
BEGIN
SIGNAL SQLSTATE 'SP001' SET MESSAGE_TEXT = 'No base currency found';
END;
SELECT curr_id INTO returnVal
FROM PUBLIC.curr_symbol
WHERE curr_base = 1;
RETURN returnVal;
END
When porting to DB2:
Use appropriate statement in SQL PL when porting the code used for error handling in
PL/pgSQL.
PL/pgSQL allows the format string to be followed by optional argument expressions to be
inserted into the message. Inside the format string, % is replaced by the string
representation of the next optional argument's value. This is not allowed in SQL PL
message text. The message text has to be simple text message without any expressions in
the message.
A workaround is to build the message text before passing it to the SIGNAL statement.
PLpg/SQL example:
IF (p_per_num <= 0) THEN
72
RAISE EXCEPTION ''Invalid negative or zero period number %'',
p_per_num;
RETURN NULL;
END IF;
SQL PL example:
IF (p_per_num <= 0) THEN
SET l_message_text = 'Invalid negative or zero period number '
|| CAST(p_per_num AS VARCHAR);
SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT = l_message_text;
RETURN NULL;
END IF;
Consider using DBMS_OUTPUT.PUTLINE when porting RAISE NOTICE.
PLpg/SQL example:
IF (p_start_date >= p_end_date) THEN
RAISE NOTICE ''Start date % should be before end date %'',
p_start_date, p_end_date;
RETURN -5;
END IF;
SQL PL example:
IF (p_start_date >= p_end_date) THEN
CALL DBMS_OUTPUT.PUT_LINE('Start date ' || p_start_date || ' should
be before end date ' || p_end_date);
RETURN -5;
END IF;
6.11 Using Dynamic SQL
40B
Dynamic SQL is used when the syntax of a statement is only known at runtime. The
statements will build typically by concatenating variables and strings.
The privileges to execute Dynamic SQL will be checked at runtime. Make sure that the
user calling the routine has required privileges to execute the statement.
In both SQL PL and PL/pgSQL, you can use EXECUTE IMMEDIATE statement if a
dynamic SQL is executed only once. PREPARE and EXECUTE statements are used if you
want to execute a statement multiple times.
When porting to DB2:
Dynamic values that are to be inserted into the constructed query require careful handling
since they might themselves contain quote characters. When working with dynamic SQL
statements, you will often have to handle escaping of single quotes.
In PL/pgSQL, expressions containing column or table identifiers are passed through
quote_ident function before insertion in a dynamic query. Expressions containing values
that should be literal strings in the dynamic SQL are passed through quote_literal function.
73
These functions take the appropriate steps to return the input text enclosed in double or
single quotes respectively, with any embedded special characters properly escaped.
Make sure, you make appropriate changes to the dynamic SQL statement that is
constructed in a routine and remove any PostgreSQL dependencies.
PL/pgSQL Example:
BEGIN
...
SELECT orderseq_number, orderseq_table, orderseq_numcol
INTO _number, _table, _numcol
FROM orderseq
WHERE (orderseq_name=psequence);
...
EXECUTE 'SELECT ' || quote_ident(_numcol) ||
' FROM ' || quote_ident(_table) ||
' WHERE (' || quote_ident(_numcol) || '=' ||
quote_literal(_number) || ');'
INTO _test;
...
END;
DB2 SQL PL example:
BEGIN
DECLARE VAR1 VARCHAR(1000);
DECLARE STMT1 STATEMENT;
...
SELECT orderseq_number, orderseq_table, orderseq_numcol
INTO pnumber, ptable, pnumcol
FROM PUBLIC.orderseq
WHERE (orderseq_name=psequence);
...
SET VAR1 = 'SELECT '|| CHAR(pnumcol)||' FROM '|| CHAR(ptable) || ' WHERE ('
|| CHAR(pnumcol) || '=' ||CHAR(pnumber) || ');'
PREPARE STMT1 FROM VAR1 ;
EXECUTE STMT1 INTO PTEST;
...
END
6.12 Triggers
41B
In PostgreSQL, a trigger is a specification to the database for the automatic execution of a
function whenever certain type of operation is performed. The operation is considered an
event that “triggers” the execution of additional procedural code.
The trigger specification is registered in the database using CREATE TRIGGER and
contains no procedural logic. A trigger specification identifies a trigger function to be
executed when the event has occurred.
e.g.
CREATE TRIGGER cashrcpttrigger
74
BEFORE INSERT OR UPDATE ON cashrcpt
FOR EACH ROW
EXECUTE PROCEDURE _cashrcpttrigger ();
Í trigger function
In DB2, a trigger is both the specification and procedural routine to be performed when the
specific event occurs. However, using a trigger to CALL a stored procedure is a frequently
used technique and can be used to emulate the PostgreSQL implementation.
Both database recognize INSERT, UPDATE or DELETE operations as trigger events,
Neither database supports the use of SELECT triggers.
6.12.1 FOR EACH ROW and FOR EACH STATEMENT
19B
Both DB2 and PostgreSQL offer both per-row triggers and per-statement triggers. With a
per-row trigger, the trigger function is invoked once for each row that is affected by the
statement that fired the trigger. In contrast, a per-statement trigger is invoked only once
when an appropriate statement is executed, regardless of the number of rows affected by
that statement.
It should be noted, in both databases a statement that affects zero rows will still result in
the execution of any applicable per-statement triggers.
6.12.2 Classified as BEFORE or AFTER
120B
Both DB2 and PostgreSQL support two trigger classifications: before triggers and after
triggers. Statement-level before triggers naturally fire before the statement starts to do
anything, while statement-level after triggers fire at the very end of the statement. Rowlevel before triggers fire immediately before a particular row is operated on, while row-level
after triggers fire at the end of the statement (but before any statement-level after triggers).
6.12.3 Multiple events on a single object
12B
PostgreSQL supports trigger specifications for multiple events INSERT or UPDATE:
e.g.
CREATE TRIGGER cashrcpttrigger
BEFORE INSERT OR UPDATE ON cashrcpt
Í trigger executed on both operations
FOR EACH ROW
EXECUTE PROCEDURE _cashrcpttrigger ();
DB2 requires a separate trigger to be created for each type of operation regardless if the
procedural logic is the same. For example, you cannot have a single trigger that activates
for both UPDATE and INSERT events. You must create two separate triggers.
6.12.4 Multiple triggers for a single event type
12B
PostgreSQL supports more than one trigger being defined for the same event on the same
relation (i.e. multiple INSERT triggers for the same table) and will fire each in alphabetical
order by trigger name.
75
In DB2, multiple triggers can be created on the same event and relation however the
activation order is determined by which ones were created first as opposed to alphabetical
order.
6.12.5 Cascading triggers
123B
When a PostgreSQL trigger function executes SQL commands, these commands might
fire triggers again. This is known as cascading triggers. There is no direct limitation on the
number of cascade levels. It is possible for cascades to cause a recursive invocation of
the same trigger; for example, an INSERT trigger might execute a command that inserts
an additional row into the same table, causing the INSERT trigger to be fired again. It is the
trigger programmer's responsibility to avoid infinite recursion in such scenarios.
DB2 protects against this scenario by supporting BEFORE triggers with an implicit no
cascade. Also, BEFORE triggers have restrictions on the types of stored procedures it can
execute. Thus DB2 will not encounter recursive processing of triggers.
When creating a BEFORE trigger which executes a stored procedure the procedure will
need the inclusion of the keywords READS SQL DATA and contain no DML statement
which modifies data. DB2’s BEFORE triggers cannot execute a stored procedure which
contains a DML statement other than SELECT. This is to enforce a rule protecting against
operations that might activate other triggers.
An AFTER trigger activates AFTER a row is inserted, updated, or deleted. AFTER triggers
do allow INSERT, UPDATE, and DELETE statements. You can designate an AFTER
trigger as FOR EACH ROW, meaning that the trigger should activate after every row is
inserted, updated, or deleted. Or, you can designate the trigger as FOR EACH
STATEMENT, which activates it after the triggering statement completes and all applicable
rows have been processed.
6.12.6 Access to transition data and values
124B
Each database has its own method for making the trigger input data available to the trigger
function:
For PostgreSQL this input data includes the type of trigger event (e.g., INSERT, UPDATE
or DELETE) as well as any arguments passed to the trigger function. For a row-level
trigger, the input data also includes the NEW row for INSERT and UPDATE triggers, and
the OLD row for UPDATE and DELETE triggers. Statement-level triggers do not currently
have any way to examine the individual row(s) modified by the statement.
DB2 triggers can access both transition variables as well as complete data sets which are
effected by the triggering operation. The REFERENCING clause specifies the correlation
names for the transition variables and the table names for the transition tables. Correlation
names identify a specific row in the set of rows affected by the triggering SQL operation.
Table names identify the complete set of affected rows.
Each row affected by the triggering SQL operation is available to the triggered action by
qualifying columns with correlation-names specified as follows:
OLD AS correlation-name specifies a correlation name which identifies the row state prior
to the triggering SQL operation.
76
NEW AS correlation-name specifies a correlation name which identifies the row state
as modified by the triggering SQL operation and by any SET statement in a BEFORE
trigger that has already executed.
The complete set of rows affected by the triggering SQL operation is available to the
triggered action by using a temporary table name specified as follows.
OLD TABLE AS identifier specifies a temporary table name which identifies the set of
affected rows prior to the triggering SQL operation.
NEW TABLE AS identifier specifies a temporary table name which identifies the affected
rows as modified by the triggering SQL operation and by any SET statement in a BEFORE
trigger that has already executed.
6.12.7 Enabling PostgreSQL triggers in DB2
125B
When a PostgreSQL trigger function is defined, arguments can be specified for it. The
purpose of including arguments in the trigger definition is to allow different triggers with
similar requirements to call the same function. As an example, there could be a
generalized trigger function that takes as its arguments two column names and puts the
current user in one and the current time stamp in the other.
A properly written PostgreSQL trigger function would typically be independent of the
specific table it is triggering on. So the same function could be used for INSERT events on
any table with suitable columns, to automatically track creation of records in a transaction
table for example. It could also be used to track last-update events if defined as an
UPDATE trigger.
There are two recommended methods for converting PostgreSQL triggers to DB2:
1 – Emulate the architecture of the Postgres’ trigger implementation. This can be
accomplished by creating only the specification as a DB2 trigger and placing all trigger
function logic within a DB2 stored procedure. This maps two PostgreSQL objects directly
to two DB2 objects.
2 - Consolidate the PostgreSQL trigger and trigger function into a single DB2 trigger.
The complexity of the PostgreSQL trigger functions logic should be considered before
making a decision on which methodology to use for the conversion. While consolidating
into a single database object would provide the most efficient and easiest scenario to
manage, DB2 triggers support only a sub-set of the SQL PL commands available within a
stored procedure and the complexity of the PostgreSQL trigger function may require the
full support of DB2’s SQL PL programming language.
Converting the trigger function
PostgreSQL example:
CREATE OR REPLACE FUNCTION _cashrcpttrigger()
RETURNS trigger AS
$BODY$
DECLARE
_check
BOOLEAN;
77
_checkId
INTEGER;
_currId
INTEGER;
_bankCurrId INTEGER;
BEGIN
-- Checks
-- Start with privileges
IF (TG_OP = 'INSERT') THEN
SELECT checkPrivilege('MaintainCashReceipts')
IF NOT (_check) THEN
RAISE EXCEPTION 'You do not have privileges
Cash Receipts.';
END IF;
ELSE
SELECT checkPrivilege('MaintainCashReceipts')
IF NOT (_check) THEN
RAISE EXCEPTION 'You do not have privileges
Cash Receipt.';
END IF;
END IF;
INTO _check;
to add new
INTO _check;
to alter a
-- Currency must be same as Bank Currency
IF (TG_OP = 'INSERT') THEN
_currId = COALESCE(NEW.cashrcpt_curr_id, basecurrid());
ELSE
_currId = NEW.cashrcpt_curr_id;
END IF;
SELECT bankaccnt_curr_id INTO _bankCurrId
FROM bankaccnt
WHERE (bankaccnt_id=NEW.cashrcpt_bankaccnt_id);
IF (_currId<>_bankCurrId) THEN
RAISE EXCEPTION 'Currency supplied does not match Bank Currency.';
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
DB2 syntax:
CREATE OR REPLACE PROCEDURE cashrcpttrigger (
IN tg_op CHAR(6),
IN new_cashrcpt_curr_id INTEGER,
IN new_cashrcpt_bankaccnt_id INTEGER
)
READS SQL DATA
BEGIN
DECLARE check
BOOLEAN;
DECLARE checkId
INTEGER;
DECLARE currId
INTEGER;
DECLARE bankCurrId INTEGER;
-- Checks
-- Start with privileges
IF (TG_OP = 'INSERT') THEN
SET check = public.checkPrivilege('MaintainCashReceipts');
IF (check != TRUE) THEN
78
SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT='You do not have privileges to add
new Cash Receipts.';
END IF;
ELSE
SET check = public.checkPrivilege('MaintainCashReceipts');
IF (check != TRUE) THEN
SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT='You do not have privileges to
alter a Cash Receipt.';
END IF;
END IF;
-- Currency must be same as Bank Currency
IF (TG_OP = 'INSERT') THEN
SET currId = COALESCE(new_cashrcpt_curr_id, basecurrid());
ELSE
SET currId = new_cashrcpt_curr_id;
END IF;
SELECT bankaccnt_curr_id INTO bankCurrId
FROM bankaccnt
WHERE ( bankaccnt_id = new_cashrcpt_bankaccnt_id );
IF (currId <> bankCurrId) THEN
SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT='Currency supplied does not match
Bank Currency.';
END IF;
END@
Converting the trigger
Postgres example:
CREATE TRIGGER cashrcpttrigger
BEFORE INSERT OR UPDATE ON cashrcpt
FOR EACH ROW
EXECUTE PROCEDURE _cashrcpttrigger ();
DB2 syntax:
CREATE TRIGGER cashrcpttrigger_i
BEFORE INSERT ON cashrcpt
REFERENCING NEW AS new
FOR EACH ROW
CALL public.cashrcpttrigger
('INSERT', new.cashrcpt_curr_id, new.cashrcpt_bankaccnt_id);
CREATE or replace TRIGGER cashrcpttrigger_u
BEFORE UPDATE ON cashrcpt
REFERENCING NEW AS new
FOR EACH ROW
CALL public.cashrcpttrigger
('UPDATE', new.cashrcpt_curr_id, new.cashrcpt_bankaccnt_id);
79
6.13 PostgreSQL Rules
42B
PostgreSQL supports a database rule system which allows the definition of alternative
action to be performed when a data manipulation statement (DML) is processed against a
specified table.
The PostgreSQL rule system could be more accurately described as a “query rewrite
facility”. It interfaces with the database’s query optimization process; between the parser
and the planner, and has the ability to transform a query prior to passing a modified
version for planning and execution. Rules can be a very powerful tool since they can not
only apply substitution, but include additional SQL statements for processing and thus
providing a macro-expansion facility for SQL Processing.
From an enablement perspective, a PostgreSQL rule can be emulated by DB2 using a
combination of triggers and stored procedures.
There are some differences in the initiating event; PostgreSQL rules can be initiated by
any DML statement (i.e. SELECT, INSERT, UPDATE, or DELETE) processed against a
table. DB2 triggers can be initiated by an INSERT, UPDATE, or DELETE events with no
support for a trigger based on a SELECT event.
Additionally, a PostgreSQL rule uses a specification of DO ALSO or DO INSTEAD which
designates how the rule is to interact with the original query. A rule’s DO specification will
be followed by one or more SQL commands or the keyword NOTHING as an instruction
that no action is to take place. In DB2, the type of trigger; BEFORE, AFTER and
INSTEAD OF determines how it processes with the original query and a sub-set of DB2’s
SQL PL programming language provides the procedural processing capability.
PostgreSQL has support for a NOTIFY action, a simple form of an inter-process
communication mechanism, which has no corresponding facility in DB2.
The following example demonstrates how the similarities between a PostgreSQL rule and
a DB2 trigger can ease of conversion. In this case an update to a table causes the
execution of an INSERT statement. By default, a PostgreSQL rule definition’s is DO ALSO
thus a DB2 AFTER trigger would perform this procedure in an identical manner.
PostgreSQL example:
CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
WHERE NEW.sl_avail <> OLD.sl_avail
DO INSERT INTO shoelace_log VALUES (
NEW.sl_name,
NEW.sl_avail,
current_user,
current_timestamp
);
DB2 syntax
CREATE TRIGGER log_shoelace AFTER UPDATE ON shoelace_data
REFERENCING NEW AS new OLD AS old
FOR EACH ROW
WHEN (NEW.sl_avail <> OLD.sl_avail)
INSERT INTO SHOELACE_LOG VALUES (
80
NEW.SL_NAME,
NEW.SL_AVAIL,
CURRENT_USER,
CURRENT_TIMESTAMP
);
A PostgreSQL INSTEAD rule can be converted easily to a DB2 INSTEAD OF trigger if
applicable database object is a view. DB2 only supports the use of INSTEAD OF triggers
on views. While PostgreSQL does not have this restriction, INSTEAD logic for rules was
implemented to provide the ability to update complex views making all views “update-able”.
This was the same rationale as DB2 so you may find most occurrences within your
database to be capable of the conversion without significant change.
PostgreSQL example:
CREATE RULE shoelace_ins AS ON INSERT TO shoelace Í
DO INSTEAD
INSERT INTO shoelace_data VALUES (
NEW.sl_name,
NEW.sl_avail,
NEW.sl_color,
NEW.sl_len,
NEW.sl_unit
);
shoelace is a view
DB2 syntax:
CREATE trigger shoelace_ins INSTEAD OF INSERT ON shoelace
REFERENCING NEW AS new
FOR EACH ROW
INSERT INTO shoelace_data VALUES (
NEW.sl_name,
NEW.sl_avail,
NEW.sl_color,
NEW.sl_len,
NEW.sl_unit
);
While there are similarities between the uses of a PostgreSQL rule and those of a DB2
trigger it is important to realize that a PostgreSQL rule is a unique object with some unique
capabilities which are not supported by DB2.
81
7.
Basic Security
6B
There are many similarities between PostgreSQL and DB2’s Basic Security. This section
examines the three primary security mechanisms of both databases while focusing on the
differences between their implementations:
Authentication
• Process of validating a supplied user ID and password against a security facility
• Confirming “you are who you say you are”
Authorization
• Determines the operations that users, roles or group authorities can perform and
controls access to database objects
• Examples of authorities: SYSADM, DBADM, SECADM
Privileges
• Defines operations permitted on database objects
• Object security more granular than authorities
7.1
Authentication
43B
There is no user authentication data managed DB2. Authentication of a user is completed
using a security facility outside of the DB2 database. The security facility can be part of
the operating system or a separate product. Any attempt to attach to the instance or
connect to any of the instance’s databases will require the user ID identifies the user to the
security facility. By supplying the correct password, information known only to the user and
the security facility, the user's identity (corresponding to the user ID) is verified.
PostgreSQL database passwords are separate from operating system user passwords.
The password for each database user is stored in the pg_authid system catalog.
Passwords can be managed with the SQL commands CREATE USER and ALTER USER,
e.g., CREATE USER user-id WITH PASSWORD 'secret'. By default, that is, if no
password has been set up, the stored password is null and password authentication will
always fail for that user.
H
H
H
H
Both DB2 and PostgreSQL support a variety of authentication using similar methods;
trusted authentication, password authentication, encrypted passwords, LDAP, Kerberos,
GSS-API, SSPI, SSL plug-in and PAM authentication.
PostgreSQL supports an Identification-based authentication which DB2 does not support
natively however can be configured using a combination of a authentications and
authorizations.
82
7.2
Authorization
4B
As mentioned already, DB2 relies upon an authentication process external to the
database. The user is authenticated to be “who he says he is” by an external sub-system
and as a result no user security data such as the user’s password are in the database.
Once the user has passed through Authentication, the second component of basic
security, Authorization, takes responsibility for managing access to specific database
objects. Once connected to a DB2 database, users (identified by an authorization ID) can
successfully execute operations only if they have the authority to perform the specified
function. For example, to create a table, a user must be authorized to create tables; to
alter a table, a user must be authorized to alter the table; and so forth.
PostgreSQL manages all database access permissions using the concept of roles. A role
can be thought of as either a database user, or a group of database users, depending on
how the role is set up (i.e. CREATE … LOGIN or NOLOGIN). A role having the LOGIN
attribute can be thought of as a user. Roles without this attribute are useful for managing
database privileges, but are not users in the usual sense of the word.
DB2 supports a concept of “Separation of Duties” for database authorities and divides the
duties of database administrator and security administrator. This separation empowers the
Security Administrator (SECADM) to the highest authorization for managing users and
database access. The SECADM authority is required for all grants and revokes of
authorities, roles and privileges.
7.3
Privileges
45B
In both databases, roles can own database objects (for example, tables) and can assign
privileges on those objects to other roles to control who has access to which objects.
Furthermore, it is possible to grant membership in a role to another role, thus allowing the
member role use of privileges assigned to the role it is a member.
In DB2, managing database privileges through the use of roles is the equivalent of
PostgreSQL’s user security.
7.4
7.4.1
Data Control Language (DCL)
46B
Creating a RESTRICTIVE database in DB2
126B
When the RESTRICTIVE option is used when creating a DB2 database the DB CFG
parameter RESTRICT_ACCESS is set to YES and no privileges or authorities are
automatically granted to PUBLIC.
DB2 syntax:
CREATE DATABASE database-name RESTRICTIVE
83
7.4.2
Instance administrative authority
127B
PostgreSQL example:
CREATE ROLE role-name SUPERUSER
DB2 syntax:
Using the security management facility of the operating or 3rd party security system create
the user id and group id (if necessary), assign the user to the group then update the
instance configuration for SYSADM_GROUP to the group-name.
UPDATE DBM CFG USING SYSADM_GROUP {group-name}
All members of the group identified by SYSADM_GROUP parameter value will have the
instance’s highest administrative privileges.
Database administrative authority
7.4.3
128B
DB2 database administrative authority is granted to roles or users using the GRANT
command.
PostgreSQL example:
CREATE ROLE role-name SUPERUSER
DB2 syntax:
CREATE ROLE dba
GRANT DBADM ON DATABASE TO ROLE dba
GRANT ROLE dba TO USER bob
7.4.4
Creating a new database user and granting user privileges
129B
PostgreSQL example:
CREATE ROLE { user-id | role-name } LOGIN
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE
DB2 equivalent syntax:
CREATE ROLE { user-id | role-name }
GRANT CONNECT ON DATABASE TO ROLE { user-id | role-name }
GRANT DATAACCESS ON DATABASE TO ROLE { user-id | role-name }
GRANT ROLE { user-id | role-name } TO USER { user-id | role-name }
84
8.
Migration Issues
7B
This section lists known migration issues which cannot be identified as part of DDL, DML
or SQL considerations. This allows a separate discussion of the issues when enabling an
application from PostgreSQL to DB2.
For example, the issues surrounding creating a stored procedure are discussed in the DDL
section, and the issues surrounding the stored procedure language are discussed in the
DML section.
This section is provided as a “how to” guide when a simple solution is not available.
8.1
Name identifiers
47B
Rules exist for the naming of all database objects, users, groups, files, and paths in both
Postgres and DB2. Some of these rules are specific to the operating system platform.
On UNIX platforms, names are case-sensitive. For example, /data1 is not the same
directory as /DATA1 or /Data1
On Windows® platforms, names are not case-sensitive. For example, \data1 is the same
as \DATA1 and \Data1.
In DB2, all names can include the following characters:
− The letters A through Z, and a through z, as defined in the basic (7-bit) ASCII character
set. When used in identifiers for objects created with SQL statements, lowercase
characters “a” through “z” are converted to uppercase unless they are delimited with
quotes (“)
− 0 through 9
− ! % ( ) { } . – ~ _ (underscore) @, #, $, and space
− \ (backslash)
A comparison of PostgreSQL and DB2 conventions results in a restriction; DB2 name
identifies can not begin names with a number or with the underscore character.
8.2
Database name length
48B
All DB2 identifiers visible by the application have a name limit of 128 characters with the
following exceptions:
• Database and database aliases are limited to 8 characters in length
• Buffer pools and table spaces are limited to 18 characters in length
• Index extensions, ADT transform groups, and type mappings are limited to 18.
85
The only resolution is reduce the length of the PostgreSQL database object name to
conform to DB2 naming standard lengths.
A database name should be the only identifier requiring conversion impacting the
application. The other database objects bound by the 18 character limit are never
referenced directly by SQL statements so shortening of these names has no functional
impact on your migrated application.
8.3
Column default derived from function
49B
Only built in functions can are supported as default values for column declarations.
CREATE TABLE "PUBLIC"."ACCNT"
(
“ACCNT_CURR_ID” INTEGER DEFAULT basecurrid()
…
);
-orALTER TABLE "PUBLIC"."ACCNT"
ALTER COLUMN "ACCNT_CURR_ID" SET WITH DEFAULT basecurrid
Solution:
• The assignment of a default value returned by the PostgreSQL function will need to
be encapsulated within a DB2 BEFORE on INSERT trigger. A BEFORE trigger can
be used to manipulate a column’s value for the rows processed by an INSERT,
UPDATE or DELETE statement.
8.4
TYPE declarations in functions and procedures
50B
DB2 9.7 does not support TYPE declarations inside functions and procedures. The only
exception being TYPE <type> IS REF CURSOR. All other variable types will need variable
types to be created outside of the routine.
8.5
SUBSTR restrictions
51B
Both DB2 and PostgreSQL SUBSTR function have operational equivalence, being passed
a string, a starting position and number of characters to be extracted from string.
DB2’s SUBSTR function requires the value of <length> to be in the range of 0 to n, where
n equals LENGTH_OF_<string> - <start> + 1. When exceeded, this limit will return an
error.
PostgreSQL does not impose this restriction thus the references to this function may have
specified a value that is greater than DB2’s upper limit.
PostgreSQL example:
86
CREATE TABLE shoe_sizes
(
sl_name character varying(30)[],
sl_avail integer
);
select substr(sl_name, 10,30) from shoelace_data;
-orselect substr(sl_name, 10,999) from shoelace_data;
DB2 syntax:
CREATE TABLE shoe_sizes
(
sl_name character varchar(30),
sl_avail integer
);
Length value must be
reduced to DB2 limit
select substr(sl_name, 10,21) from shoelace_data;
8.6
DEFAULT parameters in functions
52B
DB2 9.7 does NOT support DEFAULT parameters on functions. If this functionality is
needed it will be necessary to create a duplicate of the function and overload it with a
version which supplies the default value or find all references to the function and call it
passing the default value in cases where no value was being passed.
Functions that modify data
DB2 9.7 requires that you add the MODIFIES SQL DATA option when declaring a function
that performs any INSERT, UPDATE or DELETE processing.
The only solution is to add the required syntax to the user defined function.
CREATE FUNCTION DEPTEMPLOYEES (DEPTNO CHAR(3))
RETURNS TABLE (EMPNO CHAR(6), LASTNAME VARCHAR(15))
LANGUAGE SQL
MODIFIES SQL DATA
NO EXTERNAL ACTION
DETERMINISTIC
BEGIN ATOMIC
INSERT INTO AUDIT
VALUES (USER, ‘Table: EMPLOYEE Prd: DEPTNO = ' || DEPTNO);
RETURN
SELECT EMPNO, LASTNAME, FIRSTNME
FROM EMPLOYEE
WHERE EMPLOYEE.WORKDEPT = DEPTEMPLOYEES.DEPTNO;
END
8.7
Boolean variables and IF statements
53B
DB2 9.7 does not support the use of a BOOLEAN variable as a boolean expression in a
test condition with the SQL PL procedural language.
87
The PostgreSQL syntax must be changed, from:
IF v_firstColumn THEN
DB2’s supported syntax:
IF (v_firstColumn = TRUE) THEN
8.8
INTERVAL data type
54B
In PostgreSQL interval values are written with syntax QUANTITY UNIT where quantity is a
number and unit is microsecond, millisecond, second, minute, hour, day, week, month,
year, decade, century, millennium, or abbreviations or plurals of these units (i.e. 2
MONTH).
There is no interval data type in DB2’s SQL PL. A workaround is to use two variables, one
for quantity and one for unit.
PLpg/SQL example:
CREATE OR REPLACE FUNCTION LIST_EMPLOYEES (INTERVAL)
RETURNS RECORD
LANGUAGE 'plpgsql'
AS
$$
DECLARE
l_cutoff_time interval ALIAS for $1;
l_emprec RECORD;
BEGIN
FOR l_emprec in (select empno, empname from employee
where hiredate < current_date – l_cutoff_time)
LOOP
RETURN l_emprec;
END LOOP;
END;
$$
;
DB2 SQL PL syntax:
CREATE OR REPLACE FUNCTION LIST_EMPLOYEES (l_cutoff_quantity SMALLINT,
l_cutoff_unit VARCHAR(20))
RETURNS TABLE(empno INT, empname VARCHAR(30))
BEGIN
DECLARE l_cutoff_date TIMESTAMP;
IF (l_cutoff_unit = 'year') THEN
SET l_cutoff_date = current_date - ((l_cutoff_quantity * 1) years);
ELSEIF (l_cutoff_unit = 'month') THEN
SET l_cutoff_date = current_date - ((l_cutoff_quantity * 1) months);
ELSEIF (l_cutoff_time_unit = 'day') THEN
SET l_cutoff_date = p_data_timestamp - ((l_cutoff_quantity * 1) days);
END IF;
RETURN select empno, empname
88
from employee
where hiredate < current_date – l_cutoff_time;
END
8.9
Un-typed NULL values in a SELECT list
5B
The following PostgreSQL SQL statement will be returned an error by DB2:
PostgreSQL example:
SELECT sl_name, NULL as sl_size FROM shoe_sizes
SQL0418N A statement contains a use of an un-typed parameter marker or a null
value that is not valid. SQLSTATE=42610
The reason for the error is the presence of a result column (sl_size) of a SELECT
statement that is returning an un-typed NULL value expression. DB2 can not resolve the
expression type of the NULL value to a data type from the SELECT list.
Solution:
• The un-typed NULL value must be explicitly cast to a valid DB2 data type.
SELECT sl_name, CAST(NULL AS INTEGER) as sl_size FROM shoe_sizes
8.10 Combined action triggers
56B
DB2 9.7 does not support combined event triggers, i.e., triggers that are fired for more than
one event, with events being INSERT, UPDATE and DELETE type of action.
CREATE TRIGGER custtrigger
BEFORE INSERT OR DELETE OR UPDATE ON custinfo
FOR EACH ROW
EXECUTE PROCEDURE _custtrigger();
Solution:
• Split the combined action trigger into separate triggers, one for each type of action.
In this case, you will need to split the original trigger in two different triggers. One
will have the AFTER INSERT clause and the other will have the AFTER UPDATE
clause.
8.11 BEFORE triggers that modify the database
57B
DB2 9.7 does not allow BEFORE triggers to modify the database. That means BEFORE
triggers can not execute DML operations such as INSERT, UPDATE or DELETE.
Solution:
• Convert any BEFORE trigger which processes a DML statement to an AFTER trigger.
Comment out all insert, update and delete operations in the original BEFORE trigger
89
and create a new AFTER trigger to execute all the operations which must be
removed from the BEFORE trigger.
8.12 Using a function’s expression as an index key
58B
Functional indexes are indexes created on the value returned by the function, rather than
the value of a column. PostgreSQL will allow an index to be created using a built-in or
user-defined function.
DB2 does not support functional indexes however a solution can be engineered using the
GENERATED ALWAYS option applied to a column’s definition.
PostgreSQL example:
CREATE INDEX indx1 ON tab1(UPPER(COL1))
DB2 solution:
SET INTEGRITY FOR tab1 OFF;
ALTER TABLE tab1 ADD col2 GENERATED ALWAYS AS (UPPER(col1));
SET INTEGRITY FOR tab1 IMMEDIATE CHECKED FORCE GENERATED;
CREATE INDEX INDX1 ON tab1(col2);
When using this solution the application’s SQL does not need to changed. The DB2 SQL
optimizer will compensate and choose the proper index for the generated index key.
8.13 Limitation on table row width
59B
Within a DB2 database, rows in a table cannot span more than one page. A table's row
size is the sum of bytes required to represent all the columns in a table (not including LOB
data).
DB2’s maximum page size is 32 kilobytes. Therefore, maximum row size for any table
must be within this 32 kilobyte limit.
Solutions (more than one may apply):
1. Reduce the table’s row size
Evaluate how the tables are used and the businesses reasons for having this size.
Very often, the majority of these large tables could be reduced below the 32 K limit
easily without a major impact on applications.
2. Relocate data elements
Use DB2’s XML or CLOB data type for column’s containing large character strings.
The table’s required row width can be reduced by storing columns in alternate
locations. In DB2, XML and large object data can designate a storage location in
another table space other than the remaining data elements of the table.
3. Create a view to represent the two wide tables
90
If the row width cannot be reduced under the 32,676 byte limit another possible
solution is to physically split the table into two tables and provide the application
with a unified view.
Solution:
Postgres
CREATE TABLE wide_table(
pk INTEGER,
c1 VARCHAR(20000),
c2 VARCHAR(20000));
DB2
CREATE
pk
c1
c2
TABLE wide_table1(
INTEGER,
VARCHAR(15000),
VARCHAR(15000));
CREATE
pk
c1
c2
TABLE wide_table2(
INTEGER,
CLOB(20K),
CLOB(20K));
Then unify the two tables using a view:
CREATE VIEW wide_table
AS
SELECT wide_table1.c1, wide_table1 c2, wide_table2.c1, wide_table2.c2
FROM wide_table1, wide_table2
WHERE wide_table.pk = wide_table2.pk;
8.14 Disabling triggers
60B
There is no facility for disabling triggers in DB2. Without the ability to disable a trigger the
only option in DB2 is to drop and re-create the trigger.
91
9.
9.1
Additional Resources
8B
Education and learning
61B
Porting to DB2 Universal Database. The developerWorks DB2 Universal Database porting
site gives you the information you need to port an application and its data from other
database management systems to DB2 UDB.
H
H
Visit the developerWorks DB2 zone to expand your DB2 skills
H
H
Stay current with DeveloperWorks technical events and Webcasts.
H
H
UDFs to ease migration
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm0504greenstein/index.html
HU
U
Everything You Wanted to Know About DB2 Universal Database Processes
http://www128.ibm.com/developerworks/db2/library/techarticle/0304chong/0304chong.html
HU
Leverage MySQL skills to learn DB2 Express
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0602tham2/
HU
U
U
DB2 Express-C, the developer-friendly alternative
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0602hutchison/
HU
UH
Log DB2 UDB stored procedure messages
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0601khatri
HU
Getting to know the DB2 UDB command line processor
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0503melnyk/
HU
U
The IBM DB2 Universal Database for Linux, UNIX, and Windows Backup Utility
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0501zikopoulos/
HU
U
Lock avoidance in DB2 UDB V8
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0509schuetz/
HU
U
Migrating to IBM database servers gets easier with the latest MTK release
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0603geib/
HU
92
9.2
Download products and technologies
62B
DB2 Express-C Absolutely Free
http://www.ibm.com/developerworks/downloads/im/udbexp/?S_TACT=105AGX01&S_CMP
=LP
H
Software Evaluation Kits on DVDs
http://www.ibm.com/cgibin/software/track0.cgi?i=53018&c=74648&o=5&ef=T&cn=7817704
H
Featured product trials
http://www.ibm.com/cgibin/software/track0.cgi?i=50023&c=74648&o=4&ef=T&cn=7817704
H
PostgreSQL JDBC Driver
http://jdbc.postgresql.org/
H
IBM JDK 5.0
http://www-128.ibm.com/developerworks/java/jdk/
H
9.3
Discussion groups and forums
63B
Participate in DB2 discussion Groups
IBM DB2 Express-C Forum
http://www-128.ibm.com/developerworks/forums/dw_forum.jsp?forum=805&cat=19
H
Participate in developerWorks blogs and get involved in the developerWorks community.
H
9.4
H
References
9.4.1
64B
PostBooks: An Open Source ERP
130B
Most of the PostgreSQL examples used in this document are from the database of a free
open source ERP application called PostBooks. More information about this application
can be found at: http://sourceforge.net/projects/postbooks/
H
9.4.2
PostgreSQL Documentation
13B
Porting Topics covered in this document are based on PostgreSQL version 8.4. Online
documentation can be found at: http://www.postgresql.org/docs/
H
9.4.3
DB2 Documentation
132B
Porting Topics covered in this document are based on DB2 Express-C Edition for Linux,
Unix, and Windows version 9.7. From time to time, we have also covered some advanced
topics like table partitioning which is part of DB2 Enterprise Edition. DB2 Online
93
documentation can be found at:
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
H
9.4.4
developerWorks Articles
13B
We referred to the following two articles for the content in architectural overview and data
type comparison chapters.
Leverage your PostgreSQL V8.1 skills to learn DB2, Version 8.2
http://www.ibm.com/developerworks/data/library/techarticle/dm0603wasserman2/index.html
H
Migrate from MySQL or PostgreSQL to DB2 Express-C
http://www.ibm.com/developerworks/data/library/techarticle/dm-0606khatri/
H
Complete coverage of DB2 Data Partitioning features is beyond the scope of this guide,
the following developerWorks articles provide resources to learn about different DB2 data
partitioning features and the best approach to implement each of them:
DB2 partitioning features
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0608mcinerney/
H
Introducing DB2 9, Part 2: Table partitioning in DB2 9
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0605ahuja2/
H
94
Appendix A - Using the IBM Data Movement Tool (IDMT)
9B
There is a free tool offered by IBM to assist your enablement effort. The IBM Data
Movement Tool (IDMT) is a simple tool that can extract database object definitions (DDL)
and data from a variety of database management systems to a format which can be
accepted by DB2 for Linux, UNIX, and Windows and DB2 for z/OS.
This tool can be downloaded from:
DB2 9.7: IBM Data Movement Tool
http://www.ibm.com/developerworks/data/library/techarticle/dm-0906datamovement/
H
This tool is not supported by the IBM support organization. However, you can report bugs,
issues, suggestions, and enhancement requests in the support forum.
H
H
95
While IDMT does not fully support migrations from PostgreSQL it can still provide a
significant assist with a migration. The utility will extract and produce a script of DDL
converted to DB2 syntax for each table, index and sequence object.
Prior to deployment in a DB2 database the DDL scripts generated by IDMT should be
reviewed for any conversion issues. Typically, DDL conversion issues can result from data
type mapping or the use of native PostgreSQL functions in a table definition.
See the following examples:
Mapping TEXT to CLOB(2147483647)
IDMT will map the PostgreSQL data type TEXT to the DB2 data type CLOB. If this is not
acceptable it will be necessary to determine the required size for the column to contain the
data and manually edit the db2tables.sql file prior to deployment of the DDL within the
destination DB2 database.
TIMESTAMP data types with default of ‘now’
IDMT does not convert the PG/sql keyword ‘now’. It will be necessary to replace the
reference with DB2’s CURRENT TIMESTAMP.
Extracted by IDMT:
ALTER TABLE "PUBLIC"."BANKREC"
ALTER COLUMN "BANKREC_CREATED" SET WITH DEFAULT 'now'
Manually edited for DB2:
ALTER TABLE "PUBLIC"."BANKREC"
ALTER COLUMN "BANKREC_CREATED" SET WITH DEFAULT CURRENT TIMESTAMP
96
© Copyright IBM Corporation 2009
All Rights Reserved.
IBM, IBM (logo), and DB2 are trademarks or registered
trademarks of International Business Machines Corporation
in the United States, other countries, or both.
Linux is a registered trademark of Linus Torvalds in the
United States, other countries, or both.
UNIX is a registered trademark of The Open Group in the
United States, other countries, or both
Windows is a trademark of Microsoft Corporation in the
United States, other countries, or both.
Other company, product, or service names may be
trademarks or service marks of others.
References in this publication to IBM products or services
do not imply that IBM intends to make them available in all
countries in which IBM operates. The following paragraph
does not apply to the United Kingdom or any other country
where such provisions are inconsistent with local law:
Information concerning non-IBM products was obtained
from the suppliers of those products, their published
announcements or other publicly available sources. IBM has
not tested those products and cannot confirm the accuracy
of performance, compatibility or any other claims related to
non-IBM products. Questions on the capabilities of non-IBM
products should be addressed to the suppliers of those
products.
The information in this publication is provided AS IS without
warranty. Such information was obtained from publicly
available sources, is current as of January 2009, and is
subject to change. Any performance data included in the
paper was obtained in the specific operating environment
and is provided as an illustration. Performance in other
operating environments may vary. More specific information
about the capabilities of products described should be
obtained from the suppliers of those products.
INTERNATIONAL BUSINESS MACHINES CORPORATION
PROVIDES THIS PUBLICATION "AS IS" WITHOUT
WARRANTY OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE.
Some states do not allow disclaimer of express or implied
warranties in certain transactions, therefore, this statement
may not apply to you.
This information could include technical inaccuracies or
typographical errors. Changes are periodically made to the
information herein; these changes will be incorporated in
new editions of the publication. IBM may make
improvements and/or changes in the product(s) and/or the
program(s) described in this publication at any time without
notice.
Any performance data contained herein was determined in a
controlled environment. Therefore, the results obtained in
other operating environments may vary significantly. Some
measurements may have been made on development-level
systems and there is no guarantee that these
measurements will be the same on generally available
systems. Furthermore, some measurement may have been
estimated through extrapolation. Actual results may vary.
Users of this document should verify the applicable data for
their specific environment.
97