Newsletters   Subscriptions  Forums  Store  Media Kit  About Us  Contact  Search   Home 
fhg
Volume 4, Number 8 -- March 17, 2004

Using 'New' SQL Data Types in RPG


by Raymond Everhart

As RPG programmers, we have become very comfortable with character, zoned, and packed decimal data types. Occasionally, when dealing with APIs or subprocedures, we’ve been forced to dabble with binary numbers or variable length strings. More recently some of us have started taking advantage of the strengths of the date, time, and timestamp data types supported in RPG IV. And just when we think we’ve got it all covered, we find out that DB2 supports even more data types.

DB2 supports data types that are seldom used by iSeries programmers. However, since C or Java programmers may create tables (or files) on the iSeries, we need to know how to interact with these data types.

The following tables list the data types that can be used in DB2 on the iSeries.


Numeric Data Types Min Value Max Value Bytes of Storage Used
Small Integer -32,768 32,767 2
Integer -2,147,483,648 2,147,483,647 4
Big Integer -9,223,372,036,854,775,808 9,223,372,036,854,775,807 8
Decimal -1031 + 1 1031 - 1 Up to 16
Numeric -1031 + 1 1031 - 1 Up to 31
Float(Single Precision) 1.17549436 x 10-38 3.40282356 x 1038 4
Float(Double Precision) 2.2250738585072014 × 10-308 1.7976931348623158 x 10308 8


String Data Types Description Max Length
Char Fixed Length Character Data 32,766
VarChar Variable Length Character Data 32,740
CLOB Character Large Object String 15,728,640
Graphic Fixed Length Graphic String 16,383
VarGraphic Variable Length Graphic String 16,370
DBCLOB Double Byte Character Large Object String 7,864,320
BLOB Binary Large Object String 15,728,640


Date/Time Data Types Contents Limits Bytes of Storage Used
Date 3 part value: Year, Month and Day If the date format *JUL, *MDY, *DMY, or *YMD is used, the year part of the value can only represent dates in the range 1940 through 2039. 4
Time 3 part value: Hour, Minutes and Seconds 0 3
TimeStamp 7 part value: Year, Month, Day; Hours, Minutes, Seconds, Microseconds 0 10

Now that we know just how much we don't know, let's look at how to define these data types in RPG and how to convert to and from these data types using SQL scalar functions.


DEFINING SQL DATA TYPES IN RPG


Let me start by saying that the SQL precompiler does a lot of the hard work for you. When you use embedded SQL to put data into your application, you must define "host variables" to contain the values selected in your SQL statement. When using native I/O, coding an F-spec adds the fields and their definitions into the program, during the compile process. Embedded SQL does not require an F-spec. Instead, host variables are defined in D-specs, like any other variable in RPG. Host variables can be defined as stand-alone fields, data structures, externally described data structures or multiple occurrence data structures.

In the example below, a single host variable has been defined. When the SQL statement runs, the number of records in the QADBXREF file will be placed into the variable RecordCount. In this case, RecordCount is defined as a packed decimal value with a precision of 9,0.

.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
     D RecordCount     S              9  0

     C/Exec SQL
     C+ Select Count(*) into :RecordCount from QADBXREF
     C/End-Exec

Now let's make a change. Notice that the RecordCount variable is now defined as a zoned decimal value with a precision of 7,0. This code will also work just fine.

.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
     D RecordCount     S              7S 0

     C/Exec SQL
     C+ Select Count(*) into :RecordCount from QADBXREF
     C/End-Exec

Now the RecordCount variable is defined as a four-byte Integer. This code will also work.

.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
     D RecordCount     S              5I 0

     C/Exec SQL
     C+ Select Count(*) into :RecordCount from QADBXREF
     C/End-Exec

The point that I am trying to make is that if the data types are not the same, the program will work to convert the value correctly, if possible. The data types do not have to be the same, but they do need to be compatible. If the value of one data type can be assigned to another without the use of a scalar function, the data types are compatible. For example, a small integer value can be assigned to a decimal variable, a character value can be assigned to a character large object, and a correctly formatted character value can be assigned to a date variable. Just like in RPG, you can add a zoned decimal to an integer and store the results in a packed decimal field. You don't have to worry about the differences; RPG will handle all of the data type conversions necessary. So if a column in your table is defined as numeric, but you define it as an integer in RPG, the conversion will be handled automatically. The most important thing to watch for is that you keep data from being truncated as it moves from one data type to another.

