Escolar Documentos
Profissional Documentos
Cultura Documentos
Prepared By:
Business Partner Technical Enablement Competitive Technologies and Enablement IBM Data Servers, IBM Software Group June 2012
Version 1.6
Trademarks
IBM, AIX, DB2, DB2 Universal Database, Informix, and iSeries are trademarks of the International Business Machines Corporation in the United States, other countries or both. UNIX and Unixbased trademarks and logos are trademarks or registered trademarks of The Open Group. Intel and Intel-based trademarks and logos are trademarks or registered trademarks of Intel Corporation. Windows is a trademark of Microsoft Corporation in the United States, and other countries, or both. Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other company, product or service names may be the trademarks or service marks of others.
Disclaimer
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: 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. The use of this information or the implementation of any of these techniques is your responsibility and depends on your ability to evaluate and integrate them into your operational environment. While each item may have been reviewed by IBM for accuracy in a specific situation, there is no guarantee that the same or similar results will be obtained elsewhere. Customers attempting to adapt these techniques to their own environments do so at their own risk. 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. 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 nonIBM products. Questions on the capabilities of non-IBM products should be addressed to the suppliers of those products. The information in this white paper is provided AS IS without warranty. Such information was obtained from publicly available sources, is current as of December 2011, 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.
Version 1.6
Document History
Revision History
Authoring
Original Document (May 2000) Glen Black, Frank Martino & Tim Tobey Informix Software Incorporated, Partner Engineering Organization Revisions for Informix Dynamic Server.2000, Version 6 (July 2000) Tim Tobey Informix Software Incorporated, Partner Engineering Organization Updated to IBM Informix Dynamic Server Database Version 9, Release 4. (February 2004) Christine Normile Informix Dynamic Server Product Manager IBM Software Group, Information Management Updated material for Sequence Objects (December 2004) Sam Marino DB2 Business Partner Technical Enablement IBM Information Management Solutions, IBM Software Group Updated to IBM Informix Dynamic Server Database Version 10.00 (January 2006) Sam Marino Business Partner Technical Enablement Data Services IBM Information Management, IBM Software Group Updated to IBM Informix Dynamic Server Database Version 11.10 (December 2007) Sam Marino IBM Business Partner Technical Enablement Data Services IBM Information Management, IBM Software Group Updated material for delimited identifiers, metadata extraction, type conversion, and miscellaneous (June 2012) Chris Golledge IBM Information Management, IBM Software Group
Contributions
Technical Reviewers
Keshava Murthy IBM Informix Database Server Development IBM Software Group, Information Management Lakshman Sakaray IBM Database Migration Toolkit IBM Software Group, Information Management
Version 1.6
Table of Contents
CHAPTER 1: INTRODUCTION ............................................................................................ 8
PURPOSE ........................................................................................................................................ 8 PRODUCT OVERVIEW ....................................................................................................................... 8 ORGANIZATION................................................................................................................................ 8 CONVENTIONS ................................................................................................................................ 9 CHAPTER 2: DEFINING THE PROBLEM SPACE ............................................................ 11
EXTRACTING THE OBJECTS TO BE MIGRATED .................................................................................. 11 Working With Oracle Dump Files ............................................................................................ 11 CHAPTER 3: DATA DEFINITION LANGUAGE ................................................................. 15
IDENTIFIERS .................................................................................................................................. 15 Delimited identifiers ................................................................................................................. 15 Explicit versus implicit schema/owner names ......................................................................... 17 Reserved words or keywords .................................................................................................. 18 Summary ................................................................................................................................. 19 DATABASES .................................................................................................................................. 19 Databases, database names and instances ........................................................................... 19 ANSI vs. non-ANSI .................................................................................................................. 20 TABLESPACES AND DBSPACES ....................................................................................................... 20 TABLES......................................................................................................................................... 21 Attributes and general syntax .................................................................................................. 21 Lock mode ............................................................................................................................... 21 Storage .................................................................................................................................... 21 Constraints .............................................................................................................................. 22 ALTER TABLE......................................................................................................................... 22 Data Partitioning ...................................................................................................................... 23 DATA TYPES.................................................................................................................................. 25 Numeric ................................................................................................................................... 25 CHAR, VARCHAR and LVARCHAR ....................................................................................... 26 Date and Time ......................................................................................................................... 27 Interval ..................................................................................................................................... 27 Raw data and Large Objects ................................................................................................... 28 ROWID .................................................................................................................................... 28 User-defined types .................................................................................................................. 29 Complex data types ................................................................................................................. 30 SEQUENCE OBJECTS ..................................................................................................................... 30 Oracle sequences.................................................................................................................... 30 Informix sequences ................................................................................................................. 30 INDEXES ....................................................................................................................................... 30 Composite indexes .................................................................................................................. 30 Maximum key size ................................................................................................................... 31 Index fragmentation ................................................................................................................. 31 General index information ....................................................................................................... 31 VIEWS .......................................................................................................................................... 32 STORED PROCEDURES AND TRIGGERS ........................................................................................... 32 ORACLE EXTENSIONS .................................................................................................................... 33 CHAPTER 4: DATA MANIPULATION LANGUAGE .......................................................... 34
SQL ............................................................................................................................................. 34 Labels using keywords ............................................................................................................ 34 Inequality operations ............................................................................................................... 34 Selects ..................................................................................................................................... 34 Optimizer directives ................................................................................................................. 34
Version 1.6
External optimizer directives .................................................................................................... 35 Inserts ...................................................................................................................................... 36 Temporary tables..................................................................................................................... 36 Outer joins ............................................................................................................................... 36 Sorts ........................................................................................................................................ 36 Exceptions ............................................................................................................................... 37 Correlation names ................................................................................................................... 37 Aliases ..................................................................................................................................... 37 Hierarchical queries ................................................................................................................. 37 Truncate .................................................................................................................................. 39 HOST VARIABLES........................................................................................................................... 40 DATE AND TIME FUNCTIONS ........................................................................................................... 41 SYSDATE ................................................................................................................................ 41 Number formats ....................................................................................................................... 41 Date formats ............................................................................................................................ 42 The RR date format element ................................................................................................... 43 USER-DEFINED ROUTINES .............................................................................................................. 43 COMPATIBLE SQL FUNCTIONS ....................................................................................................... 43 AGGREGATE FUNCTIONS ................................................................................................................ 43 MATHEMATICAL FUNCTIONS ........................................................................................................... 44 STRING FUNCTIONS ....................................................................................................................... 44 LENGTH .................................................................................................................................. 44 LTRIM and RTRIM .................................................................................................................. 44 Oracle Extensions ................................................................................................................... 44 OTHER ORACLE FUNCTIONS .......................................................................................................... 44 MACROS ....................................................................................................................................... 45 %ISOPEN and %NOT FOUND ............................................................................................... 45 %ROWTYPE ........................................................................................................................... 45 %TYPE .................................................................................................................................... 45 PSEUDO-COLUMNS ........................................................................................................................ 45 LEVEL ..................................................................................................................................... 46 ROWID .................................................................................................................................... 46 ROWNUM................................................................................................................................ 46 UPDATE USING CURSORS............................................................................................................... 49 SYSTEM TABLES ............................................................................................................................ 50 STORED PROCEDURES .................................................................................................................. 50 Size limit .................................................................................................................................. 50 Parameter limit ........................................................................................................................ 50 Packages ................................................................................................................................. 51 Routines .................................................................................................................................. 51 Exceptions ............................................................................................................................... 51 Error handling .......................................................................................................................... 52 Cursors .................................................................................................................................... 52 Variable declaration and assignment ...................................................................................... 53 Boolean ................................................................................................................................... 53 Binary data types ..................................................................................................................... 53 Dynamic SQL .......................................................................................................................... 53 Compiler .................................................................................................................................. 53 TRIGGERS..................................................................................................................................... 54 CONSTRAINTS ............................................................................................................................... 55 DUAL TABLE................................................................................................................................. 55 CHAPTER 5: EMBEDDED SQL......................................................................................... 57
HOST VARIABLES ........................................................................................................................... 57 Declaration override ................................................................................................................ 57 Arrays ...................................................................................................................................... 57 Formatting ............................................................................................................................... 58 SQL STRUCTURES ........................................................................................................................ 59
Version 1.6
SQLCA .................................................................................................................................... 59 SQLDA .................................................................................................................................... 60 ORACA .................................................................................................................................... 61 PRE-COMPILER OPTIONS................................................................................................................ 61 EMBEDDED PL/SQL ...................................................................................................................... 61 ORACLE CALL INTERFACE .............................................................................................................. 61 Database library calls .............................................................................................................. 62 Global area processing............................................................................................................ 62 Fetch cycle .............................................................................................................................. 62 RAW binary data type processing ........................................................................................... 62 Parameter bindings ................................................................................................................. 62 EMBEDDED SQL FOR C ................................................................................................................. 63 VARCHAR ............................................................................................................................... 63 Host variables .......................................................................................................................... 63 EMBEDDED SQL FOR COBOL ....................................................................................................... 63 VARCHAR ............................................................................................................................... 63 Level 88 ................................................................................................................................... 64 SQLDA .................................................................................................................................... 64 REDEFINES ............................................................................................................................ 64 Tips .......................................................................................................................................... 64 ODBC .......................................................................................................................................... 64 CHAPTER 6: APPLICATION ARCHITECTURE ................................................................ 65
TRANSACTION PROCESSING ........................................................................................................... 65 Autonomous Transaction......................................................................................................... 66 Savepoints ............................................................................................................................... 67 CONCURRENCY ............................................................................................................................. 67 Row Level Locking .................................................................................................................. 67 Transaction Isolation Level ...................................................................................................... 68 CHAPTER 7: SECURITY ................................................................................................... 70
USER AUTHENTICATION ................................................................................................................. 70 Operating system security ....................................................................................................... 70 Non-operating system security ................................................................................................ 70 ROLE BASED AUTHORITY ............................................................................................................... 71 COLUMN-LEVEL ENCRYPTION ......................................................................................................... 71 Passwords and hints ............................................................................................................... 71 Encrypting a column ................................................................................................................ 72 Querying an encrypted column................................................................................................ 72 Performance impact of encryption ........................................................................................... 73 Storage considerations ............................................................................................................ 73 Compliance regulations ........................................................................................................... 73 CHAPTER 8: ENVIRONMENT ........................................................................................... 74
SCRIPTS ....................................................................................................................................... 74 SQL script substitution variables ............................................................................................. 74 UTILITIES ...................................................................................................................................... 75 SYSTEM CATALOG ......................................................................................................................... 75 CHAPTER 9: USING BLADELETS .................................................................................... 76
W HAT IS A BLADELET? .................................................................................................................. 76 INFORMIX EXEC BLADELET FOR DYNAMIC SQL ............................................................................... 77 SQLLIB DATABLADE MODULE (SQLLIBC.1.1 / SQLLIBJ.1.1) ............................................................ 78 A P P E N D I X A: A P P E N D I X B: PLANNING GUIDE ..................................................................................... 79 SYNTAX COMPARISON ............................................................................ 82
Version 1.6
A P P E N D I X C: A P P E N D I X D:
DATE ARITHMETIC ......................................................................................................................... 88 UNITS Keyword ....................................................................................................................... 88 Using EXTEND function .......................................................................................................... 88 STRING REPRESENTATION OF DATE AND TIME ................................................................................. 88 Day and date ........................................................................................................................... 88 Abbreviation of day of week .................................................................................................... 88 USING AN INFORMIX COLLECTION DATA TYPE .................................................................................. 89 A collection data type as a VARRAY ....................................................................................... 89 Using MULTISET and ROW to replace PL/SQL TABLE and RECORD types ........................ 91 A P P E N D I X E: COUNTING SYSTEM OBJECTS ............................................................... 93
USING THE SYSTEM CATALOG ........................................................................................................ 93 System catalog ........................................................................................................................ 93 USING SQL CODE ......................................................................................................................... 94 Built-in function references ...................................................................................................... 94 Object types and counts .......................................................................................................... 95 A P P E N D I X F: DATA TYPE MAPPING .............................................................................. 97
DOUBLE ................................................................................................................................ 101 VARCHAR ............................................................................................................................. 101 NUMBER ............................................................................................................................... 101 National language types ........................................................................................................ 102 ROWID .................................................................................................................................. 102 %TYPE .................................................................................................................................. 102 %ROWTYPE ......................................................................................................................... 102 FLOAT ................................................................................................................................... 102 XMLType ............................................................................................................................... 103
Version 1.6
CHAPTER 1:
Introduction
This document is a technical document describing the differences between Oracle and Informix Dynamic Server (IDS) functionality and syntax. . This porting guide details differences between Oracles 10g release 1 (10.1) and 10g release 2 (10.2) and Informix Dynamic Server (version 11.10). In addition, it can be a useful reference for all migrations between the two database servers regardless of version. In addition to DDL, DML and overall SQL syntax, this document explores the differences between Oracle and Informix with regards to object technology through the use of large objects, user defined types, and user defined routines. It also looks at the differences between Oracles table partitioning and Informixs table fragmentation. Part of the explanation is a discussion on what needs to be changed to make an application running on an Oracle database run on an Informix database. If there is more than one way to port some piece of functionality, alternatives and recommendations are also discussed. This document is intended to be a living document. Missing items, better ways of implementing Oracle functionality in Informix other than what is documented here, examples to better illustrate a point, and other suggestions should be sent to Chris Golledge (golledge@us.ibm.com) so they may be included with future revisions.
Purpose
This document should be used as a guide to assist in porting applications that run on an Oracle database server to run on an Informix database server. 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 most 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 aid in the porting effort by addressing the technical issues. This document will be refined based on users experiences to identify as many of the porting issues as possible at the beginning of a project.
Product overview
IBM Informix Server provides high performance and scalability with legendary reliability and nearly hands-free administration of databases of all size. IDS is industry proven on UNIX, Linux, or Windows platforms with online transaction processing (OLTP) systems, data marts, data warehouses, and e-business applications. The IDS 11 release features significant additions over prior versions. It supports the servicesoriented architecture (SOA) model for application integration and offers many new features for data replication, continuous availability and hands free database administration.
Organization
This document is broken into sections to logically discuss the different database concepts. Some of the sections may contain the same sub-sections; for example, stored procedures and triggers
Version 1.6
are discussed in the DDL and DML sections. This allows separate discussions on the issues facing the same item in each area. 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. Among the other references, the Planning Guide appendix contains a quick reference of most of the differences between Oracle and Informix along with the degree of difficulty to port each difference. This reference is intended for use in the planning process to illustrate the scope and the effort required to perform the porting project. Some of the stored procedure logic used to convert Oracle functions is included in the appendix Sample code.
Conventions
The conventions used in this document include: Courier Text Distinguishes a logic example from regular text. Example Illustrates a point. In most cases an Oracle example will be followed by an Informix example. Italicized Text Signifies a substitution; in other words, substitutes for the italicized word, the actual object the word is describing, for example: table_name, column_name, and so on. Signifies database vendor reserved words or statements such as INTEGER, CREATE TABLE, and so on highlights the item that is being explained.
Version 1.6
Version 1.6
10
CHAPTER 2:
Space
It is important to define the set of objects to be migrated, and it is better if effort is put into this prior to beginning the actual migration. This is true if you are the responsible for both the database in general and its migration from one supporting DBMS to another, but it is particularly true that there be a clear agreement on the scope of what is to be migrated if the migration is to be performed by a party other than the one with long term responsibility for the database. Defining the scope will involve extracting a representation of the objects to be migrated out of the Oracle system catalogs and representing them in some format that can be manipulated into constructs that can be used in Informix.
Version 1.6
11
It may be tempting to feed the dump file into the IBM Migration Toolkit (MTK) or other tool that works on SQL flat files. This will not work. MTK works on flat text SQL files, and the dump file is binary. If you open it up, you can see what may be a large number of SQL statements, but there are also binary codes within the same file. That binary data will prevent MTK from being able to process it. Getting SQL statements If you want to get the SQL statements out of the dump file, as they would be executed on the server, there is an option available from the import tool itself, 'show=y'. imp 'myID/myPWD as sysdba' file=myFile.dmp full=yes show=y > dmp_show.txt This will produce a file which contains the statements, but they are wrapped in quotes. The contents will look something like:
"ALTER SESSION SET CURRENT_SCHEMA= "SYSTEM"" "CREATE UNDO TABLESPACE "TBSPC1" BLOCKSIZE 8192 DATAFILE 'D:\ORACLE\ORADA" "TA\SCHEMA1\CHUNK.DBF' SIZE 387973120 AUTOEXTEND ON NEXT 5242880 MAXS" "IZE 32767M EXTENT MANAGEMENT LOCAL "
which makes them strings instead of SQL statements. Fixing this is a two-step process -- removes quotes from the start of lines sed 's/^ "//g' dmp_show.txt > step1.txt -- removes quotes from the end of lines sed 's/"$//g' step1.txt > dmp_step2.sql The statements are still not correctly formatted because they have been truncated to a fixed length and line-endings inserted. However, at this point it is possible to get a count of how many of each object type there is using the script in the appendix Getting an initial count of database objects.
Data Pump Export and Import These newer tools provide better performance and more capabilities than their predecessors. Please refer to documentation on Oracle for a complete description; searches for Data Pump Import and Data Pump Export should return relevant results quickly. Below is enough information to get started on defining and extracting the objects to be migrated. Metadata can be filtered through the use of the export mode clause, and INCLUDE and EXCLUDE parameters. However, any dependent object of an included or excluded object is likewise included or excluded. For example, if you include an index, then the table associated with the index will also be included, and if you exclude a table, then any associated indexes will also be excluded. The SQL that will generate all the objects in the dump file can be created by the impdp command with the SQLFILE parameter. If the output file is very large, you might want to break it into smaller pieces. There are a couple of ways to do this, and the one that is best for you somewhat depends
Version 1.6
12
on how you intend to proceed with the conversion. Data definition language (DDL) SQL for all the objects can be put into one file, or the INCLUDE or EXCLUDE parameters can be added to direct Data Pump to filter on the types of objects. If you put all the objects into one file, then you can break that into smaller files by object type fairly easily because the objects are sorted by type in the SQL file. So, it is just a matter of cutting the file into smaller pieces. This method may be preferred because it allows for you to do things like, create all tables, load the data, and then create the indexes and triggers. If the data set is large, creating the indexes after loading the data can yield substantial performance improvements. However, this is less useful if you want to convert sets of objects according to dependencies; in which case the filtering option is likely to be more useful. Just to illustrate a difference between these two methods, in one customer case, the metadata dump file was about 18MB, and putting all objects in one SQL file resulted in a file that was about 15MB. The table definitions occupied a little under 300KB of the 15MB. The output file generated by filtering on objects of type TABLE was just over 1MB. The addition content was mostly GRANT, INDEX, and TRIGGER creation statements. There were no differences in the CREATE TABLE statements themselves. Examples Prerequisite The Data Pump tools require the use of an Oracle DIRECTORY object. This is basically a mapping between a name that exists within the DBMS and a system path. It can be a tripping point, but it provides an abstraction layer that, for instance, allows the same commands to work across systems with different disk layouts or different operating systems. Creating a DIRECTORY on a Windows system from SQLPlus: SQL>connect / as sysdba; SQL>CREATE OR REPLACE DIRECTORY dumpDir AS 'c:\temp'; Note: Make sure this directory is not read-only. There also could be problems if the directory is a network drive on Windows; these can be related to there being different users between the Oracle executable and the current user, and those users having different permissions on the network drive. SQL>GRANT read, write ON DIRECTORY dumpDir TO userID; Creating a dump file of the entire database: expdp 'userName/userPwd as sysdba' FULL=Y dumpfile=DB_full.dmp LOGFILE=LG_expdp.log CONTENT=METADATA_ONLY DIRECTORY=dumpDir Creating a dump file of just one schema: expdp 'userName/userPwd as sysdba' SCHEMAS=hr DIRECTORY=dumpDir DUMPFILE=hr .dmp LOGFILE=hr .log CONTENT=METADATA_ONLY Creating a dump of just the tables and their dependents: expdp 'userName/userPwd as sysdba' SCHEMAS=hr INCLUDE=TABLE DIRECTORY=dumpDir DUMPFILE=hr.dmp LOGFILE=hr.log CONTENT=METADATA_ONLY Creating a dump of just one table: expdp 'userName/userPwd as sysdba' SCHEMAS=hr INCLUDE=TABLE:\"LIKE \'COUNTRIES\'\" DIRECTORY=dumpDir DUMPFILE=hr.dmp LOGFILE=hr.log CONTENT=METADATA_ONLY
Version 1.6
13
Creatinge an SQL file from a dump file: impdp 'userName/userPwd as sysdba' DIRECTORY=dumpDir DUMPFILE=hr.dmp SQLFILE=dumpDir:hr.sql
The INCLUDE and EXCLUDE options are also valid when used with impdb; so, it may be easier to get a complete dump of everything to be migrated, then use these options to create subsets of objects it smaller SQL files, than it would be to create separate dump files. It is easier to divide objects than to merge them together if they are not divided initially as wanted. There is a caveat when using this impdp to generate an SQL file; the object names will all be delimited identifiers. Example: CREATE TABLE "HR"."COUNTRIES"... Because of differences between how Informix handles these and how Oracle handles these, case-sensitivity issues could occur. See the chapter on Delimited Identifiers, and, in particular, the description of default shift problems. If it can be determined that there are no name collisions if regular identifiers are used, removing the quotation marks as part of the conversion might avoid many problems. In other words, if there are no objects whose names only differ in case, like foo and FOO, then changing every occurrence of FOO to FOO in the DDL could eliminate case sensitivity issues in the application DML. It depends on if the application code uses the delimited form of the name predominantly or not.
Version 1.6
14
Identifiers
An identifier specifies the simple name of a database object such as a table name, column name, index name, view name, stored procedure name, and so on. The maximum length of an Oracle identifier is 30 characters and can contain letters, numbers, _, $, and #, although Oracle highly recommends that $ and # should not be used. In contrast, Informix identifiers have a maximum length of 128 characters and may contain letters, numbers, _ and $ (as long as $ is not the first character). See the Delimited Identifiers section below for information. This means that all Oracle identifiers containing a # anywhere in the identifier or a $ as the first character must be replaced or modified to remove those characters from the identifier.
Delimited identifiers
Delimited identifiers are also known as quoted identifiers and sometimes as escaped identifiers. They have been part of the SQL standard since SQL/92, but existed in various database management systems (DBMS) prior to that time. In a nutshell, they are a way to preserve case sensitivity in object names as well as to allow objects to have names outside of the conventions of SQL regular identifiers. Prior to the behavior of identifiers in general being standardized, different DBMS vendors implemented different means of achieving case-insensitivity for object names; some converted all regular identifiers to uppercase, and some converted regular identifiers to lowercase. By SQL/99 the concept of case normal form was standardized to mean, simply stated, that if there exists an uppercase equivalent of any character in a name, then the uppercase version is stored in the system catalogs and used for comparison purposes. See the SQL/99 standard, chapter 5, section 2, and in particular, items 21 and 22, for a formal description of case normal form and how it applies to identifier comparisons. Delimited identifiers can be used to specify names for database objects that are otherwise identical to SQL reserved keywords, such as TABLE, WHERE, DECLARE, and so on. The only database object for which delimited identifiers cannot be used is a database name. Database administrators and application programmers do not always communicate to each other with 100% efficiency, and there is no guarantee that within either of these pools, every member codes by the standard practice of the other members. After describing how delimited identifiers work in Informix, there will be a description of how any inconsistency of usage and the differences between Oracle and Informix can introduce some migration hurdles. DELIMIDENT Environment Variable To use delimited identifiers with Informix, you must set the DELIMIDENT environment variable. While DELIMIDENT is set , strings enclosed in quotation marks ( ) are treated as identifiers of database objects, and strings enclosed in apostrophes ( ) are treated as literal strings. If the
Version 1.6
15
DELIMIDENT environment variable is not set, strings enclosed in quotation marks are also treated as literal strings. When you set the DELIMIDENT environment variable, you cannot use quotation marks ( ) to delimit literal strings. If DELIMIDENT is set, the database server interprets all strings enclosed in quotation marks as SQL identifiers, not string literals. Commonly within Informix systems, DELIMIDENT is set or not on the client side, according to the design of the application. However, if you are converting a database and all applications accessing it from a system where every occurrence of quotation marks (objectName) indicates an identifier and not a string literal, you may want to consider setting it in the server environment in order to avoid any inconsistency between clients where it is set and where it might not be. Using Quotes in Strings The apostrophe ( ) has no special significance in string literals delimited by quotation marks. Conversely, double quote ( ) has no special significance in strings delimited by apostrophes. For example, these strings are valid: "Nancys puppy jumped the fence" Billy told his kitten, "No!" A string delimited by quotation marks can include a double quote character by preceding it with another double quote, as the following string shows: "Enter ""y"" to select this row." When the DELIMIDENT environment variable is set, quotation marks can only delimit identifiers, not strings. Use of Uppercase Characters You can specify the name of a database object with uppercase characters, but the Informix server shifts these to lowercase characters unless the DELIMIDENT environment variable is set and the name of the database object is enclosed in quotation marks. In this case, the database server treats the name of the database object as a delimited identifier and preserves the uppercase characters in the name. Delimited Identifiers By default, the character set of a valid SQL identifier is restricted to letters, digits, underscore, and dollar-sign symbols. If you set the DELIMIDENT environment variable, however, SQL identifiers can also include additional characters from the codeset implied by the setting of the DB_LOCALE environment variable. See the Identifier section of the Informix Guide to SQL: Syntax for more information. Storage Object Names In Informix, delimited identifiers can be used to specify nonalphanumeric characters in the names of database objects. However, delimited identifiers can not be used to specify non-alpha characters in the names of storage objects such as dbspaces and blobspaces. To use delimited identifiers, DELIMIDENT must be set both at compile and run times. For example, to set DELIMIDENT environment variable with sh or ksh, issue the following at the command line prompt: export DELIMIDENT= Note: You do not need to assign a value to the environment variable, and counter-intuitively, setting DELIMIDENT=n has the same effect as DELIMIDENT=y. Also, in a Windows environment: set DELIMIDENT= effectively undefines the variable. Default shift problems Any direct access of system catalog information involving names will cause problems when migrating from a system, like Oracle, where system catalog names are stored in uppercase to a system, like Informix, where the catalog names are stored in lowercase. For example: CREATE TABLE foo (c1 int);
Version 1.6
16
Within Oracle, the following will return information about the table: select * from sys.all_objects where object_name = 'FOO'; and the following will not: select * from sys.all_objects where object_name = 'foo'; Conversely, in Informix: select * from systables where tabname = 'foo'; will be successful, and the same with 'FOO' will not be. A similar, if not more common, problem can occur when the table has been created without the name being delimited, but is sometimes delimited when accessed by the application. Per the standard, foo == FOO == FOO, but in Informix, foo == FOO == foo. In Oracle, the following SELECT statement will be successful: SELECT * FROM FOO; but within Informix, this will result in an error, 206: The specified table (FOO) is not in the database. Likewise, if the name is delimited in its definition, such as CREATE TABLE "SCHEMA1"."TABLE1"... this creates a table that can be referenced in Oracle without the name being delimited. The statements SELECT * FROM schema1.table1; and SELECT * FROM SCHEMA1.TABLE1;
will be successful in the Oracle system, but will fail in the Informix one. In theory, whether on object name is delimited or not should be the same in the database and at every occurrence within the application, but this is not always the case. It may be beneficial to examine whether delimited identifiers or regular identifiers are most commonly used in application code, and use whichever is most common as a naming convention when translating the DDL.
Version 1.6
17
select * from SCOTT.foo1; select * from foo2; select * from scott.foo2; select * from SCOTT.foo2; select * from foo3; select * from scott.foo3; select * from SCOTT.foo3; These statements will also run without error within a non-ANSI mode Informix database, but not all of them will run successfully within an ANSI mode database. This is because Informix does not uniformly fold the case of owner names, and handles implicit names differently from explicit names; so, there will always be some combination of DDL and DML usage patterns that work within an Oracle system that do not work in an Informix one. You can set ANSIOWNER before starting your Informix server, but that will merely change which combinations do not work. You may want to examine usage patterns within the applications and choose a naming convention when translating the DDL that matches the most common naming convention used in the applications. Note: This behavior of Informix forces a tradeoff between using an ANSI mode database, which most closely matches the transaction behavior of Oracle, and a non-ANSI mode database, which has the least mismatch in identifier case sensitivity.
Version 1.6
18
The following example shows how to create a table that uses a keyword as the table name: CREATE TABLE "TABLE" () To include a double-quote (") within a delimited identifier, the double-quote (") must be preceded with another double-quote ("), as shown in the following example: CREATE TABLE "My""Good""Data" ()
Summary
The main points to keep in mind when deciding about any questions on how identifiers should be translated are: Oracle always has delimited identifiers enabled, and Informix does not. Oracle folds regular identifiers to uppercase, and Informix folds to lowercase. Informix has behavioral differences between an ANSI mode database and a non-ANSI mode one.
It is beneficial to consider the most common usage patterns within the existing application code prior to deciding default identifier translation patterns.
Databases
Databases, database names and instances
Oracle and Informix implement databases and instances differently. Oracle considers a database to be a set of data files, control file(s) and log files, while an instance is a set of background processes and memory structures accessing database data. Oracle instances are also known as servers. Each Oracle instance or server runs against one database, but through the use of Oracle Parallel Server, a database may have multiple instances accessing it. An Oracle database is named at initialization and the name has a limit of 8 ASCII characters. Informix databases are defined as a collection of information contained in tables that are useful to a particular organization or used for a specific purpose. Informix database names may be up to 128 characters in length. An Informix instance is a set of processes, memory and disk allocations that manage data and will contain at least two and in most cases many databases. Informix instances are also referred to as servers. Informix databases may share disk allocations (dbspaces) with other databases within an Informix instance. Oracle databases cannot share disk allocations (tablespaces). Informix databases should be created in a dbspace other than the root dbspace. The root dbspace holds data for the system, configuration information for the engine, and so on. If userdefined objects are created in this dbspace, then the dbspace may become unmanageably large, and during backup, the system information may also get backed up unnecessarily. The CREATE DATABASE statements of Informix and Oracle have differences which may require modification to routines responsible for database creation. Informix will accept the same minimal syntax required by Oracle (e.g. CREATE DATABASE myDB) however issuing the command will implicitly accept the creation of a database without transaction logging enabled and establish the default location for all database objects as the instances default storage location. The instances default storage location, or root dbspace, should not contain user-defined objects. The root dbspace holds data for the system and some configuration information for the engine. If user-
Version 1.6
19
defined objects are created in this dbspace it may become unmanageable and result in the system contending with user objects for the available space.
If an Informix ESQL/C or 4GL application was developed to run on a non-ANSI Informix database (including BEGIN WORK statements), the application could run on an ANSI Informix database in one of two ways: By placing the BEGIN WORK statement in a pre-processor directive, such as IFDEF object_name, and omitting the proper preprocessor compile options, such as -D object_name By compiling the application normally and ignoring the resulting warning messages
Additionally, the LOG MODE ANSI clause must be added to the CREATE DATABASE statements. ANSI mode databases cannot have buffered logging. Applications written to use an open API, like ODBC or JDBC, are compiled without awareness of the database and these APIs are written with the intent to abstract specific database behavior. For instance, in one of these, the application developer would call a function to begin or end a transaction rather than execute a BEGIN and COMMIT or ROLLBACK. The API would execute these statements internally, or not, as necessary for the database connection. See the Transaction Processing section in Application Architecture for more information on how an application running on a non-ANSI Informix database can simulate Oracle transaction behavior.
Version 1.6
20
Tables
Attributes and general syntax
When creating tables, the Oracle CREATE TABLE statement must be converted to Informix, taking advantage of the Informix options IN, EXTENT, NEXT, and LOCK MODE. IN specifies the dbspace in which the table will reside. EXTENT specifies the amount of space that will initially be allocated to the table (16K default on most platforms). NEXT specifies the amount of space that will be allocated when additional space is needed (16K default on most platforms.
Lock mode
LOCK MODE specifies whether to use row or page locks for the table. In Oracle, the default is row level locking; in Informix the default setting is page level locking. However it can be changed by using one of the following methods: (resolved in the following order of precedence) 1. LOCK MODE specified using an attribute of the CREATE TABLE or ALTER TABLE command syntax 2. IFX_DEF_TABLE_LOCKMODE environment variable setting 3. DEF_TABLE_LOCKMODE parameter setting in the ONCONFIG file NOTE: If the DEF_TABLE_LOCKMODE parameter cannot be found in the ONCONFIG file it can be added to make the specification for every database within the instance. The Informix instance must be restarted for this parameter to take effect. The new default LOCK MODE will apply to all tables created after the parameter has been changed. To change the LOCK MODE of existing objects use the ALTER TABLE statement.
Storage
The Oracle STORAGE INITIAL and STORAGE NEXT clauses must be changed to the Informix EXTENT SIZE and NEXT SIZE clauses, respectively. In Oracle the STORAGE clause options MINEXTENTS, MAXEXTENTS and PCTINCREASE should be removed. For example: Oracle: CREATE TABLE dept( deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13) ) STORAGE (INITIAL 100K NEXT 50K MINEXTENTS 1 MAXEXTENTS 50 PCTINCREASE 5);
Informix: CREATE TABLE dept ( deptno SMALLINT, dname VARCHAR(14), loc VARCHAR(13) );
Version 1.6
21
When an Oracle CREATE TABLE statement does not include a STORAGE clause, the table will be created using the tablespace STORAGE clause by default. If an Oracle tablespace is created specifying a STORAGE INITIAL of 100KB and a STORAGE NEXT of 50KB, then all tables created within that tablespace will have a default value of STORAGE INITIAL 100KB and STORAGE NEXT 50KB. Oracle tables cannot be created with smaller STORAGE clause values than the tablespace default they are created in. Informix dbspaces do not have storage clauses attached to them. As stated earlier, the default Informix EXTENT and NEXT sizes are 16KB on most platforms. The minimum EXTENT and NEXT sizes are 4 times the page size.
Constraints
The Oracle constraint syntax must be changed to the Informix syntax for primary keys, foreign keys, unique, and so on. For example: Oracle: CONSTRAINT PK_NUMBER PRIMARY KEY(CUST_NUM) CONSTRAINT CK_EMP_CODE CHECK (EMP_CODE > 100) Informix: PRIMARY KEY(CUST_NUM) CONSTRAINT PK_NUMBER CHECK (EMP_CODE > 100) CONSTRAINT CK_EMP_CODE An Oracle check constraint statement may contain functions that are not available in Informix. In this circumstance it may be necessary to code the combination of a trigger and a stored procedure to emulate the same functionality. A trigger based on an insert or update event can execute a stored procedure which tests the constraint condition and if necessary raise an exception to reject the row data which violates the constraint. The Oracle PARALLEL clause, which specifies parallel execution of an operation, must be removed from any SQL statements (such as CREATE TABLE and ALTER TABLE). In Informix there are ways to accomplish this parallel execution depending on the context in which these SQL statements are called (shell script file, batch file, and so on.).
ALTER TABLE
Informix offers a rich set of ALTER TABLE features: adding and dropping columns (rename by using the RENAME statement), changing column data types, altering the next size, and changing the lock mode. Informix will choose one of three algorithms when executing an ALTER TABLE statement depending upon the operation to be performed. For certain conditions, the database server uses either a slow, in-place" or fast alter algorithm to modify the table. Informix provides in-place alter table support for adding or dropping a column anywhere in the table, changing the column length, and changing the column data type without an exclusive lock on the table. An in-place alter will modify the tables definition without changing the existing rows or unloading and reloading the data. After the ALTER TABLE operation, the database server inserts rows using the latest definition. Informix will not change the row structure until a data row is touched by a user operation. Once a query accesses a row that is not yet converted, there can be a slight degradation in the performance because the database server reformats each row in memory before it is returned. Informix uses the slow alter algorithm when the ALTER TABLE statement makes column changes that it cannot perform in place. This type of alter would be: Adding or drop a column created with the ROWIDS keyword Dropping a column of the TEXT or BYTE data type
Version 1.6
22
Converting an INT or a SMALLINT column to SERIAL or SERIAL8 Modifying the data type of a column so that some possible values of the old data type cannot be converted to the new data type For example, if you modify a column of data type INTEGER to CHAR(n), the database server uses the slow ALTER algorithm if the value of n is less than 11. An INTEGER requires 10 characters plus one for the minus sign for the lowest possible negative values.
Modifying the data type of a fragmentation column in a way that value conversion might cause rows to move to another fragment Adding, dropping or modifying any column when the table contains user-defined data types or smart large objects
When the database server uses the slow alter algorithm to process an ALTER TABLE statement, the table can be unavailable to other users for a long period of time because the database server will lock the table exclusively for the duration of the operation, make a copy of the table to convert the table to the new definition and convert the data rows. This type of ALTER TABLE processing can encounter the scenario of a statement being a long transaction and abort it if the Long Transaction High Water Mark (LTXHWM) threshold is exceeded. Informix will use the fast alter algorithm when the ALTER TABLE statement changes attributes of the table but does not affect the data. The database server uses the fast alter algorithm when you use the ALTER TABLE statement to make the following changes:
Change the next-extent size Add or drop a constraint Change the lock mode of the table Change the unique index attribute without modifying the column type
With the fast alter algorithm, the database server holds a lock on the table for a very brief period. In some cases, the database server will lock the system catalog tables but only long enough to change the attribute. In either case, the table is unavailable for queries for only a short time.
Data Partitioning
Informix Table Fragmentation is the counterpart to Oracles Table Partitioning and allows the user to control where data is physically placed at the table level. Table Fragmentation or Data Partitioning is typically done to large tables, but Informix and Oracle implement fragmentation and partitioning for different reasons and with different results. Informix recommends using table fragmentation to improve single-user response time, concurrency, data availability, backup / restore characteristics, and data-load performance. While Oracle does state that table partitioning may improve the performance of queries, and that the Oracle optimizer takes partitioning into account, the primary goal of partitioning in Oracle is improving database maintenance. Partitioning strategies in Oracle include range partitioning as well as hash and composite partitioning. Composite partitioning combines range and hash partitions through the use of subpartitions. Tables incorporating Oracle LOBs (large objects) cannot be partitioned. Informix fragmentation strategies include expression-based and round robin. Basic expressionbased fragmentation can replace Oracle range partitioning. Unlike Oracle LOBs, Informixs Smart Large Objects can be fragmented. Examples of creating tables with Oracle range partitioning and Informix fragmentation by expression are shown below: Oracle range partitioning: CREATE TABLE dept
Version 1.6
23
IBM Software Group ( deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13) ) partition by range (deptno) (partition PART1 values less than tablespace PART1_TS, partition PART2 values less than tablespace PART2_TS, partition PART3 values less than tablespace PART3_TS, partition PART4 values less than tablespace PART4_TS); Informix expression based fragmentation:
CREATE TABLE dept( deptno SMALLINT, dname VARCHAR(14), loc VARCHAR(13) ) FRAGMENT BY EXPRESSION deptno < 11 IN dbspace1, deptno >= 11 AND deptno < 21 IN dbspace2, deptno >= 21 AND deptno < 31 IN dbspace3, REMAINDER IN dbspace4; Oracle uses MAXVALUE for values not found in the specified range while Informix uses the REMAINDER keyword for values that fall outside the specified expression or expressions. Prior to IDS version 10.00, each table fragment had to go into a separate dbspace. Now tables can be fragmented within a single dbspace. You can create partitions within a dbspace that can each support a table fragment. It is better to have one chunk per disk drive, and now it is not necessary to create a dbspace just to facilitate fragmentation. This feature can simplify the management of dbspaces. The benefits gained through this new development include: It reduces the total number of dbspaces needed for a fragmented table. Storing multiple table fragments in a single dbspace improves query performance over storing each fragmented expression in a different dbspace.
For example, Informix partition fragmention in a single dbspace: CREATE TABLE dept( deptno SMALLINT, dname VARCHAR(14), loc VARCHAR(13) ) FRAGMENT BY EXPRESSION PARTITION part1 PARTITION part2 PARTITION part3 PARTITION part4
Partitions of an Informix fragmented table can be manipulated using the ALTER FRAGMENT statement which supports attaching, detaching, adding, modifying, and dropping, as well as initializing the distribution strategy.
Version 1.6
24
For example, the following SQL removes a partition fragment and places the contents into a new table: ALTER FRAGMENT ON TABLE dept DETACH PARTITION part3 dept_part3; Making use of ALTER FRAGMENT to detach fragments can be an effective way of deleting large quantities of rows from a table, quickly and easily. After the above statement completes, the table will no longer contain rows with a deptno greater than 21 and less than 31. Refer to the Informix Guide to SQL: Syntax for a complete description on how to use the ALTER FRAGMENT statement to change the distribution strategy or the storage location of an existing table or index.
Data types
Numeric
Oracles NUMBER data type needs to be replaced with one of the following Informix equivalent data types, depending on the size of the column. The Informix numeric data types are listed below. SMALLINT (-32,767 to 32,767) INTEGER (-2,147,483,647 to 2,147,483,647) BIGINT (-9,223,372,036,854,775,807 to 9,223,372,036,854,775,807) INT8 (-9,223,372,036,854,775,807 to 9,223,372,036,854,775,807) The BIGINT type is more efficient in terms of space and speed; there are few reasons to use INT8 now that BIGINT is available. DECIMAL (floating point up to 32 significant digits -10
-130
to 10
124
In an ANSI database, there is an implied scale of 0 when no scale is given; so, this is not strictly speaking a floating point type within an ANSI database. NUMERIC (floating point up to 32 significant digits -10 to 10 FLOAT (double precision, like double data type of C) SMALLFLOAT (single precision, like float data type of C) REAL (same as SMALLFLOAT) DOUBLE (same as FLOAT) LONG (same as long data type of C)
-130 124
Oracles NUMBER data type is used to store zero, positive and negative fixed size, and floating -130 125 point numbers with magnitudes between 1.0 x 10 and 9.9...9 x 10 (38 9s followed by 88 0s) with 38 digits of precision. A fixed-point number is specified by NUMBER(p, s) where p is the precision, or the total number of digits, and s is the scale, or the number of digits to the right of the decimal point. For example, a column defined as NUMBER(10,4) would contain numbers in the format 999999.9999. In Oracle, the scale can range from -84 to 127. If the scale is 0, or not mentioned, then the data type can be converted into Informixs SMALLINT, INTEGER, or BIGINT depending on the precision, or FLOAT, SMALLFLOAT, DOUBLE or REAL, depending on usage in the application. When the scale is positive, the data type should be converted to Informixs DECIMAL or NUMERIC. A floating-point data type in Oracle is declared using the type NUMBER without mentioning scale and precision. In Informix this can be replaced with FLOAT, SMALLFLOAT, REAL, DOUBLE PRECISION, or DECIMAL(p) in an non-ANSI database.
Version 1.6
25
Oracle allows a negative scale. If the scale is negative, the actual data is rounded to the specified number of places to the left of the decimal point. For example, a specification of NUMBER (10, -2) means to round to the hundred. If the general form for any number is: mantissa X 10
exponent
then precision is the number of digits in the mantissa, and scale is the negative exponent. Example: select cast( '987654321' AS NUMBER(10,-2) ) from dual; returns 987654300 Informix does not support a negative scale. If precision - scale is less than the maximum precision of an integer type, then that is the most efficient type to use. Failing that, and if the database is non-ANSI, a floating point DECIMAL can be used. If that is not sufficient, then it may be necessary to define a user type and associated functions. Oracle also allows the scale to be greater than the precision. Precision is just the number of digits that will be preserved. A NUMBER(3, 5) might have the value 0.00123. If the Oracle scale is less than the Informix maximum precision, then the Oracle scale can be used for both the Informix precision and scale. A NUMERIC(5,5) column could also store the value 0.00123. You may need to take into consideration not only the minimum and maximum values but the default size for data types. For example, when the size of the NUMBER data type is absent, Oracle will default to NUMBER(38), while Informix defaults to NUMERIC(16). Oracle and Informix support the ANSI DECIMAL data type. Therefore, in the case of an ANSI data type, the Oracle data type can be converted to the same Informix data type. There are differences between conversions based on theory versus those based on practice. For instance, it is very common to see an undecorated NUMBER declaration where the customer database and applications are using integer data. When converting NUMBER declarations, it may be necessary to consider how the data is being used in order to determine the best type mapping.
Version 1.6
26
Empty Oracle VARCHAR2 strings are considered NULL. Empty Informix VARCHAR and LVARCHAR strings are not considered NULL; rather, they contain at least one space. Oracle compares VARCHAR2 values using non-padded comparison semantics. Therefore, BOB BOB . Informix ignores trailing blanks. Therefore, BOB = BOB or = . Hence, checks for NULL within the application must be replaced with checks for an empty string (such as or ) whenever an empty string is inserted into the column. If NULL is truly inserted into the column, checking for NULL is appropriate (for example, SELECT * FROM WHERE IS NULL). In Oracle, LONG columns store variable length character strings containing up to 2 gigabytes, or 31 2 -1 bytes. Informix LONG columns store numeric data. Oracles LONG columns have many of the characteristics of VARCHAR2 columns. They can be used in a SELECT list, in the SET clause of an UPDATE statement, and in an INSERT statement, but they cannot be used in a WHERE clause, a GROUP BY clause, or an ORDER BY clause, and they cannot be indexed. Oracles LONG columns should be converted to an Informix Smart Large Object or SLOB (BLOB, CLOB) column.
Interval
Within Informix there are two classes of interval types, YEAR-MONTH and DAY-FRACTION. There are different numbers if days in different months; so, the MONTH-DAY boundary cannot be crossed without creating ill-defined results. Within each of these classes, Informix allows you to declare columns or variables as any subset of the start and end fields. Oracle has one INTERVAL
Version 1.6
27
type for each of the two classes, YEAR(p) TO MONTH and DAY(p) TO SECOND(s). The Oracle scale on the SECOND field is logically equivalent to the Informix scale on the FRACTION field.
ROWID
The implementation of ROWID differs between Oracle and Informix. Oracles ROWID is both a pseudo-column and a data type. See the ROWID subsection in the Pseudo-Columns section in CHAPTER 3: Data Manipulation Language for more information. Informix implements ROWID as a pseudo-column only. Oracle stores the ROWID column and ROWID data type column values in hexadecimal format. Informix stores the ROWID column values in INTEGER format. The Oracle and Informix engines maintain the values of the ROWID pseudo-column. Oracles engine does not maintain the values of other columns of type ROWID. In Informix, the term rowid refers to an integer that defines the physical location of a row. Informix assigns rows in a non-fragmented table a unique rowid, which allows applications access to a particular row in a table. Rows in fragmented tables, in contrast, are not assigned a rowid. To access data by rowid in a fragmented table, a rowid column must be explicitly created as is described in the Informix Guide to SQL: Reference manual Creating a Rowid Column. If applications attempt to reference a rowid in a fragmented table that does not contain a rowid that was explicitly created, Informix displays an appropriate error message and execution of the application is halted.
Version 1.6
28
When used as a data type for a column, Oracle does not guarantee that the values are valid ROWIDs. For example, if the ROWID is used as a data type on a column, such as a column in a child table named parent_rowid containing the ROWID of the parent, then the values are maintained by the application, outside of the engine. The application must read the ROWID of the parent and insert it into the parents corresponding child table rows. This is usually done so the two tables can be joined on the parents ROWID and the childs parent_rowid column. This functionality can be duplicated in Informix by using primary and foreign keys. Informix recommends that primary keys are used as a method of access in applications rather than rowids, because primary keys are defined in the ANSI specification of SQL, using them to access data makes applications more portable. Refer to the Informix Guide to SQL: Reference and the Informix Guide to SQL: Syntax for a complete description on how to define and use primary keys to access data.
User-defined types
Both Oracle and Informix allow the user to create and define data types. Oracle refers to these as abstract data types while Informix refers to these as user-defined types. In Oracle, all userdefined types are referred to as abstract data types while Informix may refer to user-defined types as COLLECTION types, ROW types, DISTINCT types and OPAQUE types. Currently, the Informix ROW type is closest in form and function to the Oracle abstract data type. An example of syntax for creating both an Oracle abstract data type and an Informix ROW type is shown below: Oracle abstract data type: CREATE TYPE name_type AS OBJECT (first_name VARCHAR2(25), middle_initial CHAR(1), last_name VARCHAR2(30)); Informix row type: CREATE ROW TYPE name_type (first_name VARCHAR(25), middle_initial CHAR(1), last_name VARCHAR(30)); Both Oracle and Informix support the use of user-defined types for table definition or column definition within a table. Building on the example above, the following create table example show a table definition and column definition within a table based on user-defined types: Oracle table creation: CREATE TABLE name OF name_type; Informix table creation: CREATE TABLE name OF type name_type; Oracle column definition: CREATE TABLE employee (empno name Informix column definition: CREATE TABLE employee NUMBER(9), name_type);
Version 1.6
29
For more information on User Defined Types, see the Informix Guide to SQL: Syntax.
Sequence objects
Oracle sequences
An Oracle sequence is a database object from which multiple users, or transactions, may generate unique integers. For example, sequences can be used to automatically generate primary key values. When a sequence object is queried, the sequence number is incremented and passed to the query, independent of the transaction committing or rolling back. If two applications increment the same sequence, the sequence numbers each application acquires may not be sequential since sequence numbers are being generated by the other application. One user, or transaction, can never acquire the sequence number generated by another user, or transaction. Once a user or transaction generates a sequence value, that value will never be generated and passed to another user or transaction.
Informix sequences
Informix s implementation of sequence objects is identical to that of Oracle. Issues regarding syntax compatibility should be negligible with the exception of some keywords which have no effect on the behavior of the sequence. Informix supports DML statements (CREATE SEQUENCE, ALTER SEQUENCE, RENAME SEQUENCE, DROP SEQUENCE) for sequence objects that multiple users can access concurrently to generate unique integers in the 8-byte integer range. GRANT and REVOKE statements support access privileges on sequence objects, and the CREATE SYNONYM and DROP SYNONYM statements can be used to reference synonyms for sequence objects in the local database. The operators, CURRVAL and NEXTVAL, can read or increment the value of an existing synonym with behavior the same as Oracle.
Indexes
Composite indexes
A composite index can have up to 16 key parts that are columns, or up to 341 key parts that are values returned by a UDR. This limit is language-dependent, and applies to UDRs written in SPL or Java; functional indexes based on C language UDRs can have up to 102 key parts. A composite index can have any of the following items as an index key: One or more columns
Version 1.6
30
One or move values that is returned by a user-defined function (referred to as a functional index) A combination of columns and user-defined functions
In addition to aiding the porting process, wider indexes have satisfied requirements for Unicode data as well as provide performance gains by reducing B-Tree index traversal costs since indexing can be built with more items on an index page and produce fewer levels.
Index fragmentation
Just as Oracle and Informix support table fragmentation, or partitioning in Oracle, both support index fragmentation as well. See the Table fragmentation section above for more information regarding Informix table fragmentation and Oracle table partitioning. Oracle indexes that are partitioned in the same manner as the table they are indexing are referred to as local indexes. Informix refers to these as attached indexes. Oracle indexes that span partitions are known as global indexes. Informix refers to these as detached indexes. Informix detached indexes may also refer to indexes that do not follow the same fragmentation scheme as the table they are indexing. Starting with Informix version 11.10, indexes can be fragmented similarly to tables, on a partition level.
Version 1.6
31
compactness. A low value provides room for growth in the index. A high value compacts the index. If an index is fully compacted (100 percent), any new inserts result in splitting nodes. The setting on the CREATE INDEX statement overrides the ONCONFIG file value. The FILLFACTOR default value for both the CREATE INDEX statement as well as the ONCONFIG is 90. Informix has no support for bitmap indexes.
Views
Oracles CREATE VIEW statement contains three options; FORCE, NO FORCE and WITH READ ONLY. FORCE creates the view regardless of whether the view's base tables exist or the owner of the schema containing the view has privileges on them. NO FORCE creates the view only if the base tables exist and the owner of the schema containing the view has privileges on them. WITH READ ONLY specifies that no deletes, inserts, or updates can be performed through the view. These options must be removed from the Informix CREATE VIEW statements. Because a view is not really a table, it cannot be indexed, and it cannot be the object of such statements as ALTER TABLE and RENAME TABLE. The columns of a view cannot be renamed with RENAME COLUMN. To change anything about the definition of a view, you must drop the view and re-create it. Because it must be merged with the users query, the SELECT statement on which a view is based cannot contain any of the following clauses:
INTO TEMP
The users query might contain INTO TEMP; if the view also contains it, the data would not know where to go. The users query might contain UNION. No meaning has been defined for nested UNION clauses. The users query might contain ORDER BY. If the view also contains it, the choice of columns or sort directions could be in conflict.
UNION
ORDER BY
Version 1.6
32
IBM Software Group DROP PROCEDURE IF EXISTS CREATE PROCEDURE are logically the same as this Oracle statement: CREATE OR REPLACE PROCEDURE
So, it is possible to achieve the same result, but not necessarily the same number of statements.
Oracle extensions
The Oracle CLUSTER option in CREATE statements should be removed. These are not to be confused with Informix CLUSTER index statements (See Indexes section above). An Oracle cluster is a database schema object that contains one or more tables that all have one or more columns in common. Rows of one or more tables that share the same value in these common columns are physically stored together within the database. Removing this Oracle feature will not affect the application. Other non-Informix DDL statements like CREATE DATAFILE, CREATE CONTROLFILE, CREATE ROLLBACK SEGMENT, CREATE SNAPSHOT, CREATE DATABASE and CREATE DATABASE LINK must be removed or changed (in the case of the CREATE DATABASE statement). The Oracle CREATE PROFILE statement must be removed. An Oracle profile is a set of limits on database resources. Profiles can be used to limit the database resources available to a user for a single SQL statement or a single session.
Version 1.6
33
SQL
Labels using keywords
Oracle displays labels in SQL statements that are Informix reserved words, such as UNITS, YEAR, MONTH, DAY, HOUR, and so on, must be converted by using the Informix AS clause between the column name and the display label. Otherwise, syntactic ambiguities will cause errors.
Inequality operations
In addition to the Informix supported not equal to symbols <> and !=, Oracle supports the symbol ^=. All occurrences of ^= must be replaced with one of the Informix supported symbols.
Selects
Queries are executed based on how the optimizer determines the best path to the data. Oracle and Informix developed their own query optimizers, with their proprietary methods and rules. A query that looks exactly the same in both environments may run differently in each, following a different path and executing faster or slower. Therefore, every query in the ported application should be tested for performance, regardless of whether a query had to be converted. Furthermore, Oracle supports optimizer hints within a SELECT statement. Prior to IDS 7.3 and Informix Dynamic Server 9.2, Informix did not allow optimizer hints. See the Optimizer Directives subsection below for more information on porting Oracles optimizer hints to Informixs optimizer directives.
Optimizer directives
Informix offers optimizer directives similar to Oracles optimizer hints. This feature provides the query developer the flexibility to direct the optimizer to follow specific paths, rather than choosing a plan through its analysis. A query is processed in two steps. First it is optimized and compiled to product a query plan. Secondly, it is executed to produce a result. Optimizer directives are a method for influencing the choice of the optimizer in the creation of the plan.
Version 1.6
34
Optimizer directives address the following key issues: Reduced time for correcting performance problems. Rewriting queries can be very time consuming, and this allows you to have a quick way to alter a plan. Competitive pressure. Users accustomed to this function were looking for it in Informix. Product development tuning. This allows product development to alter plans dynamically rather than through code changes to evaluate the effect of different optimization techniques.
The syntax and behavior of Informixs implementation is compatible with Oracles optimizer hints, which eases the porting of applications from Oracle to Informix. Directives are written as a comment whose first character is a + (plus sign) . An example is: select {+ ORDERED AVOID_FULL(e)} empname, deptno from employee e, department d where e.dept_no = d.dept_no; This above example specifies that the tables should be joined in the order specified in the query and that the employee table (e) should NOT be accessed with a full table scan. The Informix implementation differentiates itself significantly from Oracles in one way. Informix supports the notion of negative directives whereas Oracle only supports direct hints. A directive that tells the optimizer what to avoid, rather than what to choose, is unique to Informix. The query result can be realized by writing a directive to avoid certain actions known to cause performance issues, but allow any new indexes or table attributes to be explored by the optimizer as they are added over the life of the table and query. This allows a DBA to continue to add indexes to tables and not have to rewrite directives. Additionally, Informix supports full recognition of directives with SET EXPLAIN output. Informix will highlight semantic and syntactic errors, which Oracle does not. Optimizer directives support control in the following areas of the optimization process: Access methods: Index versus scans Join Methods: Forcing hash joins, nested loop joins Join Order: Specify which order the tables are joined Goal: Specify first rows or all rows (response time versus throughput)
See the Informix Guide to SQL: Syntax or Reference for more information.
Version 1.6
35
These directives are applied automatically to subsequent instances of the same query. You must include one of the ACTIVE, INACTIVE, or TEST ONLY keyword options to enable, disable, or restrict the scope of external directives. When external directives are enabled and the sysdirectives system catalog table is not empty, the database server compares every query with the query text of every ACTIVE external directive, and for queries executed by the DBA or user informix, with every TEST ONLY external directive. External directives are ignored if the EXT_DIRECTIVES parameter is set to 0 in the ONCONFIG file. In addition, the client system can disable this feature for its current session by setting the IFX_EXTDIRECTIVES environment variable to 0. If an external directive has been applied to a query, output from the SET EXPLAIN statement indicates EXTERNAL DIRECTIVES IN EFFECT for that query. Any inline directive is ignored by the optimizer when the external directives are applied to a query that matches the SELECT statement. Like inline optimizer directives that are embedded within a query, external directives can improve performance in some queries for which the default behavior of the query optimizer is not satisfactory. Unlike inline directives, external directives can be applied without revising or recompiling existing applications.
Inserts
Informix does not support Oracles INSERT with SELECT statement utilizing an UNION clause (although a view with an UNION clause can be referenced, resulting in an UNION operation). Additionally, Informix does not support an INSERT statement with a VALUE clause with SELECT statements. The SELECT statement within a VALUE clause can be rewritten by omitting the VALUE clause and performing an INSERT INTO table_name SELECT FROM other_table_name.
Temporary tables
Informix and Oracle implemented the concept of temporary tables differently. Oracle implements temporary tables as a work area during batch data loads. Informix implements temporary tables just like regular database tables. These temporary tables can be created, manipulated, and dropped only within a session, such as stored procedures and ESQL programs. Once the session ends, any remaining temporary tables are automatically dropped. Temporary tables can give an application extra functionality; however, their use should be limited if reducing database extensions to increase database independence within an application is a priority.
Outer joins
Both Oracle (starting with Oracle 9i) and Informix support ANSI standard syntax for outer join specification. The syntax for left and right outer join using the plus sign (+) in the WHERE clause is only supported for backward compatibility however it is still in existence. The use of ANSI outer join syntax is recommended. The Oracle outer join syntax + (placed after the column which has values not matching the corresponding column in the joined table) can be replaced with the Informix equivalent, OUTER. The OUTER keyword is placed within the SELECT statement before the name of the subservient table. Unlike Oracle, in Informix multiple outer joins per SELECT statement are allowed, grouped with parentheses.
Sorts
In Oracle sorts, NULL values are considered the highest value and are therefore ordered last in ascending sorts. Informix sorts with NULLS as the lowest value, ordering them first in ascending sorts. First, it must be determined whether this sorting difference will affect the outcome enough to warrant a work around. In most cases it will not. If it does, then a stored procedure can be
Version 1.6
36
written to evaluate whether a column is NULL and if so, replace it with a high value so that it will sort last. Once the application receives the results, it must replace the high values with NULL if the column is going to be displayed, or manipulated.
Exceptions
Error handling using hard coded Oracle SQL codes must be replaced with the corresponding Informix SQL codes.
Correlation names
Informix does not support correlation names with aliases on the main table of an UPDATE or DELETE statement. Such cases must be converted. For example: Oracle: UPDATE customer C SET zip_code = 92612 WHERE zip_code IN (SELECT zip_code FROM zip_table Z WHERE C.create_date <= Z.effective_date) Informix: UPDATE customer SET zip_code = 92612 WHERE zip_code IN (SELECT zip_code FROM zip_table Z WHERE customer.create_date <= Z.effective_date) -andOracle: DELETE customer C WHERE order_date <= (SELECT control_value FROM control_table T WHERE T.control_field = archive_date AND C.state = T.state ) Informix: DELETE customer WHERE order_date <= (SELECT control_value FROM control_table T WHERE T.control_field = archive_date AND customer.state = T.state ) Note that Informix allows correlation names with aliases on tables other than the updated or deleted table.
Aliases
Unlike Oracle, in Informix, if an alias is used in the FROM clause of a SELECT statement, it must also be used in the SELECT list and WHERE clauses. The original table name should be replaced with the alias wherever aliases and original names are used together within a SELECT statement in an Oracle application.
Hierarchical queries
Informix does not allow query results to be organized hierarchically in a B-tree fashion. Oracle does allow it by using the clauses START WITH and CONNECT BY PRIOR in the SQL
Version 1.6
37
statement. In Oracle, if a table contains hierarchical data, a bill of materials for example, rows can be selected in a hierarchical order using the following clauses. START WITH The START WITH clause identifies the row(s) to be used as the root(s) of a hierarchical query. This clause specifies a condition that the root(s) must satisfy. If this clause is omitted, Oracle uses all rows in the table as root rows. A START WITH condition can contain a subquery. CONNECT BY The CONNECT BY clause specifies the relationship between parent and child rows in a hierarchical query. This clause contains a condition that defines this relationship. The part of the condition containing the PRIOR operator must have one of the following forms: PRIOR expression comparison_operator expression -orexpression comparison_operator PRIOR expression To find the children of a parent row, Oracle first evaluates the PRIOR expression to identify the parent row(s) and the other expression for each row in the table. Rows for which the other expression is true are the children of the parent. The CONNECT BY clause can contain other conditions to further filter the rows selected by the query. WHERE The WHERE clause can restrict the rows returned by the query without affecting other rows of the hierarchy. Oracle uses the information from each of the clauses mentioned above to form the hierarchy using the following steps. 1. Oracle selects the root row(s) of the hierarchy. These are the rows that satisfy the condition of the START WITH clause. 2. Oracle selects the child rows of each root row. Each child row must satisfy the condition of the CONNECT BY clause with respect to one of the root rows. 3. Oracle selects successive generations of child rows. Oracle first selects the children of the rows returned in step 2, and then the children of those children, and so on. Oracle always selects children by evaluating the CONNECT BY condition with respect to a current parent row. 4. If the query contains a WHERE clause, Oracle removes all rows from the hierarchy that do not satisfy the condition of the WHERE clause. Oracle evaluates the WHERE condition for each row individually, after the row has been fetched, rather than only fetching rows that satisfy the WHERE condition. 5. Oracle returns the rows in the order of an in-order, or left-root-right, binary tree traversal.
Version 1.6
38
For example, the following SQL statement returns the data in the adjacent table in hierarchical order. The root row is defined to be the employee whose job is PRESIDENT. The child rows of a parent row are defined to be those rows whose manager number is the employee number of the parent row. SELECT ename, empno, mgr, job FROM emp START WITH job = PRESIDENT CONNECT BY PRIOR empno = mgr ENAME KING JONES SCOTT ADAMS FORD SMITH BLAKE ALLEN WARD MARTIN TURNER JAMES CLARK MILLER EMPNO 7839 7566 7788 7876 7902 7369 7698 7499 7521 7654 7844 7900 7782 7934 MGR 7839 7566 7788 7566 7902 7839 7698 7698 7698 7698 7698 7839 7782 JOB PRESIDENT MANAGER ANALYST CLERK ANALYST CLERK MANAGER SALESMAN SALESMAN SALESMAN SALESMAN CLERK MANAGER CLERK
To duplicate this hierarchical functionality in Informix, stored procedures or functions can be written requiring intensive use of cursors and program arrays. Informix offers the choice of creating and using a User Defined Routine or UDR. See User Defined Routines section below. Use of Informix global arrays will help considerably. To maximize read processing at the expense of insert processing, another method is to break the table into two tables, one containing the data and the other containing the relationship (foreign keys) between each parent and child. A parent row would have an entry in the relationship table for each of its children, grandchildren, great grandchildren, and so on. The opposite is true, where a child row would have an entry in the relationship table for its parent, grandparent, great grandparent, and so on.
Truncate
Informix supports the TRUNCATE statement for deleting all active data rows from a table and associated indexes. When using Informixs TRUNCATE, you also have the option of releasing the storage space that was occupied by the rows and index extents or keeping the space allocated to be used as the table is repopulated with new data. TRUNCATE [TABLE] table [ [ DROP | REUSE ] STORAGE ]; You may use the commands simplest usage: TRUNCATE my_table; In the example above, the TRUNCATE statement drops all the data for the table and keeps only the initial extents. There is a minor difference from Oracle syntax as Informix does not require the keyword TABLE. Another example: TRUNCATE my_table REUSE STORAGE;
Version 1.6
39
This example drops all the data for the table but retains all the space allocated. The permissions needed for TRUNCATE TABLE depend on the existence of DELETE triggers on the table. For tables with DELETE triggers, ALTER permission on the table is required and RESOURCE or DBA privileges because the DELETE triggers will be bypassed. For tables without DELETE triggers, you need DELETE permission on the table and CONNECT privilege to the database. While Oracle does not provide rollback, Informix does permit TRUNCATE TABLE to execute within a transaction. When you rollback a TRUNCATE statement, no rows are removed from the table, and the storage extents that hold the data rows and index pages continue to be allocated to the table. In a database that supports transaction logging, only the COMMIT WORK or ROLLBACK WORK statement is valid after the TRUNCATE statement within a transaction. Any other statement will generate an error. The TRUNCATE statement does not reset the serial value of SERIAL or SERIAL8 columns. To reset the counter of a serial column, you must do so explicitly by using the MODIFY clause of the ALTER TABLE statement, either before or after you execute the TRUNCATE statement. After the TRUNCATE statement successfully executes, Informix automatically updates the statistics and distributions for the table and for its indexes in the system catalog to show no rows in the table nor in its dbspace partitions. It is not necessary to run the UPDATE STATISTICS statement immediately after you commit the TRUNCATE statement.
Host variables
Host variable formats should not change during the porting process. Instead, data types should be converted in a manner to preserve the column and host variables formats. However, there are times when the database schema changes in a way where the host variable format must change. Any column converted to a different format in Informix than that of Oracle requires that its corresponding host variable format be changed to be consistent. Alternatively, if an Oracle format, such as date and numeric variables, is not directly supported in Informix, then the conversion may require some format processing before or after the SQL statement. For example, the Oracle function TO_CHAR is used to format both date and numerical values. A similar function, or at least two functions, one to handle date data types and another to handle numeric data types, can be declared and used in the Informix application. Informix provides two built-in functions: TO_DATE which converts a character string to a DATETIME variable and TO_CHAR which converts a DATETIME variable to a character string. . When converting variables, an optional formatting string is allowed which determines how the string is displayed (full day names, partial day names, full months, month number, and so on). There is also a function, ifx_to_gl_datetime(), which takes an Oracle date format and returns the corresponding Informix date format. This function is supplied in genlib and is for use in ESQL programs to ease migration efforts from Oracle. The syntax is as follows: TO_CHAR (source_date, fmt) Returns a character string, containing the date specified in source_date, in the format specified by fmt if one is provided. If fmt is missing, the function will use the default date format (as specified by the client environment variables). Note, fmt must be an Informix format and does not necessarily include all possible Oracle date formats.
TO_DATE (source_string, fmt) Evaluates source_string as a date according to the format fmt. If fmt is missing, the function will use the
Version 1.6
40
default format (as specified by the client environment variables). Note, fmt must be an Informix format and does not necessarily include all possible Oracle date formats. These functions are mainly useful for simplifying migration from Oracle to Informix, but are also useful for performing advanced searches on DATETIME data types and for better output presentation.
SYSDATE
IDS 11.10 will support the SYSDATE operator which returns a single value representing the current date and time from the operating system clock. SYSDATE is identical to the Informixs CURRENT operator, except that the default precision of SYSDATE is YEAR TO FRACTION(5), while the default precision of CURRENT is YEAR TO FRACTION(3). On Windows platforms that do not support a seconds scale greater than FRACTION(3), SYSDATE is effectively a synonym for the CURRENT operator, In addition to SYSDATE, Informix version 11.10 has support for Oracles date functions ADD_MONTHS(date,months), LAST_DAY(date), MONTHS_BETWEEN(date1, date2), NEXT_DAY(date,char), ROUND(date,format), SYSDATE, and TRUNC(date,format). Depending on the whether or not the Oracle date_format argument is supported by Informix, TO_CHAR(date, char_format) and TO_DATE(character_string, date_format) may have to be converted to Informix date processing. Date processing may be required because the Oracle application may format the date in many different ways, unsupported by Informix. The formats used in the Oracle functions TO_CHAR, TO_NUMBER and TO_DATE are illustrated below. These formats should be replaced with Informix formats wherever possible, format processing functions, or stored procedures written to duplicate the Oracle functionality. Refer to the appropriate Informix API Programmers Manual (Informix-ESQL/C Programmers Manual or Informix-ESQL/COBOL Programmers Manual) for more information.
Number formats
Element 9 Example 9999 Description Return value with the specified number of digits with a leading space if positive. Return value with the specified number of digits with a leading minus if negative. Leading zeros are blank, except for a zero value, which returns a zero for the integer part of the fixed-point number. Return leading zeros. Return trailing zeros. Return value with a leading dollar sign. Return blanks for the integer part of a fixed-point number when the integer part is zero (suppress leading zeros regardless of whether zeros are used in the format model i.e. B00999 ). Return negative value with a trailing minus sign -. Return positive value with a trailing blank. Return negative value with a leading minus sign -. Return
0 $ B
MI S
9999MI S9999999
Version 1.6
41
Element
Example S 9999PR 99D99 9G999 C999 L999 9,999 99.99 999V99 9.9EEEE RN FM90.9
PR D G C L , . V EEEE RNrn FM
Description positive value with a leading plus sign +. Return negative value with a trailing minus sign -. Return positive value with a trailing plus sign +. Return negative value in <angle brackets>. Return positive value with a leading and trailing blank. Return a decimal point . In the specified position. Return a group separator in the specified position. Return the ISO currency symbol in the specified position. Return the local currency symbol in the specified position. Return a comma in the specified position. Return a decimal point . In the specified position. n Return a value multiplied by 10 (and if necessary, round it up), where n is the number of 9s after the V. Return a value in scientific notation. Return a value as Roman numerals in uppercase. Return a value as Roman numerals in lowercase. Value can be an integer between 1 and 3999. Return a value with no leading or trailing blanks.
Date formats
Element -/,.;:text AD or A.D. AM or A.M. BC or B.C. CC or SCC D DAY DD DDD DY IW IYY or IY or I IYYY HH or HH12 HH24 J MI MM MONTH MON RM Q RR WW W PM or P.M. SS SSSSS Y/YYY YEAR or SYEAR YYYY or SYYYY Meaning Punctuation and quoted text is reproduced in the result. AD indicator with or without periods. Meridian indicator with or without periods. BC indicator with or without periods. Century; S prefixes BC dates with -. Day of week (1-7). Name of day, padded with blanks to length of 9 characters. Day of month (1-31). Day of year (1-366). Abbreviated name of day. Week of year (1-52 or 1-53) based on the ISO standard. Last 3, 2, or 1 digit(s) of ISO year. 4-digit year based on the ISO standard. Hour of day (1-12). Hour of day (0-23). Julian day; the number of days since January 1, 4712 BC. Number specified with J must be integers. Minute (0-59). Month (01-12; JAN = 01) Name of month, padded with blanks to length of 9 characters. Abbreviated name of month. Roman numeral month (I-XII; JAN = I). Quarter of year (1, 2, 3, 4; JAN-MAR = 1) Last 2 digits of year; see below for years in other centuries. Week of year (1-53) where week 1 starts on the first day of the year and continues to the seventh day of the year. Week of month (1-5) where week 1 starts on the first day of the month and ends on the seventh. Meridian indicator with and without periods. Second (0-59). Seconds past midnight (0-86399). Year with comma in the / position. Year spelled out; S prefixes BC dates with -. 4-digit year; S prefixes BC dates with -.
Version 1.6
42
YYY or YY or Y
User-defined routines
User-defined data types, user defined behaviors and user defined access methods add rich functionality to Informix. A user-defined routine (UDR) can be developed in C, Java, or Informix SPL language, to vastly extend the capabilities of the database. Porting applications to Informix gives the option to create UDRs for aggregate and mathematical functions or to emulate Oracle built-in functions and reduce the impact of replacing all references throughout the application. Or, you can rename an Informix function to the corresponding Oracle function name.
These functions are documented with examples in the IBM Informix Guide to SQL: Syntax.
Aggregate functions
Like Oracle, the result returned by an Informix aggregate function is NULL if all of the column values are NULL, with the exception of COUNT which returns 0 (zero). Like Oracle, Informix aggregate functions cannot be used in a WHERE clause unless it is on a corresponding column originating from a parent query and the WHERE clause is within a subquery that is within a HAVING clause, or the aggregate function is contained within a sub-query. Unlike Oracle, in Informix the argument of an aggregate function cannot be another aggregate function. Informix supports the SELECT COUNT (column_name) statement, where the number of rows containing non-null values in the specified column is returned.
Version 1.6
43
The Oracle aggregate functions STDDEV and VARIANCE are supported, however the Informix standard deviation routine is named STDEV thus all references to Oracles STDDEV must be changed to match Informixs STDEV. Informix does not support Oracles greatest lower boundary (GLB ) or least upper boundary (LUB). Therefore, UDRs must be written to provide equivalent functionality. Informix allows users to define their own aggregate functions known as user-defined aggregates (UDA). This extension of existing aggregates can be used for new data types as well as the definition of new aggregates. In Informix, TEXT and BYTE columns cannot be used in aggregate functions such as COUNT, AVG, MAX, MIN and SUM.
Mathematical functions
Informix does not support all of Oracles mathematical functions such as SIGN, COSH, SINH, and TANH. Therefore, functions or UDRs must be written in the Informix application to provide equivalent functionality. In Informix, the rounding factor within the ROUND function must be a value from -32 to 32. This limitation has seldom been encountered as a migration issue.
String functions
LENGTH
Oracles LENGTH function will return different values than Informix for strings stored in CHAR data types. The numeric return value representing the string length returned by Oracle will include all trailing spaces. Whereas Informixs LENGTH function will ignore trailing blanks regardless of data type. For example, for the two CHAR strings BOB and BOB Oracles LENGTH function will return different values for each string, 3 and 5 respectively. Whereas Informixs LENGTH function will ignore trailing blanks and return the value 3 for both. When the input string is NULL, both database functions will return a NULL.
Oracle Extensions
Informix does not support all of Oracles string functions such as CHR, INSTR, SOUNDEX, and TRANSLATE. Therefore, corresponding user-defined routines or UDRs (i.e. functions or stored procedures) must be written in the Informix application to provide equivalent functionality. Please note that the VERITY and EXCALIBUR Datablades included with Informix will work with Oracles string function SOUNDEX.
Version 1.6
44
HEXTORAW LEAST LEAST_UB RAWTOHEX ROWIDTOCHAR TO_LABEL TO_MULTI_BYTE TO_SINGLE_BYTE UID USERENV(OSDBA/ LABEL/ LANGUAGE/ TERMINAL/ SESSIONID/ ENTRYID) VSIZE
Macros
Oracle contains macros, sometimes referred to as language constructs, which can determine the status of an object. Informix does not support Oracles macros. These macros must be removed from the code, and the associated logic should be implemented with equivalent Informix logic, where applicable.
%ROWTYPE
The Oracle macro prefix%ROWTYPE is used in the declarative section as a data type to declare variables, similar to the structure construct of C or RECORD of INFORMIX. The prefix can be either a table name or another structure name. Structure names ultimately refer back to a table name. This macro may be replaced with the Informix statement LIKE table_name.*. The construct LIKE table_name.* cannot be used in SPL. Instead, the construct DEFINE column1 LIKE table_name.column1; DEFINE column2 LIKE table_name.column2; and so on, should be used to declare variables corresponding to all the columns of the table. Then operations on the whole or part of the structure should be replaced with operations on single SPL variables.
%TYPE
The Oracle macro prefix%TYPE is used in the declarative section as a data type to declare single variables. The prefix is either a table_name.column_name or a structure_name.variable_name. A structure_name.variable_name ultimately refers back to a table_name.column_name. This macro can be replaced with the Informix statement LIKE table_name.column_name.
Pseudo-columns
Pseudo-columns are columns that exist in tables but are not displayed from a SELECT * FROM table_name query. Informix pseudo-columns are generally reserved for the engines use. Eliminating the use of such columns increases an applications portability and eliminates the need for future modifications if the engine is ever modified to process the column differently or not at all.
Version 1.6
45
LEVEL
In Oracle, for each row returned by a hierarchical query, the pseudo-column LEVEL returns 1 for a root node, 2 for a child of a root, 3 for a child whose parent is at level 2, and so on. A root node is the highest node within an inverted tree, and therefore has no parent. A child node is any non-root node. A parent node is any node that has children. A leaf node is any node without children. To define a hierarchical relationship in a query, you must use the START WITH and CONNECT BY clauses. Informix does not support the LEVEL clause. See the Hierarchical Queries subsection in the SQL section in the Data Manipulation Language chapter for more information on how to process these queries.
ROWID
Oracles ROWID pseudo-column returns the row's address for each row in the database. ROWID values contain the following information necessary to locate a row: Which data block in the data file Which row in the data block (first row is 0) Which data file (first file is 1)
Usually, a ROWID value uniquely identifies a row in the database. However, rows in different tables that are stored together in the same cluster can have the same ROWID. Values of the ROWID pseudo-column have the data type ROWID. ROWID values have several important uses: They are the fastest way to access a single row. They can show you how a table's rows are stored. They are unique identifiers for rows in a table. A ROWID does not change during the lifetime of its row. However, you should not use ROWID as a table's primary key. If a row is deleted and re-inserted, its ROWID may change, even when using the export and import utilities. If a row is deleted, Oracle may re-assign its ROWID to a new row inserted later. Although you can use the ROWID pseudo-column in the SELECT and WHERE clauses of a query, these pseudo-column values are not actually stored in the database. The value of a ROWID pseudo-column cannot be inserted, updated, or deleted. For example, the following Oracle statement selects the address of all rows that contain data for employees in department 20: ROWID 0000000F.0000.0002 0000000F.0003.0002 0000000F.0007.0002 0000000F.000A.0002 0000000F.000C.0002 ENAME SMITH JONES SCOTT ADAMS FORD
The equivalent pseudo-column in Informix is also known as ROWID, and although the behavior is similar, the data type is different from Oracles. See the ROWID subsection in the Data Types section in the chapter Data definition language for more information.
ROWNUM
In Oracle, for each row returned by a query, the ROWNUM pseudo-column returns a number indicating the order in which Oracle selected the row from a table or set of joined rows. The first row selected has a ROWNUM of 1, the second has 2, and so on. ROWNUM can be used to limit the number of rows returned by a query, as in this example to read 9 rows: SELECT * FROM emp WHERE ROWNUM < 10
Version 1.6
46
You can also use ROWNUM to assign unique values to each row of a table, as in this example: UPDATE tabx SET col1 = ROWNUM Oracle assigns a ROWNUM value to each row as it is retrieved, before the rows are sorted by an ORDER BY clause. Therefore, the final order of the rows is in ORDER BY order not in ROWNUM order. An ORDER BY clause does not affect the ROWNUM values except in the case where the ORDER BY clause causes Oracle to use an index. In that case, the ROWNUM values are set in the order the rows are retrieved using the index and hence in ORDER BY order. This order is different than if the rows were retrieved without the index. So in this case the ORDER BY can affect the ROWNUM values. Conditions which test for ROWNUM values greater than zero are always false. For example, this query returns no rows: SELECT * FROM employee WHERE ROWNUM > 1
The first row fetched is assigned a ROWNUM of 1, thus making the condition false. The second row to be fetched is now the first row and is also assigned a ROWNUM of 1 making the condition false. All rows subsequently fail to satisfy the condition, so no rows are returned. Although there is no ROWNUM equivalent in Informix, there are solutions. Beginning with IDS 7.3 and in Informix Dynamic Server 2000, Informix provides a feature which allows the user to limit the results of a query to the first N rows. This was implemented for TPC-D compliance and to support rank queries. Rank queries can be assembled by using FIRST N with the ORDER BY clause. Informix will return the top N rows according to some ordering criteria. Therefore the following Oracle SELECT utilizing ROWNUM: SELECT * FROM emp WHERE ROWNUM < 10 can be ported to Informix as follows: SELECT FIRST 9 * FROM emp Informix does not support SELECT FIRST N in complex cases as the following: Sub-queries (SELECT within a SELECT) View definitions (Cannot be used by a SELECT statement which references a view) UNION queries
The behavior of SELECT FIRST N depends on the presence of an ORDER BY clause. If no order by clause is specified, the first N rows returned may be in any order. Examples are as follows: /* find 10 highest paid employees */ SELECT FIRST 10 name, salary FROM emp ORDER BY salary; /* find 10 highest salary values SELECT FIRST 10 DISTINCT salary FROM emp ORDER BY salary; */
Version 1.6
47
Informix supports column names of first. Thus, without a positive integer following the word first, the token is parsed as a column name rather than a keyword. The value of N may be 31 between 1 and (2 -1). When ROWNUM is used in a WHERE clause, the same results can be obtained through the use of the FIRST N and SKIP clauses, but if ROWNUM is used in the select list, the solution is a little more complicated. Simply stated, you can construct a query where the ROWNUM column in any row is the count of the rows that came before. This involves creating a correlated subquery where the subquery contains a self-join. This can be done for any table, or set of tables, which has a unique key defined on it. Here is an example using the customer table of the stores7 database. select counter.rownum, base.customer_num, base.fname, base.lname from -- There can be more than one table here, and the result -- set should thought of as a table (just not a base table). -- The result table has to be joined to itself in the -- subquery; so, if there are multiple tables in this FROM -- clause, the expansion can get messy. You have to have a -- set of columns that uniquely identify each row in the -- result table, and join across them. ROWID would -- likely work if the table is not fragmented, but if it is, -- there is no guarantee the final results would be accurate -- because ROWID is not guaranteed to be unique across -- fragments. customer base, (select count(*) as rownum, a.customer_num -- any unique key, possibly multiple -- columns from customer a, customer b where -- This is where the rownum is determined the relationship -- here has to match the outer order-by, where the rows -- are sorted, and has to create a unique sort order --- Any columns to be ordered by go here. -- Also, the unique key has to be used to keep rows -- that do not have a unique sort order from being merged (a.lname > b.lname) -- example, sorting by last name or (a.lname = b.lname and a.fname > b.fname) -- sorting by fname where lname is equal or (a.lname = b.lname and a.fname = b.fname and a.customer_num >= b.customer_num) -- sorting by unique key where all the -- other sort columns are equal -- The expansion above is logically the same as -a.lname || a.fname || to_char(a.customer_num) >= -b.lname || b.fname || to_char(b.customer_num) -- but it allows the server to utilize any indexes that -- may exist. group by -- unique key columns go here
Version 1.6
48
a.customer_num ) counter where -- key columns in the base tables go here base.customer_num = counter.customer_num -- if you want to limit on rownum, it goes here -- and rownum <= 10 order by counter.rownum If using ROWNUM as an assignment, as in: UPDATE tabx SET col1 = ROWNUM The following Informix-ESQL/C pseudo-code example would have to be used: int counter = 0; EXEC SQL declare c1 cursor for SELECT col1, col2 INTO :col1, :col2 FROM table 1 WHERE col1 = "XX"; EXEC SQL open c1; while (SQLCODE == 0) { EXEC SQL fetch c1; counter++; fetched */ if (counter >= 5) { break; /* logic... */ } } /* End while */ /* End if */ /* Increment counter for each row
Version 1.6
49
In Informix, a commit or rollback statement closes all cursors open in a given transaction boundary. See the Transaction Processing section in CHAPTER 5: Application Architecture for more information. In situations where the intention is to commit or rollback without closing the cursor, in other words, where the commit or rollback is executed within a cursor fetch loop, the cursor can be declared as a HOLD cursor. This requires that a BEGIN WORK is issued before the cursor loop starts. A HOLD cursor is not closed when a commit or rollback statement is issued. In Informix, the FOR UPDATE clause cannot be used when declaring a HOLD cursor. Thus, where an Oracle application updates a table from which it fetches data in the fetch loop or issues a commit work in the fetch loop, it must be converted to Informix. The cursor can be declared with HOLD and then an UPDATE statement can be issued without the WHERE CURRENT OF clause. In order to uniquely identify the row to be updated in the table, in other words, in order to simulate the WHERE CURRENT OF clause, the ROWID or unique primary key columns of the table(s) to be updated must also be fetched and the WHERE CURRENT OF clause can be replaced with WHERE ROWID = fetched rowid or WHERE unique primary key column(s) = fetched unique primary key column(s). A BEGIN WORK must follow immediately after a COMMIT WORK or ROLLBACK WORK in the fetch loops to simulate Oracle implied transaction boundaries. These transaction control statements work for either Informix logged databases or Informix ANSI mode databases, however, ANSI mode database processing with these statements will set certain warning flags after executing the BEGIN WORK statement and continue processing without failure. See the ANSI vs. Non-ANSI subsection in the Databases section in the chapter Data Manipulation Language for more information.
System tables
References to Oracle system tables should be replaced with corresponding references to Informix system tables. The information schema views provided by Informix can be used. These views are created after the database is installed. They are populated by data in the system catalog tables and are used for easier porting.
Stored procedures
Informix procedures and functions are considered to be user-defined routines (UDR). A UDR can be written in Informixs Stored Procedure Language (SPL) or an external language, such as C or Java. A procedure is a routine written that does not return a value. A function is a routine written that returns a single value, a value with a complex data type, or multiple values. Informix SPL is an extension to Informix SQL and provides procedural flow control such as looping and branching. A SPL routine is a generic term that includes both SPL procedures and SPL functions. You use SQL and SPL statements to write an SPL routine. SPL statements can be used only inside the CREATE PROCEDURE, CREATE PROCEDURE FROM, CREATE FUNCTION, and CREATE FUNCTION FROM statements. SPL routines are parsed, optimized, and stored in the system catalog tables in executable format. Like Oracle, Informix stored procedures support input, output and input/output parameters and can be used in SQL statements wherever expressions are allowed.
Size limit
Informix stored procedures have a size limit of approximately 64K. Oracle stored procedures greater than 64K in size can be broken into smaller Informix stored procedures communicating with each other as though they were one by passing and returning the necessary values.
Parameter limit
Version 1.6
50
Informix has a limit of 341 parameters for each stored procedure. This limit also applies to UDRs written in the Java language. UDRs written in the C language can have no more than 102 parameters. You can define any number of SPL routine parameters, but the total length of all parameters passed to an SPL routine must be less than 64 kilobytes. No more than nine arguments to a UDR written in the Java language can be DECIMAL data types of SQL that the UDR declares as BigDecimal data types of the Java language. Any C language UDR that returns an opaque data type must specify opaque_type in the var binary declaration of the C host variable.
Packages
An Oracle package is a collection of functions, procedures, and variables that can be enabled and accessed as a unit. There is no direct equivalent within Informix, but there are ways of achieving similar capabilities. Within Oracle, a procedure within a package can be accessed through grammar such as package_name.procedure_name. If you create an owner or schema name within the Informix system the same as the package name, then it will be easier to migrate calls to that procedure because the grammar is effectively the same, although the meaning changes somewhat. Using this practice, a call to a migrated procedure would be owner.procedure_name, where the owner name is the same as the package name. Translating package names as owner names is a way to maintain the scoping of the objects within the package. Maintaining the aspect of being able to enable use of or upgrade the collection of package objects can be done by creating a datablade that contains all the objects that used to be part of the package. Datablade routines can be procedures or functions written in Stored Procedure Language (SPL), C, and Java. In addition, routines can be written in C++ on Windows platforms.
Routines
Oracles stored functions and stored procedures are similar in concept to Informixs stored procedures. Oracles user defined database level functions such as stored functions, stored procedures all need to be converted to Informix stored procedures using the Informix SPL, C, or Java. Routines written in SPL have the advantage of being maintained and backed up with database backups. Routines written in C are fast, but are not automatically backed up when the database is and need to be compiled specifically for the operating system on which it will run. Routines written in Java also not backed up by the DBMS itself, but they are platform independent. However, probably as a result of having to convert between system memory where the objects have C structures and Java virtual machine memory where the objects have Java structures, the performance of Java routines can be slow compared with the C equivalent. All procedures written in an Oracle package body must be rewritten as separate Informix procedures. When rewriting package bodies into separate procedures, Oracles variable declarations can be replaced at the package level (global) with Informixs global variables. The Informix global variables must be defined in the first stored procedure of the logical group.
Exceptions
The method of handling exceptions is different between Informix and Oracle. Oracle has many predefined and user defined exception labels such as CURSOR_ALREADY_OPEN, NO_DATA_FOUND, ZERO_DIVIDE, and so on. The labels can be used in the logic to identify errors. Only one exception check is allowed per BEGIN and END block using the EXCEPTION construct, and it is normally placed just before the END statement. Informix also supports predefined and user defined exceptions, however, they are represented numerically, not with labels. In Informix, all the exceptions checked in the stored procedure control blocks, delimited with BEGIN and END statements, must be declared explicitly at the top of each
Version 1.6
51
control block with the Informix EXCEPTION construct. Therefore, Oracle procedure code must be restructured to manipulate these exceptions. In Oracle, an exception can be raised globally and acted upon globally. In Informix, the scope of an exception mechanism is always restricted to the block in which it is located. This leads to the addition of multiple Informix exception handling mechanisms for each Oracle exception raised as well as a redesign of the overall stored procedure to a more blocked format.
Error handling
In Oracle, errors are processed as part of a function call return value. In Informix, errors are retrieved as a separate function call that has multiple structures that have to be created in order to retrieve error and status. The SQLCA structure is not fully available in Informix stored procedures. It is not possible to check the SQLCODE variable in the stored procedure body. Instead, the function DBINFO can be used to extract the value of two members of the SQLCA structure: sqlca.sqlerrd1 and sqlca.sqlerrd2. This function should be used inside the FOREACH construct while the cursor is open. Once the cursor is closed, the DBINFO function cannot return proper values. The sqlca.sqlerrd1 option returns different values depending on the type of SQL statement. For INSERT statements, if the table contains a serial column, then the sqlca.sqlerrd1 option will return the serial value of the last row inserted into the table. For SELECT, DELETE, and UPDATE statements the sqlca.sqlerrd1 option will return the number of rows processed by the query. In these cases, upon each pass through the FOREACH loop, sqlca.sqlerrd1 is the same value: the number of rows the FOREACH loop will process. The sqlca.sqlerrd1 value can still be interrogated during each pass through the FOREACH loop. The sqlca.sqlerrd2 option returns the number of rows processed by a SELECT, INSERT, UPDATE, DELETE, or EXECUTE PROCEDURE statement. It should not be interrogated until after the cursor has finished processing. In other words, within the FOREACH loop, the sqlca.sqlerrd2 value can be moved to a variable which is then interrogated outside of the FOREACH loop.
Cursors
Unlike Informix, in Oracle, cursors can be global to a package. In Informix, Oracles global cursors can be replaced with temporary tables. A temporary table can be created and populated in place of where the cursor is opened. The temporary table can then be processed the same way the cursor is processed. Finally, the temporary table should be dropped in place of where the cursor is closed. Cursors are explicitly declared, opened and fetched in Oracle stored procedures. In Informix, cursors do not need to be explicitly declared, opened and fetched in stored procedures. Instead, Oracle stored procedure cursors can be replaced with Informixs FOREACH construct. The Oracle cursor name should be used in the FOREACH statement, for example: FOREACH cursor_name SELECT END FOREACH. In order to update a cursor row in Oracle, the cursor must be declared with the FOR UPDATE clause. In Informix, if the SELECT statement in the FOREACH construct is not a multi-table join, then each fetched row can be updated using the UPDATE <table_name> WHERE CURRENT OF <cursor_name> statement. See the Update Using Cursors section in Data Manipulation Language for more information. Informix does not support the SELECT FOR UPDATE statement in a stored procedure. Therefore, the SELECT FOR UPDATE clause cannot be used in the FOREACH construct.
Version 1.6
52
Boolean
Oracles BOOLEAN variable type can be replaced with Informixs BOOLEAN data type.
Dynamic SQL
Unlike Oracle, Informix does not support dynamic SQL within the Stored Procedure Language. In other words, a statement such as SELECT variable_name FROM variable_name WHERE variable_name is not supported. This kind of processing can be achieved in Informix within an embedded SQL program. This requires that either the Oracle stored procedure be converted to an embedded SQL program, or just the Dynamic SQL portion be placed in an embedded SQL program and then called from within the stored procedure. The latter option will have performance implications since calling an embedded SQL program from a stored procedure requires an operating system call. Another option is to use the Informix EXEC Bladelet. The EXEC Bladelet consists of user-defined functions that take a SQL query as an argument, execute it, and return a result (the format of which varies depending on the function and the kind of query). The EXEC Bladelet functions can handle most Data Definition Language (DDL) statements, and all Data Manipulation Language (DML) queries. Further details can be found in Chapter 7: Using Bladelets.
Compiler
Unlike Oracle, the Informix compiler was developed with the concept that developers can create stored procedures independently of the database. Therefore, Informixs stored procedure
Version 1.6
53
compiler has a limited set of errors that it checks compared to Oracles . For example, the Informix stored procedure compiler does not validate database object names such as table, column, and view names. Therefore, database object naming errors will occur at runtime, not compile time. Additionally, the error messages generated from the compiler are not very specific. Identifying a problem in a stored procedure may require breaking it apart and recompiling the pieces until the problem is found. This may impact the time necessary to unit test the stored procedures.
Triggers
Oracle supports the use of multiple trigger events, for example, insert, update, and delete within the same trigger. Informix only supports one trigger event per trigger. In Informix, the Oracle trigger body in this example must be copied into three different triggers each with only one event. Informix triggers have some constraints; Oracles do not. In Informix, if a trigger is fired due to inserting a row into a table, a trigger can only act on any rows or columns within that table using the EXECUTE PROCEDURE INTO syntax. Similarly, if a trigger is fired due to updating a row, then the trigger can only act on the column that caused the trigger to fire using the EXECUTE PROCEDURE INTO syntax. Like Oracle, if a trigger is fired due to deleting a row, there are no restrictions. Prior to IDS 7.3 when a trigger was fired on an INSERT/UPDATE action, no modification could be done to the columns (in the row) which just fired the trigger. The reentrant UPDATE/INSERT triggers feature introduced with IDS 11.10 enables users to update the triggering columns by using the EXECUTE PROCEDURE ... INTO syntax. Additionally, the feature enforce that this action will not cause any additional triggers to be fired (same or different trigger) causing a cascading of triggers and potentially an infinite loop. The following example demonstrates how the reentrant UPDATE/INSERT trigger feature is used: create table foo ( x int default NULL, y int default NULL, z int default NULL ); create procedure reentrant() returning int; return 56; end procedure; create trigger reentrant_trigger insert on foo for each row ( execute procedure reentrant() into z ); insert into foo values ( 1, 2, 3 ); The following SELECT will result in the following returned data: select * from foo; x 1 y 2 z 56
Version 1.6
54
Oracle allows SQL statements, logical statements, and stored procedure calls within a trigger body. Informix allows only SQL statements and stored procedure calls within a trigger body. Oracle triggers containing logical statements must be converted to Informix by moving their contents into a stored procedure. The stored procedure should then be executed from the trigger.
Constraints
Constraints in both Oracle and Informix can be enabled and disabled within an application transaction, however, there are behavioral differences. In Oracle, the application is always executing within a transaction. In Informix, transaction boundaries are explicitly declared and care should be taken to ensure that this functionality is performed within the boundaries of a transaction. See the Transaction Processing section in CHAPTER 5: Application Architecture for more information. The constraint syntax available in Informix is: SET {CONSTRAINTS/INDEXES/TRIGGERS} FOR table_name {ENABLED|DISABLED} SET CONSTRAINTS comma_separated_constraint_names {ENABLED|DISABLED} SET INDEXES comma_separated_index_names {ENABLED|DISABLED} SET TRIGGERS comma_triggers_constraint_names {ENABLED|DISABLED} SET CONSTRAINTS {ALL/constraint_name} {IMMEDIATE|DEFERRED} The first four statements must be executed with DBA privileges if placed in the application. Therefore, care should be taken when using them. Note that the last statement contains a DEFERRED clause. This is the statement used if the users of the application do not have DBA privileges. When the constraint is set with the DEFERRED clause, the specified constraints are not checked until the transaction is committed. If a constraint violation occurs while the transaction is being committed, the transaction is rolled back.
DUAL table
Oracles DUAL table is a system table with only one row containing one column named DUMMY. This table is used to complete the syntax of an SQL statement that does not involve an existing table such as: A SELECT statement which assigns some constant value (which can only be derived in an SQL statement) to a host variable: SELECT TO_CHAR(SYSDATE) INTO :date_var FROM DUAL; A SELECT statement which assigns a value of another variable to a variable: SELECT :source_var INTO :dest_var FROM DUAL; A SELECT statement which unions application host variable values with another SELECT statement to return a result containing a row of application variable values: SELECT col1, col2, col3 FROM table_name UNION SELECT :host_var1, :host_var2, :host_var3 FROM DUAL; Converting Oracles DUAL table functionality to Informix depends on the way it is used. Converting statements that just assign constants is as simple as replacing the DUAL statement with an Informix assignment statement. The solutions below apply to Informix versions prior to 11. At 11 and above, the concept of a DUAL table, as well as sysdate, is supported:
Version 1.6
55
SELECT sysdate FROM sysmaster:sysdual; If you want a dual table in your local database, then create the following synonym. The sysmaster:sysdual table is much faster than a physical table in your database because it is an inmemory pseudo table. CREATE SYNONYM dual FOR sysmaster:sysdual; If you are restricted to using a version of Informix prior to 11, then the following solutions can be used. A dummy table can be created to mimic the behavior of simple SELECT INTO statements used to assign values to variables. CREATE TABLE dual (dummy VARCHAR(1)); INSERT INTO dual VALUES(X); An alternate solution to widespread use of the DUAL table could be creating a permanent view that is generally accessible. CREATE VIEW dual (d) as SELECT 'X' FROM systables WHERE tabid = 1; The exact definition could be used or modified as needed, but this would solve the problem of having DUAL be permanent, usable by anyone, and not modifiable.
Version 1.6
56
CHAPTER 5:
Embedded SQL
Oracles embedded SQL products are Pro*C and Pro*COBOL. Informixs corresponding embedded SQL products are ESQL/C and ESQL/COBOL.
Host variables
Declaration override
The Oracle EXEC SQL VAR declarative statement (host variable equivalency of Oracle external data types by overriding the default assignment) can be converted to an Informix explicit declaration statement. For example: Oracle: char char_var[20]; EXEC SQL VAR char_var IS STRING(11);
Informix: char char_var[11]; Note that the size and type used in the EXEC SQL VAR section is the final information required to declare the host variable in Informix.
Arrays
Oracle arrays are not subscripted in SQL statements since it is not required to process the host arrays in a loop in the SQL statement. In Informix, subscripting is mandatory. In Oracle, if an array is defined of size 200 then an SQL statement would be: EXEC SQL FETCH CURSOR-NAME INTO :VAR-A, :VAR-B, :VAR-C END-EXEC -orEXEC SQL SELECT COL1, COL2, COL3 INTO :VAR-A, :VAR-B, :VAR-C FROM TABLE1 WHERE COL2 > 100 END-EXEC where VAR-A, VAR-B and VAR-C are each an array of say 200.
Version 1.6
57
In Informix, the first example would be converted to: PERFORM VARYING LOOP-CTR FROM 1 BY 1 UNTIL LOOP-CTR IS GREATER THAN 200 EXEC SQL FETCH CURSOR-NAME INTO :VAR-A(LOOP-CTR), :VAR-B(LOOP-CTR), :VAR-C(LOOP-CTR) END-EXEC IF SQLCODE = 100 GO TO EXIT-PERFORM END-IF END-PERFORM EXIT-PERFORM. For the second Oracle example given above, a cursor must be declared in Informix, opened, and fetched for 200 rows or less (less, because there may be less than 200 qualifying rows) into the host array and then should be closed. If the number of qualifying rows is more than 200, then the extra rows must be ignored to duplicate the Oracle functionality. But for the first example, each fetch in Oracle will return the next 200 or less number of rows. Therefore, each Oracle fetch needs to be replaced by another call to the Informix fetch loop. Oracle also uses this method for inserts, deletes and updates. These array techniques are mainly used in batch SQL processing.
Formatting
In Informix, when a DECIMAL, MONEY, DATE, or DATETIME value is selected into a host variable of the same data type, the value must be formatted using the available Informix formatting routines before they can be printed or displayed. For example: dec_t dec_host_var; char formatted_dec[40]; EXEC SQL SELECT DEC_COLUMN INTO :dec_host_var FROM TABLE_NAME; rfmtdec(&dec_host_var, &&&&&&&.&&&, formatted_dec); printf(The Decimal Value is %s\n, formatted_dec);
Version 1.6
58
Informix supplies many formatting functions and formatting strings. The names of these functions are different in Informix ESQL/C and ESQL/COBOL, but the functionality is the same. Refer to the appropriate Informix API Programmers Manual (Informix-ESQL/C Programmers Manual or Informix-ESQL/COBOL Programmers Manual) for more information.
SQL structures
SQLCA
Oracles SQLCA structure is different from that of Informix., However, the components of both structures are logically the same. Oracles SQLCA components can be replaced with the corresponding Informix components. Oracles SQLCA structure: SQLCAID SQLCABC SQLCODE SQLERRM SQLERRML SQLERRMC SQLERRP SQLERRD SQLERRD(0) SQLERRD(1) SQLERRD(2) SQLERRD(3) SQLERRD(4) SQLERRD(5) SQLWARN SQLWARN(0) SQLWARN(1) SQLWARN(2) SQLWARN(3) SQLWARN(4) SQLWARN(5) SQLWARN(6) SQLWARN(7) SQLTEXT string containing SQLCA length of SQLCA data structure Oracle error message code sub-record for error message length of error message text of error message reserved for future use array of six-integer status codes reserved for future use reserved for future use number of rows processed reserved for future use parse error offset reserved for future use array of eight warning flags another warning flag set character string truncated no longer in use SELECT list not equal to INTO list DELETE or UPDATE without WHERE clause reserved for future use no longer in use no longer in use reserved for future use
Version 1.6
59
Informixs SQLCA structure: SQLCODE SQLERRM SQLERRP SQLERRD SQLERRD(0) SQLERRD(1) SQLERRD(2) SQLERRD(3) SQLERRD(4) SQLERRD(5) SQLWARN SQLWARN0 SQLWARN1 revoked SQLWARN2 SQLWARN3 end SQLWARN4 SQLWARN5 SQLWARN6 SQLWARN7 Informix error code error message parameter reserved for future use array of six-integer status codes estimated number of rows returned serial value of INSERT or ISAM error code number of rows processed estimated cost parse error offset ROWID after INSERT structure of eight warning flags another warning flag set character string truncated or no privileges NULL value returned or ANSI database SELECT list not equal to INTO list or turbo backDELETE or UPDATE without WHERE clause if non-ANSI statement if server is in data replication secondary mode reserved
In order to get Oracle error messages, an application normally uses the SQLCA element SQLERRMC. The Informix equivalent is SQLERRM. On the HP/UX and Solaris platforms, the Informix function rgetmsg should be used instead of the element SQLERRM. At the time of this writing, using SQLERRM would cause an error on the HP/UX and Solaris platforms.
SQLDA
The implementation of Oracles SQLDA structure is very different from that of Informix. Significant changes are necessary to convert Oracles functionality to Informix . Oracles sqlald function can be replaced with Informixs ALLOCATE DESCRIPTOR statement. Since Oracles and Informixs SQLDA structures are so different, Oracles SQLDA logic must be rewritten with the more powerful Informix SQLDA logic or alternatively, the Informix system-descriptor area logic. Oracles SQLDA Structure: N maximum number of SELECT list items or placeholders V pointer to array of address of SELECT list items or bind variables L pointer to array of lengths of SELECT list items or bind variables T pointer to array of data types of SELECT list items or bind variables I pointer to array of addresses of indicator variable values F actual number of SELECT list items or placeholders S pointer to array of addresses of SELECT list items or placeholder names M pointer to array of max lengths of SELECT list items or placeholder names C pointer to array of current lengths of SELECT list items or placeholder names X pointer to array of addresses of indicator variable names Y pointer to array of maximum lengths of indicator variable names Z pointer to array of current lengths of indicator variable names
Version 1.6
60
Informixs SQLDA Structure: SQLD SQLVAR SQLDATA SQLTYPE SQLLEN SQLIND SQLNAME SQLFORMAT SQLIDATA SQLITYPE SQLILEN
count of the following SQLVAR members pointer to array of structures pointer to actual data data type of placeholder or SELECT item length of the placeholder or SELECT item pointer to the indicator pointer to placeholder or SELECT item name reserved indicator data pointer indicator variable type length of indicator variable
If an Oracle application uses the simple dynamic SQL method using macros only, not the SQLDA structure directly, the value indicators/placeholders can be replaced with a ? in Informix . For example: Oracle: sprintf(sqlstring, INSERT INTO TABLE1 VALUES (:v1, :v2)); Informix: sprintf(sqlstring, INSERT INTO TABLE1 VALUES (?, ?));
ORACA
Oracles ORACA structure is not supported by Informix. This structure is used to handle Oracle specific communication and more runtime information than SQLCA. Oracle statements containing references to this structure should be removed from the application.
Pre-compiler options
The Oracle options beginning with the EXEC ORACLE OPTION statement can be removed from the application. The options set after this statement do not affect the application logic. They may affect some application performance only.
Embedded PL/SQL
Oracle allows procedure language (PL/SQL) blocks inside Pro*C and Pro*COBOL code delimited by the EXEC SQL EXECUTE and END-EXEC statements. In Informix, these blocks must be replaced with the equivalent ESQL/C or ESQL/COBOL code.
Version 1.6
61
The following table is an approximate mapping of the differences between the Informix CLI and Oracle OCI function calls in which there is not a direct one-to-one mapping: Oracle HAD, LDA, CDA OLOG, OOPEN OPARSE, OBNDRV, OEXEC ODEFIN, OFETCH OCOM, OROL OLOGOF, OCLOSE Informix HENV, HDBC, HSTMT SQLConnect, SQLAllocEnv, SQLAllocConnect, SQLAllocStmt SQLPrepare, SQLBindParameter, SQLExecute SQLBindCol, SQLFetch SQLTransact SQLDisconnect, SQLFreeStmt, SQLFreeConnect, SQLFreeEnv
Buffer Areas Connect and allocate resources Update, delete, insert, select Select Commit, Rollback Disconnect
Fetch cycle
Another difference between Informix CLI and Oracle OCI calls is that the overall fetch cycle is different for each and must be modified accordingly. In Oracle, the fetch cycle for selecting multiple rows utilizing a cursor area involves parsing, binding, defining, fetching, and then executing into a cursor data area. These must be translated to a cycle that involves preparing, binding, executing, binding, and then fetching via the For Each cycle.
Parameter bindings
In Oracle, multiple output bindings of parameters are declared as type OUTPUT in the ODEFIN() calls. In Informix, convert the calls to Informix SQLBindCol() calls and bind the output parameters as columns. Differences also exist between Informix CLI and Oracle OCI in the use of input/output bindings. In Oracle, these bindings are declared as type INPUT/OUTPUT in the ODEFIN() calls . In Informix, a round robin approach is used using three variables in the following manner: A=B, B=C, C=A. A variable (A) is declared before the SQL bindings as an input variable. The function is called
Version 1.6
62
using a second input variable (B) that is set to the first input variable (A). The function returns a third variable (C) that is bound as an output column. Finally, the first variable (A) is now set to the returned third variable (C) that made the first variable (A) appear as an input/output variable to the rest of the program.
Host variables
The Oracle statement EXEC SQL TYPE is synonymous with the C languages typedef declarative instruction. It can be easily replaced with the Informix declarative instruction typedef.
Version 1.6
63
Level 88
COBOLs level 88 functionality is not supported within an Informix ESQL/COBOL host variable declaration section in versions prior to 7.2. Level 88 functionality is supported in Informix ESQL/COBOL 7.2.
SQLDA
In Informix ESQL/COBOL, the SQLDA structure is not available. The Informix macros, such as ALLOCATE DESCRIPTOR, DESCRIBE, GET DESCRIPTOR, and SET DESCRIPTOR must be used to retrieve and manipulate the SQLDA data.
REDEFINES
Oracle supports the use of the REDEFINES clause at the elementary level in the host variable declaration section. In other words, the redefined item cannot be a group item but the redefining item may be a group item. Informix does not support the use of the REDEFINES clause in the host variable declaration section in versions prior to 7.2. The REDEFINES clause is supported in Informix ESQL/COBOL 7.2.
Tips
If the Informix pre-compiler finds an SQL statement within an IF [ELSE IF ] END-IF or EVALUATE END-EVALUATE or PERFORM END-PERFORM block, then the pre-compiler adds a period after the generated COBOL statements regardless of whether there is a period at the end of the SQL statement. This is a violation of COBOL rules for such blocks and the code may cause syntax errors during compilation, or may behave unexpectedly. To avoid these problems, each SQL statement group should be moved to a new paragraph and these paragraphs should be performed from the block from which they were moved.
ODBC
Although the Open Database Connectivity (ODBC) API is designed to make it possible to write and compile an application once and use it with any ODBC driver on the same platform, there are frequently differences between the underlying DBMSs that can expose problems to the applications. For instance, there can be differences between how unspecified parts of a date-time value are filled. Most of these kinds of differences that get exposed through ODBC have their origins in the differences between the DBMSs themselves. There are also cases where there are gaps in the ODBC standard; for example, there is a standard ODBC call that allows the application to ask the driver if it can support scrollable cursors, and there is another call to ask if it can support updateable cursors. There is no call to ask if it can support both at the same time. With Informix, you can have a scrollable cursor and you can have an updateable cursor, but you can not have one cursor that is both scrollable and updateable. A more complete description of ODBC application migration issues is beyond the scope of this article.
Version 1.6
64
CHAPTER 6:
Application Architecture
Transaction processing
Transaction boundaries are defined differently in Oracle and Informix. Oracles transactions begin implicitly in one of two ways, either by issuing a CONNECT statement or issuing a COMMIT or ROLLBACK statement. A CONNECT statement marks the beginning of a transaction and a COMMIT or ROLLBACK statement commits or rolls back the previous transaction, respectively, and then implicitly begins a new transaction. CONNECT statements are usually issued once at the beginning of a program; however, they may be nested or issued more than once serially to connect to the same or a different database. When using more than one CONNECT statement within a program, each CONNECT statement must be named. This marks the beginning of named transactions. Every SQL statement within a named transaction must also be named with the same transaction name as the CONNECT statement at where the SQL is to be executed. SQL is named using the EXEC SQL statements AT clause. Informixs transaction boundaries are explicitly marked with the reserved words BEGIN WORK and COMMIT WORK or ROLLBACK WORK. Note that once a transaction has begun for a given connection, it stays open until a COMMIT or ROLLBACK is executed. In other words, if an ESQL program begins a transaction and then calls a stored procedure, the stored procedure executes within the same transaction. If the stored procedure issues a COMMIT, then the whole transaction is committed and the calling ESQL program should not issue a COMMIT or ROLLBACK. Informix transactions can be written to behave the same way as Oracles. To simulate Oracles CONNECT statement behavior, an Informix CONNECT should also be issued followed by a BEGIN WORK statement. If more than one CONNECT statement is used in a program, Informix also requires that the CONNECT and SQL statements be named. To simulate Oracles COMMIT and ROLLBACK statement behavior, an Informix COMMIT WORK or ROLLBACK WORK statement should be issued followed by a BEGIN WORK statement. Nested transactions can be simulated in Informix with the CONNECT statement and naming the transactions. Then the Informix SET CONNECTION connection_name statement can be used to switch between transactions. Committing or rolling back each named transaction does not commit or roll back other active transactions. The Oracle statement EXEC SQL {COMMIT/ROLLBACK} RELEASE should be replaced with the Informix statements EXEC SQL {COMMIT/ROLLBACK} [WORK] followed by EXEC SQL DISCONNECT CURRENT. In the following examples, ws-dbenviron is the database name, ws-connect-nm is the user name and ws-identity-nm is the password set in the program, enp and connection-name are the connection names. For Informix, the user name and password information should correspond to the entries in the /etc/passwd file on the UNIX system. See the User Authentication section later in this chapter for more information. The default server name is automatically obtained from the environment variable INFORMIXSERVER. The following examples illustrate how Oracle and Informix implement the CONNECT functionality.
Version 1.6
65
Simple Connect Oracle: CONNECT :ws-connect-nm IDENTIFIED BY :ws-identity-nm Informix: CONNECT :ws-dbenviron USER :ws-connect-nm USING :ws-identity-nm Named Connect with Literal Oracle: DECLARE enp DATABASE CONNECT :ws-connect-nm IDENTIFIED BY :ws-identity-nm AT enp USING :ws-dbenviron AT enp SELECT col1, col2 INTO :var1, :var2 FROM table_name Informix: CONNECT TO :ws-dbenviron AS enp USER :ws-connect-nm USING :ws-identity-nm WITH CONCURRENT TRANSACTION SET CONNECTION enp SELECT col1, col2 INTO :var1, :var2 FROM table_name Named Connect with Variable Oracle: CONNECT :ws-connect-nm IDENTIFIED BY :ws-identity-nm AT :connection-name USING :ws-dbenviron AT :connection-name SELECT col1, col2 INTO :var1, :var2 FROM table_name Informix: CONNECT TO :ws-dbenviron AS :connection-name USER :ws-connect-nm USING :ws-identity-nm WITH CONCURRENT TRANSACTION SET CONNECTION :connection-name SELECT col1, col2 INTO :var1, :var2 FROM table_name
Autonomous Transaction
An autonomous transaction is an independent transaction that is initiated by another transaction (the parent transaction). An autonomous transaction can modify data and commit or rollback independent of the state of the parent transaction. The autonomous transaction must commit or roll back before the autonomous transaction is ended and the parent transaction continues.
Version 1.6
66
An autonomous transactions has been available since the release of Oracle 8i. An autonomous transaction is defined in the declaration of a PL/SQL block. This can be an anonymous block, function, procedure, object method or trigger.This is done by adding the statement 'PRAGMA AUTONOMOUS_TRANSACTION;' anywhere in the declaration block. There isn't much involved in defining a PL/SQL block as an autonomous transaction. You simply include the following statement in your declaration section: PRAGMA AUTONOMOUS_TRANSACTION; Sample code: PROCEDURE test_autonomous IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN insert .... commit; END test_autonomous; Autonomous transactions can be used for logging in the database independent of the rollback/commit of the parent transaction.
Savepoints
Oracle allows savepoints within its PL/SQL. For example, a PL/SQL block can be structured so that SAVEPOINT A is issued upon entry and SAVEPOINT B is issued after some processing. Then, after some more processing, a COMMIT or ROLLBACK can be issued against all the logic since the last COMMIT point, which is before the PL/SQL block, or up to any of the savepoints, by naming the COMMIT or ROLLBACK with the savepoint name. In other words, a savepoint can be issued at the beginning of a stored procedure and then only the stored procedure logic can be committed without committing the changes pending before the stored procedure was executed. Those changes can be committed or rolled back once processing is returned from the stored procedure. Informix does not support savepoint processing within a stored procedure.
Concurrency
Database concurrency can be managed through the combination of two configurable settings; one specifies the lock granularity on database objects while the other influences how the application behaves in regards to the presence and placement of locks using a transaction isolation level.
Version 1.6
67
2. The environment variable IFX_DEF_TABLE_LOCKMODE will establish the default for CREATE TABLE statements issued without the LOCK MODE attribute and will override the Instances configuration setting. The variable setting on the client will override the server environment setting. set IFX_DEF_TABLE_LOCKMODE=ROW -orexport IFX_DEF_TABLE_LOCKMODE=ROW
3. Informix allows the instances lock level default to be changed using a configuration parameter. Row level locking can be as the default by adding the parameter DEF_TABLE_LOCKMODE to the instances ONCONFIG file. This parameter may not be found in the existing file and if not present can be added using an editor and establish a new default setting of ROW: DEF_TABLE_LOCKMODE ROW
None of the steps will apply a change to existing tables only establish the lock level for the CREATE TABLE statement.
2. The SET ENVIRONMENT statement can override the USELASTCOMMITTED configuration parameter setting for the duration of the current session. The same semantics apply as the parameter within the ONCONFIG file with the setting value enclosed in quotes (). SET ENVIRONMENT USELASTCOMMITTED ALL;
Version 1.6
68
3. The SET ISOLATION statement can be used to override the instance configuration and session environment setting. The SET ISOLATION statement is an Informix extension to the ANSI SQL-92 standard and provides the same functionality as the ISO/ANSIcompliant SET TRANSACTION statement. There is no support for the LAST COMMITTED option with the SET TRANSACTION statement. SET TRANSACTION complies with ANSI SQL-92 and only ANSI supported isolation levels are supported. SET ISOLATION TO COMMITTED READ LAST COMMITTED; 4. PREPARE statements in ODBC/JDBC applications This feature is primarily documented in the Guide to SQL: Syntax, Guide to SQL: Reference, Administrator's Reference, and Administrator's Guide.
Version 1.6
69
CHAPTER 7:
Security
User authentication
In Oracle security information is stored in the database. Up until recently Informix has used only the operating system security subsystem to check security. For security purposes Oracle connects to the server and passes the user ID and password information to the database for verification.
Version 1.6
70
Informix supports for the pluggable authentication module (PAM) framework, which lets an administrator customize authentication for individual applications, and permits column-level encryption.
Column-level encryption
You can use column-level encryption to improve the confidentiality of your data. IDS Version 11.10 has new built-in SQL scalar functions provide methods for data in columns to be stored in an encrypted format. Use the ENCRYPT_AES or the ENCRYPT_TDES function to define encrypted data. Use the DECRYPT_BINARY() and DECRYPT_CHAR() functions to query encrypted data. When using the routines the encryption of data is under application control and the DBMS is not aware that data is encrypted. Informixs support of column level encryption is analogous to Oracles DBMS Obfuscation Tool Kit. Built-in ENCRYPT functions provide methods for encrypting and decrypting the following character data types or smart large object data types: CHAR NCHAR VARCHAR NVARCHAR LVARCHAR BLOB CLOB
Version 1.6
71
initializes the key when the server starts; the key is destroyed when the database server shuts down.
Encrypting a column
Column data can be encrypted through the use of two functions, ENCRYPT_TDES and ENCRYPT_AES, corresponding to the two data encryption standards; Triple Data Encryption Standard (Triple-DES) and Advanced Encryption Standard (AES) which describes the cipher algorithm used to protect data from unauthorized viewing. AES encryption (also known as Rijndael) uses a 128-bit key size and Triple-DES encryption uses two 56-bit keys for 112-bits overall. Both functions are variant functions and will return a different result every time it is used. The following example demonstrates how to use the encryption functions with a column that contains a social security number: CREATE TABLE emp (name CHAR (40), salary MONEY, ssn LVARCHAR(64)); INSERT INTO emp VALUES ('Alice', 50000, ENCRYPT_AES('123-456-7890','one two three 123')); -orCREATE TABLE emp (name CHAR(40), salary MONEY, ssn LVARCHAR(64)); SET ENCRYPTION PASSWORD "one two three 123"; INSERT INTO emp VALUES ('Alice', 50000, ENCRYPT_AES('123-456-7890'));
Version 1.6
72
Do not use either decryption function to create a functional index on an encrypted column. This would store the decrypted values as plain text data in the database, defeating the purpose of encryption.
Storage considerations
An encrypted value uses more storage space than the corresponding plain text value. Data encrypted using AES can be bigger than Triple-DES, but not by a significant amount. This occurs because all of the information needed to decrypt the value, except the encryption key, is stored with the value. Therefore, before you set the encryption password and encrypt the data, you must be sure the encrypted data can fit in the column. A chart of the expected sizes can be found in the IBM Informix Administrator Guide.
Compliance regulations
Informixs encryption routines comply with the United States regulations of Health Insurance Portability and Accountability Act (HIPAA), Sarbanes-Oxley, Gramm-Leach-Bliley, and California Personal Information: Privacy (SB 1386) as well as the international requirements of Basel II. Also, they comply with the latest cryptographic standards (OpenSSL 0.9.7c).
Version 1.6
73
CHAPTER 8:
Environment
Scripts
Oracle make files used to build the application should be modified to invoke the appropriate Informix ESQL/COBOL, ESQL/C, MF COBOL, and other application language commands. The shell scripts, shell startup scripts, and command files should be modified for Informix compliant statements.
Version 1.6
74
#----------------------# Declare variables #----------------------dfile=$1 cfile=$2 awk '{print "s/"$1"/"$2"/"}' $dfile > $dfile"_sed" sed -f $dfile"_sed" $cfile The preceding script is used by creating a decode file (named decodefile in this case), which holds two columns in the form, which may contain multiple rows: oldval newval
Executing the following command: subvals.ksh decodefile chgfile will replace every occurrence of oldval with newval in the file chgfile. The shell script (subvals.ksh) writes to standard output, therefore, the output should be redirected. The redirected file will then be able to run with dbaccess.
Utilities
To improve performance, the Informix EXPLAIN utility should be used by executing the SET EXPLAIN ON command to see how an SQL statement accesses the database. From that point forward the access path for every SQL statement is written in the SQEXPLAIN.OUT file in the current working directory, or the home directory of the process that initiated the request on the host machine. The Informix SET EXPLAIN OFF should be executed to turn off this feature when finished. The overall system performance should be monitored using the Informix ONSTAT utility.
System catalog
The following items discuss how Informix implements the system catalog differently than Oracle. Each item refers to the Informix implementation only. Object names are stored in lower case. The system catalog tables are owned by informix. To query the systables table use: SELECT * from informix.systables. Each table in systables is assigned a tabid by the system. It is used as the primary key and therefore, the foreign key for the other catalog tables. The identifier information is stored in sysindexes. Columns part1 - part16 each contain a column component of a composite index. They are integers, positive for ascending order, negative for descending order. In syscolumns, collength and coltype have special meanings depending on the data type of the column. See the Informix Guide to SQL, Reference Version for details.
Version 1.6
75
CHAPTER 9:
Using Bladelets
What is a Bladelet?
A "Bladelet" is a small, informal Informix Datablade module. It's meant to be useful "out of the box," and is offered complete with source code at no cost -- and no support or warranty. In the context of this document, the term "Datablade" refers to an extension to the standard IBM Informix database engine. These generally take the form of new data types (for example, timeseries or video) and/or new routines that execute inside the server. The new routines might operate on new data types, or on existing ones. A Datablade module is usually a formal product, available for sale. In addition a Datablade is: Developed either by IBM Informix or by a third-party developer Rigorously tested Packaged and sold for profit May or may not be formally certified by IBM Informix as having been developed according to approved Datablade coding practices
In contrast, a Bladelet is: Not rigorously tested Not sold for profit Not certified by IBM Informix
A Bladelet is an extension to the database engine that is narrow in scope and thought to be generally useful being offered at no cost, complete with source. Just remember before you use any of this code in mission-critical applications, it's up to you to thoroughly test it and fix any problems you find. Please review the disclaimer which applies to any sample code you find on this site: http://www.ibm.com/developerworks/db2/zones/informix/library/samples/db_downloads.html Note: The bladelets at this link have not been updated for some time (at the time of this writing); some of the capabilities, especially simple function call that increase compatibility, may have been introduced into the Informix server itself since they were written.
Useful Bladelets
Bladelet Description Defines two user-defined functions that provide dynamic SQL functionality within a SPL procedure. A complete access method that lets you build virtual tables based on operating system files. Implements a collection of "other database vendor" functions for Informix
Exec
Version 1.6
76
Provides a user-defined type for JPEG images that allows you to manipulate images and to extract and search on image properties
Creates the idn_mrLvarchar opaque type, which stores character data up to 2 gigabytes. Creates the node opaque type, which is intended to solve one of the hardest problems in relational databases: transitive closure. Creates routines that let you manipulate character and clob data using regular expressions. Creates several opaque types for managing spatial data, including R-tree index support.
SqlLib is a Bladelet that adds several "other database compatibility" functions to Informix . There are two functionally identical implementations: SqlLib for Java and SqlLib for C. SqlLib is a Bladelet that adds several "other database compatibility" functions to Informix . There are two functionally identical implementations: SqlLib for Java and SqlLib for C. Permits users to create and manage "versioned" tables.
We will look closer at two bladelets which could assist with migration; the Exec datablade and SQLLib.
Version 1.6
77
2. EXEC_FOR_ROWS The EXEC_FOR_ROWS() UDR is an iterator function, which means it can return more than one result row. Of course, it only does so when it is asked to execute a SELECT. Otherwise, it behaves exactly as the EXEC() UDR. Being an iterator function limits the ways in which such a UDR can be used. It cannot be used in another SQL query. The only place it can be used effectively is inside a SPL routine. 3. EXEC_FOR_MSET EXEC_FOR_MSET() is a SPL routine that uses the EXEC_FOR_ROWS() routine introduced above. Instead of returning a set of rows as an iterator, or a single row as the EXEC() UDF does, this UDR collects the results of the SQL query together into a single object: a multi-set. Refer to Appendix E: Sample Code for examples on using the EXEC bladelet functions.
For more details and download refer to: http://www.ibm.com/developerworks/db2/zones/informix/library/techarticle/db_sqllib.html For more details and download refer to: http://www.ibm.com/developerworks/db2/zones/informix/library/techarticle/db_sqllib.html
Version 1.6
78
A P P E N D I X A:
Planning guide
The checklist below will help an analyst determine which Oracle features which need to be converted to Informix and give some guidance on the effort involved. Each porting task is listed. They are followed by a quantity field used to determine how prevalent the item, the difficulty or amount of effort involved, 1 (low) to 5 (high), is used to estimate the amount of time needed to perform the task when the associated item exists in the application a moderate number of times. What is moderate depends on the size of the application. If there are an unusually large number of occurrences of an item, then the effort should be increased. Conversely, if there are a small number of occurrences of an item, then the effort should be decreased. Each of these items is discussed in detail within this document. Each heading corresponds to a section heading within the document.
Tasks
Quantity
Effort
DDL
Identifiers Delimit identifiers named with Informix reserved words Databases Determine database names and create databases Replace Oracle tablespace names with Informix dbspace names ANSI vs. Non-ANSI considerations Tables Convert create table statements Convert DDL syntax Reduce primary key length to 390 bytes Data Types Convert Oracles NUMBER data type Convert VARCHAR columns Convert Oracles DATE data type Convert raw data types Convert Rowids Indexes Convert Indexes Views Remove CREATE VIEW statement options Stored Procedures and Triggers Convert CREATE and REPLACE Stored Procedure and Trigger syntax Oracle Extensions Remove non-supported Oracle extensions from DDL 2 3 1 3 2 3 5 3 2 5 2 2 2 1 1 1
Tasks
Quantity
Effort
DML
SQL Add the Informix AS clause to display labels Replace non-supported DML syntax: ^=, /* */, :=, ELSE IF Convert Optimizer Directive/Hints Convert Insert/Select/Union and Insert/Value/Select statements 1 2 2 3
Version 1.6
79
Convert Delete statement syntax Convert temporary table processing Convert Join statements: +, MINUS, INTERSECT, different data types Convert sorts Convert hard coded SQL error messages Remove correlation names on the main table of Update and Delete statements Replace original table names in SELECT statements using aliases Convert hierarchical implementation (CONNECT BY PRIOR) Host Variables Convert host variable format or add conversion processing Functions Convert date and time functions Convert aggregate functions Convert mathematical functions Convert string function syntax Convert other unsupported Oracle functions Macros Convert ISOPEN, NOT FOUND, ROWTYPE, and TYPE macros Pseudo-Columns Convert Level processing Convert Rownum processing Update Using Cursors Convert WHERE CURRENT OF processing for multiple table joins Convert FOR UPDATE with a HOLD cursor processing Convert concurrency processing from Oracles implicit to Informixs explicit System Tables Convert system table references
1 2 2 4 3 2 1 5 5 5 3 5 1 5 3 3 2 5 2 4 1
Tasks
Stored procedures Break stored procedures greater than 64K in size into smaller ones Convert Oracles stored procedure packages Convert exception processing Convert error handling (SQLCA) Convert Oracles global cursor processing Convert Oracles explicit cursor processing Convert flow control processing Convert Oracles implicit variable declaration and assignment Convert Oracles BOOLEAN variable type Convert binary data type processing Convert Oracles dynamic SQL processing Triggers Convert multi-functional triggers Convert Insert and Update triggers which are not supported in Informix Place logical statements in a stored procedure Constraints Convert constraint enabling and disabling processing DUAL table Convert Dual table processing
Quantity
Effort
2 3 5 2 5 2 5 3 1 5 3 5 5 5 4
Embedded SQL
Host variables
Version 1.6
80
Convert declaration overrides Convert array processing Convert Oracles formatting functions SQL structures Convert SQLDA processing Convert ORACA processing Pre-compiler options Convert Oracle pre-compiler options Embedded PL/SQL Convert Oracles Embedded PL/SQL ODBC Convert Oracles OCI Convert database library calls Convert global area processing Convert fetch cycle Convert RAW data type processing Convert parameter bindings Embedded SQL for C Convert VARCHAR processing Embedded SQL for COBOL Convert VARCHAR processing Convert 88 Level processing in COBOL Convert Redefine processing in COBOL
1 5 4 5 1 1 5 5
2 2 2 4
Tasks
Quantity
Effort
Application architecture
Transaction processing Convert application to Informix transaction processing Convert multiple connect processing Convert savepoints Concurrency Address Informix locking processing User authentication Address Informix security processing 5 5 n/a n/a 2 4
Environment
Convert make files Convert shell scripts, shell startup scripts, and command files Convert script substitution variables 2 2
Version 1.6
81
A P P E N D I X B:
Syntax comparison
Oracle Informix AND NOT OR >= <= <> or != letters, numbers, and _ CHAR CHAR or TEXT SMALLINT INTEGER DECIMAL BYTE, TEXT, CLOB, BLOB --, { } LET var1 = expression ELSE or ELIF IF AVG(expression), AVG(ALL expression), AVG(DISTINCT column_name), AVG(UNIQUE column_name) COUNT(*), COUNT(DISTINCT column_name), COUNT (UNIQUE column_name) MAX(expression), MAX(ALL expression), MAX(DISTINCT column_name), MAX(UNIQUE column_name) MIN(expression), MIN(ALL expression), MIN(DISTINCT column_name), MIN(UNIQUE column_name) SUM(expression), SUM(ALL expression), SUM(DISTINCT column_name), SUM(UNIQUE column_name) ROUND(expression,rounding factor) STDDEV(expression) VARIANCE(expression) RANGE(expression)
See the Informix Guide to SQL: Syntax for more information on each item.
Boolean AND NOT OR Greater Than or Equal To Less Than or Equal TO Not Equal Identifiers Data types Character Long Character Number (2 bytes) Number (4 bytes) Number (> 4 bytes) Image DML Comments Assignment Condition Aggregate functions Average
AND NOT OR >= <= <>, !=, or ^= letters, numbers,_,$,# CHAR VARCHAR (2000) if <= 2000 LONG VARCHAR if > 2000 NUMBER NUMBER NUMBER LONG RAW, CLOB, BLOB --, /* */ var1 := expression ELSE IF AVG(expression), AVG(ALL expression), AVG(DISTINCT expression) COUNT(*), COUNT (expression), COUNT(ALL expression), COUNT (DISTINCT expression) MAX(expression), MAX(ALL expression), MAX(DISTINCT expression) MIN(expression), MIN(ALL expression), MIN(DISTINCT expression) SUM(expression), SUM(ALL expression), SUM(DISTINCT expression) ROUND(expression,rounding factor) STDEV(expression) VARIANCE(expression) ?
Count
Maximum
Minimum
Sum
Version 1.6
82
String functions Trim Length Like Like (single character) Like (wildcard) String Delimiter Escape Character Stored procedures Create
LTRIM(expression) RTRIM(expression) LENGTH(string) LIKE(string) _ % or set within LIKE clause using ESCAPE ? to make ? the escape character CREATE OR REPLACE PROCEDURE procedure_name (var1 IN CHAR(1), var2 OUT DATE, var3 IN OUT NUMBER); EXECUTE PROCEDURE procedure_name (var1 IN, var2 OUT, var3 IN OUT);
LTRIM(expression) RTRIM(expression) LENGTH(string) LIKE(string) _ % or \ or set within LIKE clause using ESCAPE ? to make ? the escape character DROP PROCEDURE procedure_name; CREATE PROCEDURE procedure_name (var1 CHAR(1), var3 INTEGER) RETURNING DATE, INTEGER; EXECUTE PROCEDURE procedure_name (var1, var3) RETURNING var2, var3;
Arguments
Version 1.6
83
A P P E N D I X C:
Database concepts
Informix Specific database name Chunk Dbspace Extent Physical Log Logical Log Root dbspace Temporary dbspaces, dbspacetemp environment variable, or dbspacetemp onconfig parameter Blobspace, Sbspace table fragmentation Not supported Not supported finderr utility onstat and oncheck utilities dbaccess utility ESQL/C ESQL/COBOL INet Like the ESQL function library after precompiling, if they were publically documented. COMMITTED READ LAST COMMITTED
The table below illustrates the relationship between each database vendors database objects.
Oracle Database name attached to a group of files Data file Tablespace (logical partition) or Segments (Index Segment, Table Segment and so on) Extent Rollback Segment Redo Log System tablespace Temporary tablespace Pointer Table partitioning Database link Snapshot oerr utility sqldba and svrmgrl - monitor utilities SQLPlus utility Pro*C Pro*COBOL SQL*NET OCI Read Consistency
Version 1.6
84
A P P E N D I X D:
Sample code
CONCAT
CREATE PROCEDURE concat (str1 VARCHAR(255), str2 VARCHAR(255)) RETURNING VARCHAR(255); RETURN str1 || str2; END PROCEDURE;
INSTR
CREATE PROCEDURE instr( str VARCHAR(255), mask VARCHAR(255), strt SMALLINT DEFAULT 1, occur SMALLINT DEFAULT 1 ) RETURNING INT; DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE DEFINE LET LET LET LET LET LET LET LET LET slen SMALLINT; mlen SMALLINT; tempstr VARCHAR(255); tempmask VARCHAR(255); nomatch SMALLINT; count SMALLINT; pos SMALLINT; retpos SMALLINT; i SMALLINT; j SMALLINT; srchstrt SMALLINT; = = = = = = = = = LENGTH(str); LENGTH(mask); 0; 0; 1; 1; ''; ''; strt;
IF (strt < 0) THEN - reverse the str FOR i = 1 TO slen LET tempstr = str[1,1] || tempstr; LET str = str[2,255]; END FOR; -- reverse the mask FOR i = 1 TO mlen LET tempmask = mask[1,1] || tempmask; LET mask = mask[2,255]; END FOR;
Version 1.6
85
LET srchstrt = strt * -1; LET str = tempstr; LET mask = tempmask; END IF; FOR j = 1 TO slen LET tempstr = str; LET tempmask = mask; FOR i = 1 TO mlen IF (tempmask[1,1] != tempstr[1,1]) THEN LET nomatch = 1; EXIT FOR; END IF; LET tempmask = tempmask[2,255]; LET tempstr = tempstr[2,255]; END FOR; IF (nomatch = 0) THEN IF (pos >= srchstrt) THEN LET count = count + 1; END IF; IF (count = occur) THEN IF (strt < 0) THEN RETURN slen - pos + 1; ELSE RETURN pos; END IF; END IF; END IF; LET str = str[2,255]; LET nomatch = 0; LET pos = pos + 1; END FOR; RETURN 0; END PROCEDURE;
YYYYMMDD
CREATE PROCEDURE yyyymmdd (str VARCHAR(10)) RETURNING varchar(8); DEFINE retstr VARCHAR(8); IF str IS NULL THEN RETURN NULL; ELSE LET retstr = str[7,10] || str[1,2] || str[4,5]; RETURN retstr; END IF; END PROCEDURE;
Version 1.6
86
Using EXEC
Note the ROW data type variable can be referenced using table and column syntax. CREATE PROCEDURE example1() RETURNING INTEGER DEFINE sql_stmt LVARCHAR(255); DEFINE rcnt ROW(val INTEGER); LET sql_stmt = "select count(*) from items where manu_code = ANZ"; EXECUTE FUNCTION EXEC(sql_stmt) INTO rcnt; RETURN rcnt.val; END PROCEDURE;
Using EXEC_FOR_ROWS
CREATE PROCEDURE example2() RETURNING INTEGER, CHAR(1) DEFINE rs_rowdata ROW(customer_num INTEGER, call_code CHAR(1)); DEFINE sql_stmt LVARCHAR(255); LET sql_stmt = "select customer_num, call_code from cust_calls where customer_num = 106"; FOREACH EXECUTE FUNCTION EXEC_FOR_ROWS(sql_stmt) INTO rs_rowdata RETURN rs_rowdata.customer_num, rs_rowdata.call_code WITH RESUME; END FOREACH; END PROCEDURE;
Using EXEC_FOR_MSET
Note the DEFINE statement for the variable rs_data. Collection data types used in a SPL routine cannot be defined using the LIKE attribute in the DEFINE statement. CREATE PROCEDURE example3() RETURNING INTEGER, VARCHAR(8) DEFINE v_customer_num LIKE accounts.customer_num; DEFINE v_account_cd LIKE accounts.account_cd; DEFINE rs_data MULTISET(ROW( r_customer_num INTEGER, r_account_cd VARCHAR(8)) NOT NULL); DEFINE sql_stmt LVARCHAR; LET sql_stmt = "select customer_num, order_num from orders where company_id = 51155"; EXECUTE FUNCTION EXEC_FOR_MSET(sql_stmt) INTO rs_data; FOREACH SELECT r_customer_num, r_account_cd INTO v_customer_num, v_account_cd FROM TABLE(rs_data) RETURN v_customer_num, v_account_cd WITH RESUME; END FOREACH; END PROCEDURE;
Version 1.6
87
Date arithmetic
Informix has extensive capabilities for manipulating dates and times. You can add or subtract DATE and DATETIME variables from each other. You can add or subtract an INTERVAL to a DATE or DATETIME.
UNITS Keyword
When working with INTERVAL values, sometimes it is necessary to specify the precision with which you are dealing. For example, suppose you have the following field defined: To add 10 days to the lead time you could use a SQL statement like this: SELECT lead_time + INTERVAL(10) DAY to DAY FROM orders -orSELECT lead_time + 10 UNITS DAY FROM orders
Within SPL routines, you can use the DBINFO function to find out the number of rows that have been processed in SELECT, INSERT, UPDATE, DELETE, EXECUTE PROCEDURE, and EXECUTE FUNCTION statements. CREATE FUNCTION del_rows(pnumb INT) RETURNING INT; DEFINE nrows INT; DELETE FROM sec_tab WHERE part_num = pnumb; LET nrows = DBINFO('sqlca.sqlerrd2'); RETURN nrows; END FUNCTION; To ensure valid results, use this option after SELECT and EXECUTE PROCEDURE or EXECUTE FUNCTION statements have completed executing. If you use the 'sqlca.sqlerrd2' option within cursors, make sure that all rows are fetched before the cursors are closed.
This function will receive the COLLECTION list of values from func1: CREATE FUNCTION func2() RETURNING INTEGER --- DEFINE lmset MULTISET(INTEGER NOT NULL); -DEFINE lmset COLLECTION; DEFINE v_int INTEGER; --- call func1 to populate local multiset variable -LET lmset = func1(); --- tally a count the number of elements -FOREACH SELECT COUNT(*) INTO v_int FROM TABLE(lmset)
Version 1.6
89
IBM Software Group RETURN v_int WITH RESUME; END FOREACH; --- return the values -FOREACH SELECT * INTO v_int FROM TABLE(lmset) RETURN v_int WITH RESUME; END FOREACH; END FUNCTION;
NOTE: In the example func2, a duplicate declaration for the lmset variable as a MULTISET data type has been commented out, by declaring the variable as a COLLECTION it can accept any of the 3 types (MULTISET, SET and LIST). When executing the function, the resulting expression will be: EXECUTE FUNCTION func2(); (expression) 4 (row count) 1 2 5 4 By using a SET data type, inserts will not permit duplicates: CREATE FUNCTION func1() RETURNING SET(INTEGER NOT NULL) DEFINE v_array_of_ints SET(INTEGER NOT NULL); INSERT INTO TABLE (v_array_of_ints) VALUES(1); INSERT INTO TABLE (v_array_of_ints) VALUES(2); INSERT INTO TABLE (v_array_of_ints) VALUES(2); INSERT INTO TABLE (v_array_of_ints) VALUES(5); INSERT INTO TABLE (v_array_of_ints) VALUES(5); INSERT INTO TABLE (v_array_of_ints) VALUES(5); INSERT INTO TABLE (v_array_of_ints) VALUES(5); INSERT INTO TABLE (v_array_of_ints) VALUES(5); RETURN v_array_of_ints; END FUNCTION;
NOTE: Because func2 is expecting a un-typed COLLECTION variable func1 does not have to be dropped and recreated. It can receive a value from any Collection Data Type (MULITSET, SET and LIST). The functions return values would change to: (with duplicates suppressed) EXECUTE FUNCTION func2(); (expression) 3 (row count) 1 2 5
Using a LIST data type, support for assigning values based on ordinal position:
Version 1.6
90
CREATE FUNCTION func1() RETURNING LIST(INTEGER NOT NULL) DEFINE v_array_of_ints LIST(INTEGER NOT NULL); --- first insert no ordinal position can be established, By default, the -- database server inserts LIST elements at the end of the list. -INSERT AT 5 INTO TABLE (v_array_of_ints) VALUES(5); INSERT AT 1 INTO TABLE (v_array_of_ints) VALUES(1); INSERT AT 2 INTO TABLE (v_array_of_ints) VALUES(2); --- Only 3 LIST elements exist, position 4 has not been instantiated -- this element will insert at the end of the list -INSERT AT 4 INTO TABLE (v_array_of_ints) VALUES(4); INSERT AT 3 INTO TABLE (v_array_of_ints) VALUES(3); RETURN v_array_of_ints; END FUNCTION; NOTE: The elements of a LIST have ordinal positions; with a first, second, and third element in a LIST. To support the ordinal position of a LIST, the INSERT statement provides the AT clause. This clause allows you to specify the position at which you want to insert a list-element value. Note the behavior of the ordinal positioning above preceded by a commented explanation. When executing the function, the resulting expression will be: EXECUTE FUNCTION func2(); (expression) 5 (row count) 1 2 3 5 4
Using MULTISET and ROW to replace PL/SQL TABLE and RECORD types
Creating variables using Informix Collection data types SET, MULTISET and LIST in combination with ROW data types can be useful when migrating applications which use Oracle REF CURSORS as arguments to functions as well as Oracle collection data types TABLE and RECORD. Typical Oracle Package specification: CREATE OR REPLACE PACKAGE MyPackage IS TYPE recOrders IS RECORD ( order_num orders.order_num%TYPE, order_date orders.order_date%TYPE, customer_num orders.customer_num%TYPE, po_num orders.po_num%TYPE ); TYPE tabOrders IS TABLE OF recOrders INDEX BY BINARY_INTEGER; TYPE ref_curtype IS REF CURSOR; Both tabOrders or ref_curtype can be converted to the following Informix SPL definition: DEFINE tabOrders MULTISET(ROW(
Version 1.6
91
order_num INTEGER, order_date DATETIME YEAR TO FRACTION(3), customer_num INTEGER, po_num CHAR(10)) NOT NULL); DEFINE ref_curtype MULTISET(ROW( { define columns based on query result set} ) NOT NULL);
Version 1.6
92
A P P E N D I X E:
Counting system
objects
Using the system catalog
System catalog
Below is a list of SQL statements that will extract most, if not all, of the counts of system objects owned by user XXX. select count(table_name) from all_tables where owner=xxx; select count(*) from dba_indexes where owner=xxx; select count(synonym_name) from dba_synonyms where owner=xxx; select count(*) from dba_views where owner=xxx; select count(*) from dba_tab_columns where length(column_name)>18 and owner=xxx; select count(*) from dba_tab_columns and owner=xxx; select count distinct(*) from dba_tab_columns and owner=xxx; select count(*) from dba_tables where length(table_name)>18 and owner=xxx; select count(*) from dba_synonyms where length(synonym_name)>18 and owner=xxx; select count(*) from dba_views where length(view_name)>18 and owner=xxx; select count(*) from dba_indexes where length(index_name)>18 and owner=xxx; select count(*) from dba_tab_columns where data_type=varchar2 and owner=xxx;
Version 1.6
93
select data_type, count(data_type) from dba_tab_columns where owner=xxx group by data_type; select count(*) from dba_tab_columns where data_type=varchar2 and length(data_type)>254 and owner=xxx; select count(*) from dba_tab_columns where data_type=number and data_scale=0 and owner=xxx;
Version 1.6
94
IBM Software Group cot( degrees( floor( radians( rand( sign( to_char( to_date( to_number( exception( pi( raise_application_error( raiserror( SQLCODE rollback savepoint /\* declare decode( nvl( print( rowid waitfor recompile bcp %isopen( %notfound( %rowtype( %type(
Then, please run the following program with the proper subdirectories: #! /bin/ksh rm f /somehome/*.outfile cd /somesource/database export sourcebase=somepath for functor in `cat /tmp/function_list` do echo before find $functor find /$sourcebase/database -exec grep -i $functor {} \; >> /somehome/$functor.outfile find /$sourcebase/intfc -exec grep -i $functor {} \; >> /somehome/$functor.outfile echo after find $functor done
Version 1.6
95
echo "Usage: objCounts.sh \"<FilePattern>\"" return 1; fi declare -a objectTypes=('CLUSTER' 'CONTEXT' 'CONTROLFILE' 'DATABASE' 'DATABASE +LINK' 'DIMENSION' \ 'DIRECTORY' 'DISKGROUP' 'FUNCTION' 'INDEX' 'INDEXTYPE' 'JAVA' 'LIBRARY' 'MATERIALIZED +VIEW' \ 'MATERIALIZED +VIEW +LOG' 'OPERATOR' 'OUTLINE' 'PACKAGE' 'PACKAGE +BODY' 'PFILE' 'PROCEDURE' 'PROFILE' \ 'RESTORE +POINT' 'ROLE' 'ROLLBACK +SEGMENT' 'SCHEMA' 'SEQUENCE' 'SPFILE' 'SYNONYM' 'TABLE' 'TABLESPACE' \ 'TRIGGER' 'TYPE' 'TYPE +BODY' 'USER' 'VIEW'); echo for type in "${objectTypes[@]}" do if [ "$type" = "PROCEDURE" ]; then echo $type " object count: " `cat $1 | grep -icE "^ *(|CREATE +|OR REPLACE +)\b$type\b"` else echo $type " object count: " `cat $1 | grep -icE "^ *(CREATE +|OR +REPLACE +)\b$type\b"` fi done
Version 1.6
96
A P P E N D I X F:
Oracle built-in data types (including ANSI types) can be converted to similar data types in the Informix database, according to the mapping described here. This table provides default mappings based on most common usage patterns; in some cases another mapping may work better. In the following table n is used to indicate length, p is used to indicate precision, and s is used to indicate scale. Oracle data type BFILE LONG RAW BLOB BINARY_DOUBLE BINARY_FLOAT BINARY_INTEGER PLS_INTEGER NATURAL NATURALN POSITIVE POSITIVEN 32-bit integers; only used in PL/SQL. NATURAL and POSITIVE are unsigned integers. BOOLEAN (PL/SQL only) CHAR(n) or CHARACTER(n) DATE BOOLEAN CHAR(n) DATETIME YEAR TO SECOND DOUBLE PRECISION BLOB Informix Server data type
DOUBLE PRECISION
Version 1.6
97
FLOAT See note on FLOAT below. INTEGER INT A 38-digit NUMBER sub-type. May want to flag with a warning on possible overflow. INTERVAL DAY(p) TO SECOND(s) Note: Oracle fractional seconds have 9 digits. INTERVAL YEAR(p) TO MONTH LONG CLOB LONG VARCHAR (xxx) Oracle recommends not using this type. NCHAR(n) NATIONAL CHAR(n), or NATIONAL CHARACTER(n) NCLOB NUMBER NUMBER(*,0) NUMBER(p) NUMBER(p, s) Where scale (s) is less than 0 (that is, s < 0), and p-s < 10. NUMBER(3,-2): 12300
FLOAT
INTEGER
CLOB
LVARCHAR
Version 1.6
98
NUMBER(p) NUMBER (p,0) Where precision (p) is greater than or equal to 10 and <= 18. NUMBER(p, s) Where scale (s) is less than 0 (that is, s < 0), and 10 <= p-s < 19. NUMBER(9,-2): 12345678900 NUMBER(p, s) Where scale (s) is greater than 0 and precision (p) is greater than or equal to s (that is, s > 0 and p >= s). NUMBER(p, s) Where scale (s) is greater than 0 and precision (p) is less than s (that is, s > 0 and p < s). NUMBER(3,5): 0.00123 NUMBER(p, s) Where scale (s) is less than 0 (that is, s < 0), and p-s > 18 and p-s <= 32.
BIGINT
NUMERIC (min(s,32),min(s,32))
NUMERIC (min(p-s,32),0)
NUMBER(p, s)
NUMERIC (32)
Scale cannot be greater than precision. Where scale (s) is greater than 32, or pInformix-s is greater NUMERIC(32,32) would guarantee that than 32. digits to the left of the decimal would be lost. Using a floating point decimal provides the simplest, best way to capture as many digits in a value as possible.
Version 1.6
99
DEC DECIMAL NUMERIC DEC(p) DECIMAL(p), NUMERIC(p), DEC(p, s) DECIMAL(p, s) NUMERIC(p, s) NVARCHAR2(n) NCHAR VARYING(n) NATIONAL CHAR VARYING(n) NATIONAL CHARACTER VARYING(n) RAW(n) REAL Record
There is no difference within Oracle between these types and each other and these types and NUMBER. The Oracle system catalogs contain the NUMBER type id for all declarations of these types, and the integer types as well. Declarations of these types can be mapped using the same rules as those for NUMBER.
LVARCHAR(min(n, 32767))
INTEGER
Version 1.6
100
VARCHAR2(n) VARCHAR(n) CHAR VARYING(n) CHARACTER VARYING(n)2 Where number (n) is less than or equal to 255 (that is, n <= 255). VARCHAR2(n) VARCHAR(n) CHAR VARYING(n) CHARACTER VARYING(n)2 Where number (n) is greater than 255 (that is, n > 255). XMLType
Notes on specific types are below.
VARCHAR(n)
LVARCHAR(n)
CLOB
DOUBLE
The range of values for the DOUBLE PRECISION data type is the same as the range of the C double data type on your computer.
VARCHAR
While Oracle VARCHAR data types have a limit of 4000 bytes, an Informix Server VARCHAR data types has a limit of 255 bytes. An Informix Server LVARCHAR has a limit of 32,739 Bytes.
NUMBER
Oracle abstracts its numeric types from the hardware and operating system through the use of its NUMBER type. Most numeric types, like INTEGER, are actually NUMBERs internally. When porting to a database server like Informix which retains more of a relationship between the operating system types and the database types, it is essentially a one-to-many mapping, and heuristics have to be used to determine the best-fit target type. No single set of type mapping rules will fit all use scenarios. The converter has default rules which fit the more common user patterns. When considering a number represented as mantissa and exponent, mantissa x 10
exponent
precision is the number of digits in the mantissa, and scale is the negative exponent, how many places to the right of the decimal point the least significant digit is located. Oracle NUMBERs have a maximum precision of 38 and the maximum precision available in Informix native types is 32. The first step in a type mapping is to truncate the target type precision to min(precision, 32). The scale of a type can be considered its anchor point with respect to the decimal point. The most
Version 1.6
101
significant digit of a numeric type is located precision digits to the left of the decimal point and precision-scale digits to the right of the decimal point. The start and end locations of the digits are used to determine the closest fitting Informix type. The order of preference is INTEGER, BIGINT, NUMERIC(p, s), and lastly, NUMERIC(p). NUMERIC(p) in a non-ANSI mode database is a decimal type with a floating point type. In an ANSI mode database, the scale is implicitly 0. All Oracle integer declaration types, such as INT, INTEGER, SMALLINT become NUMBER(38) type in the Oracle metadata. In Oracle, when precision is given, but scale is not, scale becomes 0 implicitly, which makes the type in the set of integral types. One exception to the general mapping rules is the NUMBER type specified without precision or scale. Strictly speaking, this has a floating point scale with 38 digits of precision, but most commonly it is used where an integer is more appropriate. Even if the user does specify INTEGER in a type definition, when it comes out of the Oracle catalogs, the type is NUMBER. This is one case in particular where one type mapping will not fit well with all usage scenarios.
ROWID
Oracle databases support a pseudo-column named ROWID, such that every row in every table is assigned an auto-generated ID. Oracle also allows you to define a column of type ROWID, which can be used as a foreign key to a ROWID pseudo-column. Oracle ROWID columns contain data that if converted to a string are 18 characters long, for example AAAQ+jAAEAAAAAeAAN. It is probably not advisable to migrate this data to an Informix database, and instead use the Informix type, which is an integer. If there is a dependency on the values themselves, and therefore need migrate the data, then an integer type would not hold the values.
%TYPE
In PL/SQL, you can refer to the type of an existing variable, field, or column by using the %TYPE attribute. The converter replaces this reference directly by the type it refers to.
%ROWTYPE
In PL/SQL, you can refer to the record type that represents a row of a table, a cursor, or a cursor variable. PL/SQL scripts containing the %ROWTYPE attribute are handled in the same way as a record type that has been previously declared.
FLOAT
Oracle FLOAT type is a floating point number capable of storing up to 38 decimal digits, or 126 binary digits. It has a floating point scale that can exist outside the boundaries of what an Informix DECIMAL can represent. A C language double, or Informix float type is capable of only 16 digits; so, there is the chance that some data will be lost. Using an Informix FLOAT type makes it so that less significant digits are lost in preference to more significant digits.
Version 1.6
102
References to subtypes declared in packages and PL/SQL blocks are converted to the Informix Server equivalent base types. Variables of type RECORD are not translated by the DDL Converter at the time of this writing. They will be handled by the stored procedure converter.
XMLType
Informix does not have a built-in type for representing XML. The nearest approximation is to store it in a CLOB. Another character type, like LVARCHAR, can be used if it can be determined that the actual data will fit in it.
Version 1.6
103