expand your database with udfs

Upload: rachmat99

Post on 14-Apr-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/29/2019 Expand Your Database With UDFs

    1/22

    Expand Your Database with UDFs

    Contributed by Bruce ViningWednesday, 02 July 2008Last Updated Wednesday, 02 July 2008

    User-defined functions are flexible and easy to create. Add them to your development toolkit to create powerful newsolutions for your company. By Bruce Vining Many of you are quite familiar with DDS and the ability to define physical and logical database files. For instance, if wehave a physical file MYFILE defined as shown below, we can create logical files that provide a subset of the physical filefields, map physical fields to logical fields through operators such as CONCAT and SST, map physical data types toother types, etc.:

    User-defined functions are flexible and easy to create. Add them to your development toolkit to create powerful newsolutions for your company. Many of you are quite familiar with DDS and the ability to define physical and logical database files. For instance, if wehave a physical file MYFILE defined as shown below, we can create logical files that provide a subset of the physical filefields, map physical fields to logical fields through operators such as CONCAT and SST, map physical data types to

    other types, etc.:

    R MYRCD NAME 30 TEXT('Company Name')

    XCNTRY 1 TEXT('Xfer Century') XMONTH 2 TEXT('Xfer Month') XYEAR 2 TEXT('Xfer Year') XDAY 2 TEXT('Xfer Day')

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    2/22

    For example, the logical file MYFILELF shown below maps the alphanumeric field Name to a Unicode data type and

    concatenates the fields XCntry, XYear, XMonth, and XDay to a XDate logical field in CYYMMDD format.

    R MYRCD PFILE(MYFILE) NAME G CCSID(1200) XDATE CONCAT(XCNTRY XYEAR - XMONTH XDAY)

    We can, however, do much, much more by combining the power of database with a high-level language such as RPG.

    Let's say we have a user who needs to query MYFILE to determine the number of days that have passed since the Xfer(Transfer) date for each company. For demonstration purposes, we'll load four records into MYFILE using a tool such asthe Data File Utility (DFU). These are the record contents:

    NAME XCNTRY XMONTH XYEAR XDAY Company 1 1 06 08 01

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    3/22

    Company 2 1 05 08 15 Company 3 1 05 08 20 Company 4 0 11 07 02

    Using the IBM Query product 5722-QU1, we can calculate the number of days since the transfer date using the following

    result fields and field selection criteria:

    Selected files ID File Library Member Record Format T01 MYFILE VINING *FIRST MYRCD

    Result fields Name Expression TIMESTAMP '0001-01-01-00.00.00.00000' || XCntry CENTURY DIGITS(MICROSECOND(Timestamp) + 19)

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    4/22

    DATE CHAR(DATE(SUBSTR(Century,11,2) || XYear || '-' || XMonth || '-' || XDay), ISO)

    DAYS DAYS(CURRENT(DATE)) - DAYS(Date) Ordering of selected fields

    Field Sort Ascending/ Break Field Name Priority Descending Level Text NAME Company Name DAYS

    The result fields TimeStamp and Century are used to convert the alphanumeric XCntry field to a numeric field and to thenadd the value 19 so that we can determine the century (19xx, 20xx, etc). The result field Date is used to create a datedata type field so that we can use the DAYS function to determine the number of days between the current date and thetransfer date. The value of the result field Days is that number of days. For reporting purposes, we are displaying/printingthe company name and the number of days between the current date and the transfer date.

    NAME DAYS Company 1 15 Company 2 32 Company 3 27 Company 4 36,752

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    5/22

    There are other ways to calculate the number of days, but the approach used is fairly representative of what is neededon a V5R4 system. And while it's somewhat straightforward, I would certainly not want to explain this process to a typicalend user. Most of the effort involved is in converting the four alphanumeric fields XCntry, XYear, XMonth, and XDay intothe date field Date. It would simplify life greatly if we could provide the user with a view of MYFILE that simply provided aDate field already mapped to a date data type, and that's what we're going to do.

    Within the database is the capability to create user-defined functions (UDFs). For the purpose of this article, UDFs areessentially the ability to have a user exit program called by the system when a particular field is used within a view. UDFsare considered part of the Structured Query Language (SQL), but it is not necessary to have the DB2 Query Managerand SQL Development Toolkit product 5722-ST1 installed on your system. The only products used in this article to createUDFs are the IBM i operating system and the ILE RPG compiler. For those of you who are SQL knowledgeable, even theRPG compiler is not needed. This article, however, is being published in RPG Developer and will demonstrate how to

    use UDFs and RPG without having to learn SQL (or at least not much SQL).

    We are going to create a UDF (or program) that accepts four parameters--Xcntry, XMonth, XDay, and XYear--andreturns a date data type field. To create the UDF, we will use the following CREATE FUNCTION statement:

    create function vining/Get_Date (char(1), char(2), char(2), char(2)) returns date language rpgle

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    6/22

    deterministic no sql not fenced;

    For now, don't worry about how we'll run this statement. Let's just look at what the statement contains.

    We are creating a function named Get_Date, which will be in the library VINING. The Get_Date function, an ILE RPGprogram we will create shortly, will be passed four parameters--a 1-byte character field followed by three 2-byte characterfields. These parameters correspond to XCntry, XMonth, XDay, and XYear, respectively. I'll point out that we could haveincluded the field names in this parameter list (XCntry char(1), XMonth char(2), etc.), but I'm trying to hold the informationin the statement to a minimum. (For full documentation on the CREATE FUNCTION statement, see the SQL Referencemanual.) Rather than a program, Get_Date could also be implemented as an entry point within a service program. We'reusing a program approach in order to minimize the lines of code and the number of compilation steps.

    The Get_Date function will return one parameter, which is a date data type. The function is written in ILE RPG, isdeterministic (meaning that it will always return the same result if called with the same input parameters), contains noimbedded SQL statements, and is not fenced (meaning that it can run in the same thread as the database caller of thefunction, which may not be the initial thread where the Query is running). The Not Fenced clause is not strictly necessaryfor this article, but, as it provides better performance than the alternative, Fenced, I chose to include it. Several other

    parameters for the CREATE FUNCTION statement are being defaulted, and you may want to look at the SQL Referencemanual for details on these other options.

    The system will call our Get_Date program with more than just the four parameters discussed above. The minimumparameters that will be passed are described below, where N is the number of input parameters defined (four in ourexample) on the CREATE FUNCTION statement.

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    7/22

    Required Parameters:

    1 to N N input parameters

    Input Varies based on UDF definition

    N + 1 1 result parameter Output

    Varies based on UDF definition (N+2) to (2N)+1) Indicator parameters for input parameters

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    8/22

    Input

    2-byte integers (5i 0) 2(N+1) Indicator parameter for result parameter

    Output 2-byte integer (5i 0)

    + 1 Status

    Output Char(5) + 1 Qualified function name

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    9/22

    Input

    Varying length Char(139) + 1

    Specific function name Input Varying length Char(128)

    + 1 Message text

    Output Varying length Char(70)

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    10/22

    Our Get_Date program will be called with 14 parameters. The first four will be the values for XCntry, XMonth, XDay, andXYear as each record is processed. The fifth parameter will be the output parameter where Get_Date will return the datevalue calculated from the input parameters.

    The next four parameters (six through nine) will each be 2-byte signed integers representing null indicators for the fourrespective input parameters (XCntry, XMonth, XDay, and XYear). If the indicator value is -1, then the corresponding inputparameter value is NULL. If the indicator value is 0, then the corresponding input parameter is not NULL. The next, tenth,parameter will be a 2-byte signed integer output allowing Get_Date to indicate whether or not the returned date field isNULL. As with the input parameter indicators, -1 indicates that the result is NULL.

    The next parameter, Status, can be used by the Get_Date function to pass error-related information back to the i5/OSdatabase (and from there to the Query). A value of all zeroes, which is the default value, indicates that no error wasencountered by Get_Date. Several possible error values can be returned and can be found here. The valid error valuesare those starting with either '01' for warnings or '38' for exceptions. Qualified function name, the 12th parameter, will bethe name of the function (VINING.GET_DATE for our example), Specific function name, the next parameter, will beGET_DATE, and the last parameter, Message text, is an output parameter where Get_Date can provide textual

    information related to any error the program reported in the Status parameter.

    This is the ILE RPG source for Get_Date:

    dGet_Date pr extpgm('GET_DATE') d Century 1 d Month 2 d Day 2 d Year 2

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    11/22

    d Date d d CenturyInd 5i 0

    d MonthInd 5i 0 d DayInd 5i 0 d YearInd 5i 0 d DateInd 5i 0 d SQLState 5

    d FuncName 139 varying d SpecificName 128 varying d MsgText 70 varying

    dGet_Date pi d Century 1 d Month 2 d Day 2

    d Year 2 d Date d d CenturyInd 5i 0 d MonthInd 5i 0 d DayInd 5i 0 d YearInd 5i 0

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    12/22

    d DateInd 5i 0 d SQLState 5 d FuncName 139 varying

    d SpecificName 128 varying d MsgText 70 varying /free

    Date = %date((Century + Month + Day + Year) :*CMDY0); *inlr = *on; return;

    /end-free

    As you can see, there isn't much to the program! Other than the parameter definitions, we have essentially only the onecalculation using the %date built-in function of ILE RPG. The program can be created with CRTBNDRPG GET_DATE.

    Now let's see how we can use Get_Date to simplify the Query we looked at earlier. First, we need to create a view(similar conceptually to a DDS defined logical file) that maps the physical file MYFILE to a view that includes our "virtual"date field. We do this with the SQL CREATE VIEW statement.

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    13/22

    create view vining/myfiledate as select

    Name, Get_Date(XCntry, XMonth, XDay, XYear) as Date from myfile;

    This statement creates the view MYFILEDATE in library VINING. The view includes two fields: Name and Date. Name issimply the Name field from the physical file MYFILE. Date, on the other hand, is a field returned by the Get_Date UDFwith Get_Date being passed the parameters XCntry, XMonth, XDay, and XYear from MYFILE.

    To use this view, from Query or even another RPG program, we use MYFILEDATE as the name of the file. To nowcalculate the number of days since the transfer date to the current date, we can modify our earlier Query to simply saythis:

    Selected files ID File Library Member Record Format T01 MYFILEDATE VINING *FIRST MYFILEDATE Result fields Name Expression Column Heading

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    14/22

    DAYS days(current(date)) - days(date) Ordering of selected fields

    Field Sort Ascending/ Break Field Name Priority Descending Level Text NAME Company Name DAYS

    And running the Query, we get this:

    NAME DAYS Company 1 15 Company 2 32 Company 3 27

    Company 4 36,752

    Quite a bit easier! We have basically expanded our database to now include a date data type field that is based on the

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    15/22

    physical fields found in the existing MYFILE database.

    Now we get to the question "Just what is required to run the SQL statements CREATE FUNCTION and CREATEVIEW?" Fortunately, it's very simple. Create a source physical file, enter the two CREATE statements into a sourcemember, and then run the RUNSQLSTM CL command, which will process the SQL statements. For demonstrationpurposes, we can use the following commands:

    CRTSRCPF QSQLSRC

    STRSEU QSQLSRC MYFIRSTUDF TXT

    While in SEU (or a similar editor), enter the following two statements. Be careful to not miss the closing semicolon (;) foreach statement:

    create function vining/Get_Date (char(1), char(2), char(2), char(2)) returns date language rpgle deterministic no sql

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    16/22

    not fenced; create view vining/myfiledate as select name, get_date(xcntry, xmonth, xday, xyear) as date

    from myfile;

    Exit from your editor and then run this command:

    RUNSQLSTM SRCFILE(QSQLSRC) SRCMBR(MYFIRSTUDF) COMMIT(*NONE)

    If you previously entered test data into MYFILE, you are now ready to use Query and easily determine the number ofdays that have passed since the transfer date.

    If you want to play with other versions of the Get_Date function or MYFILEDATA view, you can use the SQL DROPstatement to delete the UDF and/or view. The statements would be either or both of the two below.

    DROP FUNCTION GET_DATE;

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    17/22

    DROP VIEW MYFILEDATA;

    These statements can be run by again placing the statements into a source member of QSQLSRC and running theRUNSQLSTM command against that member.

    The Get_Date UDF provides a very productive extension to our database. You might notice that nowhere in the CREATEFUNCTION statement or the Get_Date RPG program do we actually reference MYFILE. The Get_Date UDF can be usedanytime we want to create a virtual date data type field from a physical file and the date is stored as separate fieldsrepresenting the century, year, month, and day. If some of our physical files store date-related information in formatssuch as numeric, combined YYMMDD, etc., we can also create UDFs to cater to these other file formats. We can buildthese UDFs once and then reuse them many times.

    Essentially, if we can calculate a value within an RPG program, then with UDFs and views we can have that valueappear as if it actually exists within the database. What would be required, for instance, to eliminate the one remainingresult field Days in our Query? The answer is a new UDF Get_Diff and a new view MYFILEDIFF.

    This is the CREATE FUNCTION statement to create Get_Diff:

    create function vining/Get_Diff (char(1), char(2), char(2), char(2)) returns integer

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    18/22

    language rpgle deterministic no sql

    not fenced;

    Here's the RPG program Get_Diff:

    dGet_Diff pr extpgm('GET_DIFF')

    d Century 1 d Month 2 d Day 2 d Year 2

    d Days 10i 0 d CenturyInd 5i 0 d MonthInd 5i 0 d DayInd 5i 0 d YearInd 5i 0 d DaysInd 5i 0

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    19/22

    d SQLState 5 d FuncName 139 varying d SpecificName 128 varying

    d MsgText 70 varying dGet_Diff pi d Century 1

    d Month 2 d Day 2 d Year 2 d Days 10i 0 d CenturyInd 5i 0

    d MonthInd 5i 0 d DayInd 5i 0 d YearInd 5i 0 d DaysInd 5i 0

    d SQLState 5 d FuncName 139 varying d SpecificName 128 varying d MsgText 70 varying dToday s d inz(*JOB)

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    20/22

    /free

    Days = %diff( Today :(%date((Century + Month + Day + Year) :*CMDY0)) :*DAYS);

    *inlr = *on; return; /end-free

    Create the view MYFILEDIFF:

    create view vining/myfilediff as select name, get_diff(xcntry, xmonth, xday, xyear) as days from myfile;

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    21/22

    And remove the calculation from our Query:

    Selected files ID File Library Member Record Format T01 MYFILEDIFF VINING *FIRST MYFILEDIFF

    Ordering of selected fields Field Sort Ascending/ Break Field Name Priority Descending Level Text

    NAME Company Name DAYS

    This leaves us with the same output as before, a lot less work for the end user, and elimination of the exposure thatsome end user might miscalculate the number of days between the current date and the transfer date.

    NAME DAYS Company 1 15

    MC Press Online

    http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:01

  • 7/29/2019 Expand Your Database With UDFs

    22/22

    Company 2 32 Company 3 27

    Company 4 36,752

    Before we leave, there are two items I would like to point out about Get_Diff. First, the Get_Diff function is defined asreturning an integer data type rather than a date data type. As we're returning the number of days, this makes sense butis a change that might be easily overlooked. Second, the Get_Diff RPG program initializes the field Today to *JOB. Thisis to avoid the problem of the system date rolling over to the next day if the Query happens to be running at midnight.Using *JOB, rather than *SYS, prevents the Query output from changing mid-report and leaves the function as beingdeterministic.

    And one item about views in general: A view can be used much like a logical file, but views do have limitations. Onelimitation has to do with keyed access. It is impossible to associate a key (or index) with a view in the same manner asyou can with a logical file. In the case of Query, this is not a major concern as Query tends to read an entire file andallows you to specify sort criteria for the output. In the case of an RPG application using standard RPG file managementand reading a view, this means you can only read the view sequentially (which may or may not be arrival sequence). Thismay be suitable for some batch jobs but generally precludes the use of views for most interactive applications (no CHAINby key, for instance). Using SQL, you can have an index associated with the use of a view. This consideration is not somuch a limitation of UDFs as it is a consequence of how UDFs are accessed using RPG standard data management.

    The IBM i has long been recognized as having a strong and productive database capability. While UDFs are not new tothe i database, it's been my experience that quite a few RPG developers are unaware of the flexibility available withUDFs. Or if they are aware of UDFs, many are unaware that UDFs are available within the operating system and do notrequire that the SQL Toolkit be installed. As you have hopefully seen, UDFs are highly flexible, aren't difficult to create,and can be a great addition to your development toolkit when providing new solutions to your company. I hope you keepthis capability in mind when working on future projects.

    MC Press Online