The source code listed below shows a sample RPG definition for each SQL data type. Care should be taken not to exceed the maximum length, as shown in the table above, or change the lengths of the integer or float data types. Large objects require the SQLTYPE keyword, which is processed by the SQL precompiler.

.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords

      * Numeric Definitions
     D SmallInteger    S              5I 0
     D SmallInteger    S              4B 0
     D Integer         S             10I 0 
     D Integer         S              9B 0
     D BigInteger      S             20I 0
     D Decimal         S             31P 9
     D Numeric         S             31S 9
     D Float_Single    S              4F 
     D Float_Double    S              8F

      * Character Definitions
     D Char            S          32766A
     D VarChar         S          32740A   Varying

      * Graphic Data Definitions
     D Graphic         S          16383G
     D VarGraphic      S          16370G   Varying

      * Large Object Definitions
     D CLOB            S                   SQLTYPE(CLOB:500)
     D DBCLOB          S                   SQLTYPE(DBCLOB:500)
     D BLOB            S                   SQLTYPE(BLOB:500)

      * Date/Time Definitions
     D Date            S               D
     D Time            S               T
     D TimeStamp       S               Z

For performance reasons, it makes sense to avoid unnecessary data type conversions, but the system will convert compatible data types nonetheless.


CHANGING BETWEEN DATA TYPES IN SQL


It seems as if programmers spend a lot of their time changing data from one type to another. A value stored as a number is converted to a date, an invoice amount is converted to a character string, so it can be inserted into a body of text, and on and on. SQL has built-in functions to accomplish these tasks as well. These functions allow you to control the length, precision, and data type of your results. The rest of this article examines the use of scalar functions to convert between data types. However, another option is available within SQL. The CAST expression lets you perform the same data type conversions as individual scalar functions. Once you master the scalar functions, you can decide which you prefer.


CONVERTING TO CHARACTER DATA


The first method of converting data to the character data type is the CHAR() function. The results of the CHAR() function depend on the data type being converted.

The CHAR() function will convert the following:


Character data to character Char (character expression, length)
Integer data to character Char (integer expression)
Decimal data to character Char (decimal expression, decimal character)
Float data to character Char (float expression, decimal character)
Date/Time data to character Char (date time expression, format)

The table below shows the resulting length of the Char() function based on the source data type.


Source

Source

Data Type

Comments

Length of

Result

Character

The result is a character string of the length specified in the second argument.  If the second argument is not specified, the resulting string is the same length as the source string.

 

Small Integer

Fixed length.

Preceding minus sign if negative.

Left justified.

No leading zeros.

Padded on the right with blanks

6

Integer

11

Big Integer

 

20

Decimal

Variable Length

Preceding minus sign if negative.

Left justified.

No leading zeros.

If the value is positive, there will be one trailing blank.

The decimal character can be a period or a comma and is specified on the second argument.

 

 

Precision of source value

+ 2

Float

Fixed length.

Preceding minus sign if negative.

If the value is zero, the returned string is 0E0.

The smallest number of digits/characters possible is

     used to represent the value.

Padded on the right with blanks.

 

 

24

Date

The format and separator are determined by the second argument of the function.  If no format is specified, the value of the DATFMT and DATSEP parameters is used.

 

ISO, USA, EUR,or JIS date format

10

YMD, MDY, or DMY date format

6

Time

The format and separator are determined by the second argument of the function.  If no format is specified, the value of the TIMFMT and TIMSEP parameters is used. 

 

8

TimeStamp

The second argument is not allowed when converting this data type.

26

 

 

 

 


The table below shows some samples of the CHAR() function.


Source

Source

Data Type

Source Data

CHAR() statement

Result

Character

Name = 'Dr. Suess'

Char(Name,5)

'Dr. S'

 

Char('I like ' + Name,20)

'I like Dr. Suessbbbb'

Small Integer

Sm_Int = 45

Char(Sm_Int)

'45bbbb'

Integer

Int = -654321

Char(Int)

'-654321bbbb'

Big Integer

Big_Int = 32468465654005

Char(Big_Int-5)

'32468465654000bbbbbb'

Decimal

Num1 = 36.68

Char(Num1)

'36.68b'

Num2 = -1254.996

Char(Num2,',')

'-1254,996'

 

Char(10000.00-99865)

'135.00bbb'

Float

Double = -987.654321E-35

Char(Double)

'-9.8765432100000002E-33 '

Date

InvDate = 2003-05-22

Char(InvDate, USA)

'05/22/2003'

Char(InvDate, YMD)

'03/05/22'

Time

ChgTime = 09.25.01

Char(ChgTime,USA)

'9:25 AMb'

TimeStamp

 

Char(InvDate+ChgTime)

'2003-05-22-09.25.01.000000'

 


Another function for converting to character data is the DIGITS() function. The DIGITS() function works with integer and decimal data types only. The value returned is an absolute value that is right-justified with leading zeros and no decimal separator. This function works well when you are formatting a "flat file" for export or when you want to append a sequence number to a character value. There is no equivalent CAST expression for the DIGITS() function. The following table shows the length and sample uses of the DIGITS() function.


Source

Source

Data Type

Source Data

DIGITS() statement

Length

Result

Small Integer

Sm_Int = 45

Digits(Sm_Int)

5

'00045'

Integer

Int = -654321

Digits(Int)

10

'0000654321'

Big Integer

Big_Int = 32468465654005

Digits(Big_Int-5)

19

'0000032468465654000'

Decimal

Num1 = 36.68

Digits(Num1)

Precision

of Source value

'3668'

Num2 = -1254.996

Digits(Num2)

'1254996'

 

Digits(10000.00-99865)

'0013500'

 



CONVERTING TO DATE/TIME DATA TYPES


The DATE() function returns a date from a value. The value supplied to the DATE() function can be represented in a number of ways. The value can be a timestamp, a date, a positive number, or a string. If the value supplied is a timestamp, the returned value is the date portion of the timestamp. If the supplied value is a date, then that date is returned. If the value supplied is a number, it must represent the number of days after January 1, 0001. If the value supplied is a string, it must be a valid date string or a seven-character numeric string in the form yyyynnn; where yyyy is the year and nnn is the number of days (1-366) since the beginning of the year.


DATE() EXAMPLES



Constants

Constants

Format

Date() statement

Result

Chg_Date = '2004-11-25'

Rec_Date = '2003-05-22-09.25.01.000000'

 

Date

Date(Chg_Date)

2004-11-25

TimeStamp

Date(Rec_Date)

2003-05-22

Numeric

Date(731885)

2004-10-31

USA

Date('12/05/2001')

2001-12-05

ISO

Date('2004-11-01')

2004-11-01

EUR

Date('22.09.1998')

1998-09-22

yyyynnn

Date('2000214')

2000-08-01

 

The TIME() function returns a Time value from a value. The value supplied to the TIME() function can also be represented in a number of ways. The value can be a TimeStamp, Time, or string. If the value supplied is TimeStamp, the returned value is the time portion of TimeStamp. If the supplied value is a time, that time is returned. If the value supplied is a character string, that string must be a valid representation of a time value.

TIME() Examples

Constants

Constants

Format

Time() statement

Result

Chg_Date = '2004-11-25'

Chg_Time= '13.22.05'

Rec_Date = '2003-05-22-09.25.01.000000'

 

Time

Time(Chg_Time)

13.22.05

TimeStamp

Time(Rec_Date)

9.25.01

USA

Time('01:05 PM')

13.05.00

ISO

Time('18.11.59')

18.11.59

EUR

Time('18.11.58')

18.11.58

JIS

Time('16:42:46')

16.42.46

 


The TIMESTAMP() function returns a timestamp from a value. The TIMESTAMP function can accept one or two arguments. If only one argument is specified, it must be a timestamp or a 14-character representation of a timestamp. The format for the 14-character string is yyyyMMddhhmmss, where yyyy is for the year, MM is for the month, dd is for the day, hh is for the hour, mm is for the minute, and ss is for the number of seconds. If two arguments are specified, the first value must be a date or a character representation of a date value and the second value must be a date or a character representation of a time value.


TIMESTAMP() Examples


Constants

Constants

Format

Date() statement

Result

Chg_Date = '2004-11-25'

Chg_Time= '13.22.05'

Rec_Date =

'2003-05-22-09.25.01.000000'

TimeStamp

TimeStamp(Rec_Date)

2003-05-22-09.25.01.000000

Character

TimeStamp('20040522135204')

2004-05-22-13.52.04.000000

 

TimeStamp(Chg_Date,Chg_Time)

2004-11-25-13.22.05.000000

 

TimeStamp('10/15/1975', '08:55:01')

1975-10-15-08.55.01.000000

 



CONVERTING TO INTEGER DATA TYPES


To convert to an Integer data type use one of the following expressions:

  • SmallInt()

  • Integer() or Int()

  • BigInt()

The syntax for these functions is the same. There is only one argument for these functions. The argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type. The table below shows some examples of these functions.


Constants

Constants

Function

Result

Total = 456.254

Count = 15

SmallInt(1235.564)

1235

Int(Total/Count)

30

BigInt('89465411')

89465411

Integer('45323.55')

45323

 



CONVERTING TO NUMERIC DATA TYPES


To convert data to a numeric format, use the following functions:

  • Decimal() or Dec()

  • Zoned()

For these functions, the data type of the first argument determines the rest of the syntax. The first argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type.

If the first argument is numeric:

  • The second argument is an integer value for the desired precision for the result.

  • The third argument is an integer value for the desired scale for the result.

If the first argument is a character string:

  • The second argument is an integer value for the desired precision for the result.

  • The third argument is an integer value for the desired scale for the result.

  • The fourth argument is the character that is to be used as the decimal separator in the first argument.

The value of the precision argument is from 1 to 31. If no precision is specified, the precision is defaulted to the values listed below, based on the data type of the first argument.


Data Type

Data Type

Default Precision

Floating Point

Decimal

Numeric

15

Big Integer

19

Integer

11

Small Integer

5

 


The value of the scale argument is from zero to the precision specified in the second argument.

The value of the separator argument is either a comma (,) or a period (.).

The table below shows some examples of the ZONED() and DECIMAL() functions.


Constants

Constants

Function

Result

Total = 456.254

Count = 15

Decimal(135,9,3)

135.000

Zoned('1254.33',8,4)

1254.0000

Decimal(Total/Count,9,2)

30.42

Zoned('8912354,79',9,2,',')

8912354,79

 



CONVERTING TO FLOAT DATA TYPES


To convert data to a float data type, use the following functions:

  • Double() or Double_Precision()

  • Float()

  • Real()

The syntax for these functions is the same. There is only one argument for these functions. The argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type. The table below shows some examples of the functions.


Constants

Constants

Function

Result

Total = 456.254

Count = 15

Real(1235.564)

1.2355640000E+03

Real(Total/Count)

3.0416933333E+01

Real('89465411')

8.9465411000E+07

Real('45323.55')

4.5323000000E+04

Real('9.879822E+04')

9.8798220000E+04

 



YOU ARE IN CONTROL


These functions allow you to have complete control over your data and data types. These functions can also be nested within other functions. When this approach is combined with the creation of a view, your data conversions can be defined one time for all programs or users. Another use for these functions is when you need to duplicate an existing formula coded within another language. By specifying the precision and scale of your operands, you can control the resulting value of a formula. These functions require frequent use before they become second nature to you. In the meantime, refer to your reference manuals frequently and don't be afraid to experiment with new functions.


Raymond Everhart has over 18 years of IT experience with IBM midrange computers. He was a consultant, programmer, and educator for an IBM premier business partner in Upstate New York for 10 years, before relocating to the Dallas/Ft. Worth area in 1998. Since then, Raymond has been helping local companies implement new technologies with his consulting, programming and mentoring services. E-mail: reverhart@itjungle.com

Sponsored By
COMMON

COMMON Spring 2004 IT Education Conference & Expo
San Antonio, Texas
May 2-6, 2004

Conference activities will take place in the Marriott River Walk and the Henry B. Gonzalez Convention Center.

Click here for online registration and hotel reservations.

The conference includes a special focus on Linux Education.

Browse the Online Session Guide for the conference.

View an online video on COMMON conferences and other member benefits.

Download a PDF of the Conference Invitation and the Conference Preview brochure. (Right-click on these links and select "Save Target as" to download.)

First time attending a COMMON conference? You need the First-Timers' Kit --information that will "show you the ropes."

COMMON is the best value in IT education, so don't miss out!
Click and visit www.common.org for details!


Editors: Howard Arner, Joe Hertvik, Ted Holt,
Shannon O'Donnell, Kevin Vandever
Managing Editor: Shannon Pastore
Contributing Editors: Raymond Everhart, G. Wayne Hawks,
Marc Logemann, David Morris
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

THIS ISSUE
SPONSORED BY:

Guild Companies
COMMON
iTera
WorksRight Sofware
Damon Technologies


BACK ISSUES

TABLE OF
CONTENTS
V5R3 CL Programming Enhancements, Part 1

Using 'New' SQL Data Types in RPG

Why Use the Magic Number in Qshell Scripts?

Admin Alert: The Absolute Coolness of the QNTC File System

OS/400 Alert: Major Outlook 2002 Vulnerability Discovered



Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.
Guild Companies, 50 Park Terrace East, Suite 8F, New York, NY 10034
Privacy Statement