Business Information Server: Using Stored Procedures

Craig D. Hanson

White Paper

2

Unisys Business Information Server (BIS) solutions and products enable integration of a wide range of applications and running in heterogeneous environment. You can use the BIS for Windows product plus its included Internet Commerce Enabler (ICE) module in a ClearPath® environment to extend, add to, and integrate applications and databases. With this product, you extend the value of your ClearPath application environment. BIS offers exceptional capabilities to access data from multiple disparate sources and turn it to useful information. It facilitates synergy between different data sources and enables using the data in a new manner or in a new business process. This white paper describes powerful integration capabilities of store procedures provided by the BIS solution in the ClearPath OS 2200 environments.

3

Table of Contents

1. Overview ...... 5 2. @SPI Statement Basics ...... 5 2.1 What is a Stored Procedure? ...... 5 2.2 @SPI Statement Syntax ...... 5 3. Supported Databases & Platforms ...... 10 5. Retrieving Metadata ...... 13 5.1 Guidelines & Considerations ...... 13 5.2 Examples ...... 14 5.2.1 S Option w/SQL Server, OLEDB Provider ...... 14 5.2.2 S Option w/Oracle Server, ODBC Provider ...... 15 5.2.3 Option w/SQL Server, OLEDB Provider ...... 19 5.2.4 P Option w/SQL Server, ODBC Provider ...... 20 6. Executing Stored Procedures ...... 21 6.1 Guidelines & Considerations ...... 22 6.2 Examples ...... 23 6.2.1 SQL Server - 2 Input Parameters, w/OLEDB ...... 24 6.2.2 SQL Server - Output Parameters with Result set ...... 25 6.2.3 SQL Server - Parameterized SELECT Query ...... 28 6.2.4 Oracle DB – ResultSet w/ one input, Microsoft provider for Oracle ...... 29 6.2.5 Oracle DB - ResultSet w/REF , w/Microsoft providers ...... 33 6.2.6 Oracle DB – w/REF Cursor and %ROWTYPE ...... 36 6.2.7 Oracle DB - w/REF Cursor; In, Out, & Resultset ...... 38 7. Executing Stored Procedures from BIS JavaScript ...... 41 7.1 BIS JavaScript Related Syntax ...... 42 7.1.1 Execute Method of Object ...... 42 7.1.2 DatabaseArguments Object...... 42 7.2 JavaScript Example ...... 43

4

1. Overview 2.2 @SPI Statement Syntax @SPI (Stored Procedure Interface statement) allows you The @SPI (Stored Procedure Interface) statement is to execute stored procedures on external databases and part of the MRI set of commands and combines many of return results to your Business Information Server script. the attributes of the @FCH and @SQL statements. The Through examples and explanations, this white paper MRI statements include: will describe the capabilities and limitations of the new SPI statement. Also, described is how to invoke the • Data Definition Information (@DDI) SPI feature to execute stored procedures from a Retrieves a description from a BIS JavaScript. - . 2. @SPI Statement Basics • Log On to Relational Database (@LGN)

- Establishes communication between BIS and a 2.1 What is a Stored Procedure? relational database management system. The @SPI (Stored Procedure Interface) statement • Log Off Relational Database (@LGF) allows you to execute procedures that reside in an Terminates communication established with the external database. A stored procedure is typically a set - @LGN statement. of commands and control logic executed by the database to retrieve and/or update data in the database. • Relational Aggregate Fetch (@FCH) The procedure is physically stored in the database for - Retrieves data from one or more relational both security and performance reasons. The procedure tables and places the data in a result. language is specific to the database, but often is based on the SQL command language. Normally, a procedure • Relational Aggregate Modify (@RAM) written for one database, such as Microsoft SQL Server, - Creates or deletes relational tables, updates cannot be used on another database, such as Oracle. a table, inserts a record, or issues a command. Stored procedures have different names and structures on different databases. For example, Microsoft SQL • Submit SQL (@SQL) Server defines both “functions” and “stored procedures”, - Submits SQL syntax to a relational both which can be executed with the @SPI statement. database manager. Oracle also has stored procedures, but they can be either stand-alone or part of a “package”. Like other MRI commands, the @SPI statement requires that you use the @LGN and @LGF commands to Regardless of the naming convention used, execution of connect and disconnect to a database. procedures is the same. The procedure name is specified along with input and output parameters. The results are returned to the user. Unlike the @FCH and @SQL statements, @SPI can return both a rowset and output parameters. The rowset is returned in the –0 result of the statement and the output parameters are returned to the specified BIS variables. The RETURN_VALUE is also returned to a specified BIS variable.

5

The @SPI statement supports the following operations:

• Execute a single stored procedure.

• Retrieve a list of stored procedures for a specified database.

• Retrieve a list of columns with their definitions for a specified stored procedure.

• Retrieve a list of parameters with their definitions for a specified stored procedure.

The @SPI statement has the following syntax. All sub-fields are optional unless otherwise specified in the description below.

CMD Field SP Field Param Field Param Type Field

@SPI,c,d,lab,db,edsp?,action,wrap,vert ‘sp-syntax’ vpar1,...,vparn typ1,...,typn .

Field/Sub-field Description

CMD Field Required

c,d Cabinet and drawer to hold the result. Default is 0,A lab Label to go to if the status in the STAT1$ variable is other than normal completion. db Database name. The name registered in MRIDBA. Required. edsp? edsp sub-field. Create a result if an error occurs? Y – The result contains the last statement sent to the database manager and the text of the system message. It also contains the status code and descriptive message. N – (default) A runtime error occurs if there is an error executing this statement action action sub-field. This option determines the action performed and allows you to retrieve meta-data about stored procedures in the specified database. The results are stored in the –0 result report. See details below. E – (default action) Execute the specified stored procedure. S – Returns a list of stored procedures in the specified database C – Returns a list of columns in the specified stored procedure P – Returns a list of parameters in the specified stored procedure wrap wrap sub-field. T – Truncate the results. For ‘E’ action option, if the width of the rowset exceeds the width of the result report, the rows are truncated. Also truncates decimal values that do not fit within their field widths. For meta-data action options (S, P, C), the fields are truncated on the right side. W – Wrap results on multiple lines if the result exceeds the result report width. The “W” value is only valid with the “E” action option N – (default action) For ‘E’ action option, displays a system error message if the data does not fit within the line width of the selected drawer or if a decimal value does not fit within its width. For the meta-data action options (S, P, C), displays a system error message if any field does not fit the width of a column.

6

vert vert sub-field. This option defines the format of the results. This option only applies to the “E” action. See ‘Vert Subfield Details’ below. Y – Display results vertically without column names (column names are listed in the header). N – (default action) Display results horizontally with column names.

SP Field Required if action option is not ‘S’. If action option is ‘S’, this and subsequent fields must not be present, otherwise they will be interpreted as a new command. sp-syntax The stored procedure syntax to execute or it’s name to retrieve information about. This field contains the string feed to the database to execute a stored procedure. See ‘SP-Syntax Details’ below for more details. If the action option is ‘P’ or ‘C’ this field should contain only the name of the stored procedure to retrieve metadata about.

Param Field Valid only for action option of ‘E’. Otherwise, this and subsequent fields must not be present. If there are no parameters for the stored procedure, this field must not be present; otherwise, they will be interpreted as a new command. vpar Up to 78 variables. Each variable is associated with a parameter in the sp-syntax field. The sp syntax uses the “ODBC Call escape sequence”, which contains parameter markers “?” (question marks). There is a one-to-one association between each variable (vpar) and each parameter marker in the SP syntax. Any variable may be used as an input parameter, an output parameter, or an input and output parameter. The type is defined by the stored procedure and can be determined from the ‘P’ action option. Output parameters are stored in the variable associated with that parameter. The variable must be defined large to hold the returned value. Otherwise, the value may be truncated or result in errors. See examples for usage details.

The maximum space for all SPI variables is limited to about 7,000+ bytes. If the defined size of all parameter variables exceeds this size, the SPI statement will fail with an error message.

Param Type This optional field is used if there is anything specified in the Param Field. Field typ Parameter type specification for each ‘vpar’ listed in the Param Field. This is a comma-separated list of values. The values are: – return value, (associate vpar must be an I-type variable) i – input parameter, (default value) o – output parameter, b – both input & output parameter

These values are used when binding the parameters for execution and must match the defined type for this stored procedure. The Return Value is normally always an integer, so for any parameters identified as a Return Value, the associated variable should be an “I” type or an error may be returned.

7

The SPI statement also sets the following reserved word for use by the script writer.

STAT1$ Captures the status of the action performed. This is where the status of the @SPI execution is stored. Status values of 0 or 6001 (end of records) are considered normal completion and does not take the error label branch. Other positive values reflect the native error codes from the database provider for the operation in error. Special status codes are returned as negative numbers and include: –999 = no native error code provided, see error text for more details. –1000 = errors detected while retrieving data for metadata action options. This normally occurs when the provider does not support a schema or internal method for retrieving the requested metadata.

Action Subfield Details E option – Returns the rowset results in the –0 result report and any output parameters are loaded into the corresponding variables. See examples below. A stored procedure can have three types of output depending on the procedure itself. * rowset – table stored in the –0 result (column names and sizes are defined by the stored procedure) * output parameters – stored in the corresponding variables (vpar) * return value – stored in the corresponding variables (vpar).

S option – Returns the list of stored procedures in the –0 result. The returned columns include: fieldname(column size)

Type(4) – procedure type1 (‘PROC’(procedure), ‘FN’(function), or ‘Unkn’(unknown)) SP Name(100) – name of the stored procedure

C option – Returns the list of columns for the specified stored procedure in the –0 result. The returned columns include: fieldname(column size)

Column Name(30), – name of the column Type(16), – data type name as defined by the provider Size(7), – the number of characters for this field DecPt(5), – the number of digits to the right of the decimal point (also called scale) NF(5), – can this field be a NULL - ‘True’, ‘False’, or ‘Unkn’(unknown) Length(10), – length; the number of digits or characters for the data as defined by the provider Precision(10) – precision of the column; the number of digits in the data value as defined by the provider

P option – Returns the list of parameters for the specified stored procedures in the –0 result. The returned columns include: fieldname(column size)

Parameter Name(30), – name of the column Type(16), – data type name as defined by the provider Size(7), – the number of characters for this field DecPt(5), – the number of digits to the right of the decimal point (also called scale) NF(5), – can this field be a NULL - ‘True’, ‘False’, or ‘Unkn’(unknown) PType(5), – parameter type2; IN, OUT, INOUT, RV, Unkn Length(10), – length; the number of digits or characters for the data as defined by the provider Precision(10) – precision of the column; the number of digits in the data value as defined by the provider

1 The definition of a ‘procedure’ and a ‘function’ vary from one database to another. 2 Input parameter, Output parameter, Input and Output parameter, Return Value

8

Vert Subfield Details Y option – Display the results in a vertical format with one data value per line. This format maximizes the available space for very wide data columns. The format is similar to the vert Y option for the @FCH statement. The field names are listed followed by each record, with one value per line. This option is only available for the execute operation (action = ‘E’). Each record begins with “.RECORD #:”, where “#” is the record number. For example, a 3 column, 2 record result;

.COLUMN(S) *Color *Size *Name *======.RECORD 1: |yellow | 23 |Jack .RECORD 2: |blue | 42 |Jane N option – Display the results in a horizontal format with one record per line. This is the default format. For example, a 3 column, 2 record result;

*Color Size Name *======.====.======|yellow| 23|Jack |blue | 42|Jane

SP-SYNTAX Details The sp-syntax for the metadata actions (P, C) is simply the stored procedure name. For the execute action (E), the sp- syntax uses the standard ODBC CALL escape sequence (shown below). This format allows the user to specify parameter markers (?), which will correspond with the vpar variables on the statement line.

{[?=]CALL procedure_name[([parameter][,[parameter]]...)]}

For example: {call SalesByCategory('Produce', '1995')} or {?=call SalesByCategory('Produce', ?)} The square brackets ([…]) show optional fields. Here is BIS script example.

@ldv ='{? = call SalesByCategory(?,'1995')}' @spi,0,i,0010,,y,e,n,n , In this example, there are two parameter markers. The variable is used to hold the RETURN-VALUE and holds the first input parameter passed to SalesByCategory. The STAT1$ variable holds the @SPI status after executing the @SPI statement.

While this syntax may seem awkward at first, it is a standard syntax and provides great flexibility for the user, by allowing a mix of variables and literals when passing parameters.

9

3. Supported Databases 4. Relationship between MRI & Platforms and Database Providers The @SPI statement only supported by the MRIM Before describing each of the options and going through ODBC and OLEDB data handlers to databases. These examples, it is important to understand the relationship interfaces provide a common and consistent method for between BIS, MRIM, the data providers and the accessing the database. Support for selected native database itself. Execution of stored procedures and the interfaces may be added in the future, but will not results received are very dependent on the database enhance the performance of executing stored and the data provider used. See Figure 1 and the procedures. As of the release of BIS 9.1, testing has examples for details. only been performed with the Microsoft SQL Server and the Oracle databases. Execution of stored procedures The SPI statement, like other MRI statements, has on other databases should be possible, but is currently MRIM “Data Handlers” that interface with the specified untested. “Data Providers”, which in turn interface with the specified database. For example, to access data on a The SPI statement is only supported on the Windows SQL Server using the ODBC interface, you must; platform for BIS. It is not supported on the 2200 or UNIX platforms at this time. You can also use MRI-to-MRI 1. Setup an ODBC Data Source on the BIS PC and networking to execute SPI on a different Windows specify the SQL Server with correct server path and platform with MRIM running on it. database. This establishes a path through the selected ODBC data provider to the database. The SPI statement is supported with the BIS ODBC Server using the BIS ODBC data provider. However, the 2. Next, you must create a BIS database configuration. SPI has very limited use since the BIS ODBC Server This is performed using the MRIDBA run and does not support stored procedures or parameterized specifying the name created for the ODBC Data select queries. You can use the SPI statement to pass a Source (which is maintained in 1C2). This SELECT statement that does not contain any parameter establishes a path through the specified MRIM markers (?). Of course, you can also do this with the ODBC data handler, which talks to the data provider. @FCH or @SQL statement. Now when you logon (@LGN) and execute MRIM statements (like @SPI), processing flows through the MRIM data handlers to the configured “Data Provider” to the database itself, then back to the BIS.

10

While this process may seem obvious, it is important to Figure 1 shows the components and connections used understand this basic flow. While Unisys controls the in BIS for MRI database operations. The “Data processing and actions in BIS (mapper.exe and Providers” are components on the client side (i.e., the mrim.exe), the “data providers” are third-party BIS Server) that process database requests using a components that don’t always behave the same. For specified protocol language (e.g., ODBC or OLE DB). example, an ODBC provider and an OLEDB provider for The data providers translate the requests into native API a SQL Server may return different data or the formatting commands on the database server side and perform all may be different for some operations. See some for the the actions with the database. To use a Data Provider examples below. Therefore, the user must choose the you must create a connection configuration for each type correct data provider to match the operations being of connection desired. performed. Refer to the Guidelines and Consideration sections for more details. After creating database connections for the Data Providers, you must register the database connection The SPI statement uses a “pass-through” model to before using MRI statements. This is performed with the execute stored procedures in the database. This means MRIDBA utility with the registration data maintained in that the syntax provided on the SPI statement is not 1C2. With registration complete, MRI statements (like parsed or interpreted, but rather passed through to the SPI) can be used to access databases. “data provider” as specified. Any specified parameters are bound to the execution statement; and allow input Here is how a typical SPI statement flows throw the and output data to flow as defined by the stored various components. We will use the Microsoft SQL procedure. If the stored procedure creates a result set (a Server with the ODBC interface for this explanation. table), the result set is retrieved and stored in –0 result @ spi,0,i,0199, 'db',y,e,n,n '{call of the SPI statement. Multiple parameter sets and result custordhist(?)}' 'OCEAN' i . sets are not supported. Since the data providers generally interpret question marks (?) as “parameter The ODBC connection is registered in BIS with the name markers”, there should always be one parameter in the ‘db’. When the SPI statement is executed, BIS passes it SPI statement for each “parameter marker” found in the to “MRIM” where the statement is parsed and passed to SPI syntax. This model provides greater flexibility for the the MRI ODBC data handler. The MRIM data handlers designer, but the designer must use care to match the then use the established connection to the Data SPI syntax with the stored procedure and the data Provider. The parameter, OCEAN, is bound to the provider that is used. Refer to the Oracle examples in command as an input parameter. The command text, sections 6.2.4 - 6.2.7 for examples of these differences. {call custordhist(?)}), is set. Then the command is executed. Note that command text is not parsed or altered by BIS or the MRIM data handlers. The Data Providers and the Database then do all the work with parsing the command and executing the stored procedure. The MRIM data handlers then retrieve any data values returned in the parameters and retrieve any result set. The results are passed back to BIS and the script executing the SPI statement. Retrieved data is converted to strings by the Data Providers and passed back to the user.

11

Figure 1 - BIS-MRI-Database Relationship

12

5. Retrieving Metadata 5.1 Guidelines & Considerations Stored procedure “metadata” is any data that defines Retrieving metadata for stored procedures is not information about stored procedures. The SPI statement consistent across different databases and different data has three options for retrieving metadata regarding providers. Use these guidelines and considerations to stored procedures. better understand your results.

• “S” Option – Retrieve a list of stored procedures in • The returned metadata depends on the data this database. provider used. Some data providers do not provide all of the metadata specified by the fields for the S, • “C” Option – For the specified procedure, list the C, and P options. In the returned results, the missing columns in the result set. fields will be blank. The following are examples of some differences: • “P” Option – For the specified procedure, list the parameters. - Microsoft OLEDB provider for Oracle and the Oracle OLEDB provider for Oracle provide Each of these options relies on the data provider to significantly different lists of stored procedures. provide the appropriate metadata. Unlike the execute (E) Many ODBC providers may not provide column option; the SPI statement tries to normalize some of the - metadata, but no errors are provided. returned metadata to provide consistent results. If the procedure is too complex, OLEDB • - The column names and sizes are fixed and defined providers will generate an error for column (see the @SPI Syntax section) metadata. • In the “S” option, the field (Type) is procedure type - The list of procedure names generated from an converted to ‘PROC’, ‘FN’, or ‘Unkn’ based on the SQL server includes a version number (;num). numeric value returned. However, the definition of a • The list of procedures provided with the “S” option procedure (PROC) and a function (FN) depends on depends on privileges allowed to the current logged the database you are using. on database user.

• In the “C” and “P” options, the nullable field (NF) is • When retrieving parameters (P option) and columns converted to ‘True’, ‘False’, or ‘Unkn’ based on the (C option), ODBC providers usually do not require numeric value returned. or allow delimiters around procedure names containing spaces or special characters. • In the “C” and “P” options, the data type field (Type) For example, @ldv,p s40='Sales By Year' . is converted to a string that represents the ODBC or OLEDB data type. (E.g., NVARCHAR or WSTR). • When retrieving parameters (P option) and columns Note that the data type field represents the data (C option), OLEDB providers usually do require provider data types, not the native database data delimiters around procedure names containing types. spaces or special characters. For example, @ldv,p s40='[Sales By Year]' . • In the “P” option, the parameter type field (PType) is • The Microsoft ODBC provider for SQL Server does converted to IN, OUT, INOUT, RV, Unkn based on not return any column data (C option). The Microsoft the numeric value returned. OLEDB provider for SQL Server returns column data if the procedure is not too complex. Typically, the procedure is too complex if it contains multiple statements or has a RETURN statement.

13

5.2 Examples This section shows several examples of using the @SPI statement to retrieve metadata.

These examples assume that you are familiar with writing and executing BIS scripts that use MRI statements to access databases. You can find more information in the BIS Help document. In particular, you can find help with configuring ODBC and OLEDB in the “MRI Administration and Users Guide” section of BIS Help.

5.2.1 S Option w/SQL Server, OLEDB Provider This example retrieves the list of stored procedures from the SQL Server, Northwind database using an OLEDB provider. The OLEDB data-link is configured using the “OLE DB Data Source Administration” tool. This connection is then added to BIS using the MRIDBA run. It’s given the name “NWSQL-OLE” for the example.

The results show a list of all the system and user procedures available to this user (sa). Note that the procedure names include a “;1” at the end of each name. The SQL server uses this number (version) to distinguish multiple versions of a procedure. To see an example of this; refer to the sp_columns_rowset() procedure in the SQL Server ‘master’ database.

BIS Script:

.S Option w/SQL Server, OLEDB Provider *======@. Setup database variables @ ldv,p s20=NWsql-ole,s20='sa',s20='' . @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,s,t,n . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

14

Results: . Procedure List for Database: NWSQL-OLE *Type.SP Name *====.======|FN |CustOrderHist;1 |FN |CustOrdersDetail;1 |FN |CustOrdersOrders;1 |FN |dt_addtosourcecontrol;1 |FN |dt_addtosourcecontrol_u;1 |FN |dt_adduserobject;1 |FN |dt_adduserobject_vcs;1 |FN |dt_checkinobject;1 |FN |dt_checkinobject_u;1 |FN |dt_checkoutobject;1 |FN |dt_checkoutobject_u;1 |FN |dt_displayoaerror;1 |FN |dt_displayoaerror_u;1 |FN |dt_droppropertiesbyid;1 |FN |dt_dropuserobjectbyid;1 |FN |dt_generateansiname;1 |FN |dt_getobjwithprop;1 |FN |dt_getobjwithprop_u;1 |FN |dt_getpropertiesbyid;1 |FN |dt_getpropertiesbyid_u;1 |FN |dt_getpropertiesbyid_vcs;1 |FN |dt_getpropertiesbyid_vcs_u;1 |FN |dt_isundersourcecontrol;1 |FN |dt_isundersourcecontrol_u;1 |FN |dt_removefromsourcecontrol;1 |FN |dt_setpropertybyid;1 |FN |dt_setpropertybyid_u;1 |FN |dt_validateloginparams;1 |FN |dt_validateloginparams_u;1 |FN |dt_vcsenabled;1 |FN |dt_verstamp006;1 |FN |dt_verstamp007;1 |FN |dt_whocheckedout;1 |FN |dt_whocheckedout_u;1 |FN |Employee Sales by Country;1 |FN |Sales by Year;1 |FN |SalesByCategory;1 |FN |Ten Most Expensive Products;1 ..... END REPORT ..... 5.2.2 S Option w/Oracle Server, ODBC Provider This example is similar to the previous one and retrieves a list of stored procedures from the (8.1 in this example). This time we are using ODBC data providers for Oracle. As we can see from the results below, the Oracle ODBC data provider returns different results than the Microsoft ODBC data provider. The number of procedures returned

15

and the procedure ‘type’ are different. We can also see differences between various OLEDB data providers and differences between the ODBC and OLEDB providers. Listed below is the number of records returned for the same Oracle database and the same userid. We’re not sure why the differences exist.

2220 records – w/Microsoft ODBC provider for Oracle 2114 records – w/Oracle ODBC provider for Oracle 2220 records – w/Microsoft OLEDB provider for Oracle 3842 records – w/Oracle OLEDB provider for Oracle

Also notice that Oracle procedures are listed with the structure .. Oracle stored procedures are typically part of a “Package”. An Oracle “Package” consists of two parts; the “specification” part, and the “body” part. Refer to the Oracle examples below.

BIS Script: .S Option w/Oracle Server, ODBC Provider *======@. Setup database variables @. w/MS provider @ ldv,p s20=msora-odb,s20='scott',s20='tiger' . @. w/Oracle provider @ . ldv,p s20=ora-odb,s20='scott',s20='tiger' . @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,s,t,n . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

16

Results w/Microsoft provider: . Procedure List for Database: MSORA-ODB *Type.SP Name *====.======|Unkn|CTX_DOC.FILTER |Unkn|CTX_DOC.GIST |Unkn|CTX_DOC.HIGHLIGHT |Unkn|CTX_DOC.MARKUP |Unkn|CTX_DOC.PKENCODE |Unkn|CTX_DOC.SET_KEY_TYPE |Unkn|CTX_DOC.THEMES |Unkn|CTX_DOC.TOKENS |Unkn|CTX_QUERY.BROWSE_WORDS |Unkn|CTX_QUERY.COUNT_HITS |Unkn|CTX_QUERY.EXPLAIN |Unkn|CTX_QUERY.HFEEDBACK |Unkn|CTX_QUERY.HFEED_EXECUTE |Unkn|CTX_QUERY.REMOVE_SQE |Unkn|CTX_QUERY.STORE_SQE |Unkn|DRIIMP.CREATE_INDEX |Unkn|DRIIMP.SET_OBJECT |Unkn|DRIIMP.SET_SUB_VALUE |Unkn|DRIIMP.SET_VALUE |Unkn|DRILOAD.BUILD_DML |Unkn|DRILOAD.RESOLVE_SQE |Unkn|DRILOAD.VALIDATE_POL |Unkn|DRILOAD.VALIDATE_STMT |Unkn|GEOCODER_HTTP.ESTIMATE_LEVEL |Unkn|GEOCODER_HTTP.GEOCODE1 |Unkn|GEOCODER_HTTP.SETUP_LOCATOR_INDEX ... 2220 rows reported, but not shown here to save space.

17

Results w/Oracle provider: . Procedure List for Database: ORA-ODB *Type.SP Name *====.======|PROC|CTX_DOC.FILTER |PROC|CTX_DOC.GIST |PROC|CTX_DOC.HIGHLIGHT |PROC|CTX_DOC.MARKUP |FN |CTX_DOC.PKENCODE |PROC|CTX_DOC.SET_KEY_TYPE |PROC|CTX_DOC.THEMES |PROC|CTX_DOC.TOKENS |PROC|CTX_QUERY.BROWSE_WORDS |FN |CTX_QUERY.COUNT_HITS |PROC|CTX_QUERY.EXPLAIN |PROC|CTX_QUERY.HFEEDBACK |PROC|CTX_QUERY.HFEED_EXECUTE |PROC|CTX_QUERY.REMOVE_SQE |PROC|CTX_QUERY.STORE_SQE |PROC|DRIIMP.CREATE_INDEX |PROC|DRIIMP.SET_OBJECT |PROC|DRIIMP.SET_SUB_VALUE |PROC|DRIIMP.SET_VALUE |PROC|DRILOAD.BUILD_DML |FN |DRILOAD.RESOLVE_SQE |PROC|DRILOAD.VALIDATE_POL |PROC|DRILOAD.VALIDATE_STMT |FN |GEOCODER_HTTP.ESTIMATE_LEVEL |FN |GEOCODER_HTTP.GEOCODE1 |PROC|GEOCODER_HTTP.SETUP_LOCATOR_IN ... 2114 rows reported, but not shown here to save space.

18

5.2.3 C Option w/SQL Server, OLEDB Provider This example retrieves the column metadata for the stored procedure “Employee Sales by Country”. This procedure is found in the Northwind database on the Microsoft SQL Server. The columns being described are the columns of the result set returned when executing the procedure.

Note that the procedure name needs to be enclosed with delimiters because we are using the OLEDB provider and the name contains spaces. Also, note that the ‘Type’ field represents the OLEDB data type name for this column.

BIS Script: .C Option w/SQL Server, OLEDB Provider *======@. Setup database variables @ ldv,p s20=NWsql-ole,s20='sa',s20='' . @ ldv,p s40='[Employee Sales by Country]' . @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,c,n,n . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

Results: . Column Description for Procedure: [Employee Sales by Country] *Column Name .Type .Size .DecPt.NF .Length .Precision *======.======.======.=====.=====.======.======|Country |WSTR | 15| |False| 15| |LastName |WSTR | 20| |True | 20| |FirstName |WSTR | 10| |True | 10| |ShippedDate |DBTIMESTAMP | 29| 3|False| 16| 23 |OrderID |I4 | 10| |True | 4| 10 |SaleAmount |CY | 19| |False| 8| 19

..... END REPORT .....

19

Procedure Contents:

CREATE procedure [Employee Sales by Country] @Beginning_Date DateTime, @Ending_Date DateTime AS SELECT Employees.Country, Employees.LastName, Employees.FirstName, Orders.ShippedDate, Orders.OrderID, "Order Subtotals".Subtotal AS SaleAmount FROM Employees INNER JOIN (Orders INNER JOIN "Order Subtotals" ON Orders.OrderID = "Order Subtotals".OrderID) ON Employees.EmployeeID = Orders.EmployeeID WHERE Orders.ShippedDate Between @Beginning_Date And @Ending_Date

5.2.4 P Option w/SQL Server, ODBC Provider This example retrieves the parameter metadata for the stored procedure “Employee Sales by Country”. This procedure is found in the Northwind database on the Microsoft SQL Server. The parameters being described include the two input parameters, plus the return value.

Note that the procedure name is not enclosed with delimiters because we are using the ODBC provider even though the name contains spaces. Also, note that the ‘Type’ field represents the ODBC data type name for this parameter, not the native SQL Server data type.

BIS Script: .P Option w/SQL Server, ODBC Provider *======@. Setup database variables @ ldv,p s20=NWsql-odb,s20='sa',s20='' . @ ldv,p s40='Employee Sales by Country' . @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,p,n,n . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

Results:

. Parameter Description for Procedure: Employee Sales by Country *Parameter Name .Type .Size .DecPt.NF .PType.Length .Precision *======.======.======.=====.=====.=====.======.======|@RETURN_VALUE |INTEGER | 10| 0|False|RV | 10| 10 |@Beginning_Date |TIMESTAMP | 23| 3|True |IN | 23| 23 |@Ending_Date |TIMESTAMP | 23| 3|True |IN | 23| 23 ..... END REPORT .....

20

6. Executing Stored Procedures The SPI statement allows users to execute procedures that are stored in an external database. The SPI statement syntax allows you to specify input and output parameters using BIS variables. Each parameter/variable specified maps to a parameter marker (?) in the specified SP syntax field. The SPI statement supports passing up to 78 parameters using variables, which can be specified as: input, output, input/output, or return-value. The SPI statement will always generate a –0 result with a title line. If the stored procedure generates a result set, the result set will be included in the –0 result. The SPI statement does not support procedures that generate multiple result sets.

When executing a stored procedure, parameters can be included as bound parameters using variables and parameter markers or included in the SP syntax as a literal. E.g. The following three examples are equivalent. Note, that single tic marks are needed by the data provider for literal parameters. Since BIS uses single tic marks for strings, the variable was used for a tic mark.

@ldv s5='OCEAN' . @ldv,p s40='{call custorderhist(?)}' . @spi,0,i,0060,mydb,y,e,n,n i .

@ldv,w h1=tic$ . @ldv,p s40='{call custorderhist('OCEAN)} . @spi,0,i,0060,mydb,y,e,n,n .

@ldv,w h1=tic$ . @spi,0,i,0060,mydb,y,e,n,n '{call custorderhist('OCEAN)} .

21

6.1 Guidelines & Considerations • Microsoft SQL Server always returns a RETURN- VALUE, even if the procedure does not define one. Executing stored procedures may not be consistent This is not true for other databases, such as Oracle. across different databases and different data providers. Using the syntax "{?=call ..." may result in an error if Use these guidelines and considerations to better a return value has not been defined. understand your results. • With the Microsoft data provider for Oracle, you can • Executing stored procedures is only supported for only define input parameters for Oracle stored databases that have a local data provider on a procedures that includes a Result set. You supported Windows platform. The database can cannot define output parameters for these exist on any machine if the local provider is stored procedures. configured to access the database. • Stored procedures that return multiple record sets • Stored procedures can have a maximum of 78 are not supported. passed parameter markers. They are represented as ? (question marks) in the syntax. Additional • Multiple parameter sets are not supported. parameters can be passed if they are passed as literal text in the syntax. • Only simple textual parameters, supported by Business Information Server variables, are • When executing a stored procedure, the sp-syntax supported for stored procedure parameters. Array should always use the "ODBC Procedure Call parameters are not supported. Binary, blobs, and Escape Sequence." Some database providers, such variant data types are not supported. as Oracle, do not support other syntax formats. While other syntax formats may work, they are not • Make sure that the variable type and size are tested or supported with the SPI statement. correctly defined for parameters on the SPI statement. This is particularly important for output • Use caution in constructing the sp-syntax. This parameters. The size of the variable must be large syntax uses the standard "ODBC Procedure Call enough to hold the output value. Otherwise, Escape Sequence," but each data provider supports truncation errors may occur. For example, when different parts of the standard syntax. The unaltered date values are defined in the database, such as sp-syntax is sent directly to the database. Therefore, “datetime”, then the returned value may also include you must construct the correct syntax for the the time value (e.g. 2003-12-01 00:00:00). The database and the data provider being used. For format is determined by the database data type and example, when retrieving a record set from an the conversion algorithm in the data provider. Oracle stored procedure, a different sp-syntax is required depending on how the procedure was constructed and whether you use the Microsoft data provider or the Oracle data provider. See the examples below.

22

6.2 Examples This section shows several examples of using the @SPI statement to execute stored procedures in a database. The examples show a variety of cases to illustrate the features and limitations of the @SPI statement.

These examples assume that you are familiar with writing and executing BIS scripts using MRI statements to access databases. You can find more information in the BIS Help document. In particular, you can find help with configuring ODBC and OLEDB in the “MRI Administration and Users Guide” section of BIS Help.

The first set of examples (6.2.1 - 6.2.3) demonstrate access to Microsoft SQL Server. The next set of examples demonstrates access to the Oracle Database, which is significantly more complex than the SQL Server database. When retrieving a result set from an Oracle stored procedure, the data provider must be chosen to match the procedure being accessed. For example, the stored procedure written for example 6.2.4 was written to be used with the Microsoft data provider and using the keyword “resultset” in the sp-syntax. This stored procedure would execute properly using an Oracle data provider. Refer to the Oracle examples in sections 6.2.4 - 6.2.7. Oracle stored procedures are typically part of a “package”, so the examples below use Oracle packages. An Oracle “Package” consists of two parts; the “specification” part, and the “body” part.

23

6.2.1 SQL Server - 2 Input Parameters, w/OLEDB This procedure is found in the Microsoft SQL Server Northwind database. It takes two input parameters, which define a date range.

BIS Script: . SQL Server - 2 Input Parameters, w/OLEDB *======@. Setup database variables @ ldv,p s20=NWsql-ole,s20='sa',s20='' . @ ldv,p s40='{call [Sales by year](?,?)}' . @ ldv s10='2/1/97' . 1st parameter @ ldv s10='2/11/97' . 2nd parameter @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,e,n,n , i,i . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

Results: . Results of Procedure: {call [sales by year](?,?)} *ShippedDate .OrderID .Subtotal .Year *======.======.======.======|1997-02-06 00:00:00 | 10426| 338.2|1997 |1997-02-04 00:00:00 | 10428| 192|1997 |1997-02-07 00:00:00 | 10429| 1441.37|1997 |1997-02-03 00:00:00 | 10430| 4899.2|1997 |1997-02-07 00:00:00 | 10431| 1892.25|1997 |1997-02-07 00:00:00 | 10432| 485|1997 |1997-02-07 00:00:00 | 10435| 631.6|1997 |1997-02-11 00:00:00 | 10436| 1994.52|1997 |1997-02-10 00:00:00 | 10439| 1078|1997 ..... END REPORT .....

Procedure Contents:

CREATE procedure [Sales by Year] @Beginning_Date DateTime, @Ending_Date DateTime AS SELECT Orders.ShippedDate, Orders.OrderID, "Order Subtotals".Subtotal, DATENAME(yy,ShippedDate) AS Year FROM Orders INNER JOIN "Order Subtotals" ON Orders.OrderID = "Order Subtotals".OrderID WHERE Orders.ShippedDate Between @Beginning_Date And @Ending_Date

24

6.2.2 SQL Server - Output Parameters with Result set This example shows how to call a procedure that has one input parameter, two output parameters, a return value and a result set. Here we can see the full power of the SPI statement in action.

Notice that the output parameters must be defined large enough to hold the full date value being returned. If they are too small, the output value will be truncated. Notice the difference in date formats of the output parameters for the ODBC example and the OLEDB example. ODBC returns “1999-04-23”, while OLEDB returns “Apr 23 1999”. Also, notice that the is only defined to hold 20 characters, which is large enough to hold the entire output for OLEDB, but part of the data is truncated for ODBC. This conversion is controlled by the data provider.

The stored procedure for this example is shown below.

BIS Script: . SQL Server - Output Parameters with Result set, w/ODBC *======@. Setup database variables @ ldv,p s20=acme-odb,s20='mri',s20='' . ODBC Provider @ . ldv,p s20=acme-ole,s20='mri',s20='' . OLEDB Provider @ ldv,p s40='{?=call custord1999(?,?,?)}' . @ ldv i6=0 . Stored Proc Return Value @ ldv s20='13' . Input - customerid @ ldv s20='' . Output - Min order date @ ldv s30='' . Output - Max order date @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,e,n,n ,,, r,i,o,o . @. @ ldv i6=STAT1$ . Save status of SPI statement @ rnm,-0 -1 . Save the results @ brk,0,f . Generate output display

Parameter Details: STAT1: // RV: // P01: // P02: // P03: // @. @ brk add,-0,-1 . Add output area to the results of the SPI statement @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

25

Results w/ODBC Provider: (only the 1st 80 characters of each are shown)

. Results of Procedure: {?=call custord1999(?,?,?)} *OrderNumber.Rep .Description .CustomerName *======.======.======.======... | 99110555|JIL |ELASTOPLAST COVERLET KNUCKLE 100'S |WIMMERS MEATS | 99110555|JIL |CLOTTER TOPICAL BLOOD QUIK-STAT 3 OZ |WIMMERS MEATS | 99110555|JIL |TAPE ADH WATER REPELLANT 1"X10 YD |WIMMERS MEATS | 99117287|JIL |BANDAGE ELASTOPLAST 1"X3" 100'S |WIMMERS MEATS | 99117287|JIL |OINTMENT BACITRACIN 1/32 OZ 144/BX |WIMMERS MEATS | 99122950|JIL |BANDANA COOLING NAVY PRINT |WIMMERS MEATS | 99122950|JIL |HEADBAND COOLING W/VELCRO ROYAL |WIMMERS MEATS | 99122950|JIL |NECK WRAP COOLING ROYAL |WIMMERS MEATS | 99125637|JIL |NECK WRAP COOLING ROYAL |WIMMERS MEATS | 99125637|JIL |HEADBAND COOLING W/VELCRO ROYAL |WIMMERS MEATS | 99125637|JIL |BANDANA COOLING NAVY PRINT |WIMMERS MEATS | 99126244|JIL |OINTMENT BACITRACIN 1/32 OZ 144/BX |WIMMERS MEATS | 99126244|JIL |WIPES CLEANSING 10'S |WIMMERS MEATS | 99126244|JIL |BANDAGE ELASTOPLAST 1"X3" 100'S |WIMMERS MEATS | 99126244|JIL |BURN CERTICAINE SPRAY 2 OZ |WIMMERS MEATS | 99126244|JIL |EYE WASH DACRIOSE 4 OZ |WIMMERS MEATS

Parameter Details: STAT1: / 6001/ RV: /-1 / P01: /13 / P02: /1999-04-23 00:00:00./ P03: /1999-07-07 00:00:00.000 / ..... END REPORT .....

Results w/OLEDB Provider: (the result set is the same as shown for the ODBC above, but the parameter details are different – note the date formats)

Parameter Details: STAT1: / 6001/ RV: /-1 / P01: /13 / P02: /Apr 23 1999 12:00AM / P03: /Jul 7 1999 12:00AM / ..... END REPORT .....

26

Procedure Contents:

CREATE PROCEDURE dbo.CustOrd1999 @CustomerID nchar(5), @FirstDate DateTime = '1/1/1999' OUTPUT, @LastDate DateTime = '1/1/1999' OUTPUT AS SELECT AOrders1999.OrderNumber, AOrders1999.Rep, AProductInfo.Description, ACustomers.CustomerName, AOrders1999.Qty, AOrders1999.Sale, AOrders1999.Cost, ((AOrders1999.Qty*AOrders1999.Sale)- (AOrders1999.Qty*AOrders1999.Cost)) AS Profit FROM AOrders1999 INNER JOIN ACustomers ON AOrders1999.CustomerNumber = ACustomers.CustomerID INNER JOIN AProductInfo ON AOrders1999.ProductNumber=AProductInfo.ProductNumber WHERE (AOrders1999.CustomerNumber = @CustomerID) ORDER BY AOrders1999.OrderNumber

SELECT @FirstDate=MIN(OrderDate),@LastDate=MAX(OrderDate) FROM AOrders1999 WHERE (AOrders1999.CustomerNumber = @CustomerID) RETURN -1

27

6.2.3 SQL Server - Parameterized SELECT Query In addition to executing stored procedures, the SPI statement can execute a parameterized SELECT query. In this example, we do a simple select from the Northwind database using the Microsoft ODBC provider to a SQL Server. We use a parameter marker in the where clause to pass the desired city. Parameter markers can be used anywhere in the SELECT statement, provided that is supported by the data provider. This works against both tables and views.

Non-parameterized SELECT queries can also be executed, allowing you to execute complex select queries using the SPI statement.

BIS Script: . SQL Server - Parameterized SELECT Query *======@. Setup database variables @ ldv,p s20=NWsql-odb,s20='sa',s20='' . @ ldv,p s80='SELECT LastName,FirstName FROM Employees '\ 'WHERE City = ?' . @ ldv,p s20='London' . Input - City @. @ lgn,0199,y,0,a, '',,, . @ spi,0,i,0199,,y,e,n,n i . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

Results: . Results of Procedure: SELECT LastName,FirstName FROM Employees WHERE City = ? *LastName .FirstName *======.======|Buchanan |Steven |Suyama |Michael |King |Robert |Dodsworth |Anne ..... END REPORT .....

28

6.2.4 Oracle DB – ResultSet w/ one input, Microsoft provider for Oracle This is an Oracle stored procedure example that returns a result set containing one input parameter. It uses the Microsoft data provider (either ODBC or OLE DB) for Oracle. The procedure ‘lastname’ is in the package ‘packperson’, which is shown below. The procedure accesses the table ‘Person’.

The interesting part of this example is how the result set is specified. The Oracle database does not explicitly provide a result set the way SQL Server does. Therefore, it is evident that the Microsoft data provider for Oracle uses Oracle ‘tables’ and special syntax in the CALL to retrieve a result set. Compare this with the next example that uses IO_Cursors rather than ‘tables’ to return a result set. Note that the Microsoft data provider for Oracle does not support ‘output’ parameters if you are returning a result set.

In the procedure specification section, three tables (ssn, fname, lname) are defined, one for each column in the result set. In the procedure body section the three tables are filled with the data for the result set. The Microsoft data provider for Oracle uses the following syntax to retrieve the result set:

{resultset maxrows,column1,column2,…} where resultset - is a keyword that flags this operation

maxrows - is the maximum number of rows expected

columnX - is the name of each column to be retrieved

If ‘maxrows’ is too small, an error will occur and no rows are returned. If it is too large, resources are wasted. The column names must match the table names defined in the procedure. For more information on this, refer to the Microsoft Knowledge Base articles – 174981 and 174679.

BIS Script: . Oracle DB - ResultSet w/ one input, MS provider for Oracle *======@. Setup database variables @. MS OLEDB Provider @ ldv,p s20=msora-ole,s20=scott,s20=tiger . @. MS ODBC Provider @ . ldv,p s20=msora-odb,s20=scott,s20=tiger . @ lgn,60,y,0,a, '',,, . Do the logon @ ldv s7=Goodwin . Input parameter @. @ ldv,p s80=\ '{call packperson.lastname(?,{resultset 9,ssn,fname,lname})}' . @ spi,0,i,0060,,y,e,t,n i . Execute it @0060:. @ dsp,-0 . Display the results @ lgf,,, ...... END REPORT .....

29

Results: . Results of Procedure: {call packperson.lastname(?,{resultset 9,ssn,fname,lname})} *SSN .FNAME .LNAME *======.======.======| 555662222|Sam |Goodwin | 123662200|Mary |Goodwin ..... END REPORT .....

Package Contents: Here is the Packperson Package Specification of the Oracle stored procedure.

CREATE PACKAGE PACKPERSON AS TYPE tssn is TABLE of NUMBER(10) INDEX BY BINARY_INTEGER; TYPE tfname is TABLE of VARCHAR2(15) INDEX BY BINARY_INTEGER; TYPE tlname is TABLE of VARCHAR2(20) INDEX BY BINARY_INTEGER; TYPE t_cursor IS REF CURSOR;

PROCEDURE allperson (ssn OUT tssn, fname OUT tfname, lname OUT tlname); PROCEDURE oneperson (onessn IN NUMBER, ssn OUT tssn, fname OUT tfname, lname OUT tlname); PROCEDURE lastname (inname IN VARCHAR2, ssn OUT tssn, fname OUT tfname, lname OUT tlname);

END packperson;

30

Here is the Oracle stored procedure package body. It contains three procedures. We are using the procedure lastname.

CREATE PACKAGE BODY PACKPERSON AS

PROCEDURE allperson (ssn OUT tssn, fname OUT tfname, lname OUT tlname) IS CURSOR person_cur IS SELECT ssn, fname, lname FROM person;

percount NUMBER DEFAULT 1;

BEGIN FOR singleperson IN person_cur LOOP ssn(percount) := singleperson.ssn; fname(percount) := singleperson.fname; lname(percount) := singleperson.lname; percount := percount + 1; END LOOP; END;

PROCEDURE oneperson (onessn IN NUMBER, ssn OUT tssn, fname OUT tfname, lname OUT tlname) IS CURSOR person_cur IS SELECT ssn, fname, lname FROM person WHERE ssn = onessn;

percount NUMBER DEFAULT 1;

BEGIN FOR singleperson IN person_cur LOOP ssn(percount) := singleperson.ssn; fname(percount) := singleperson.fname; lname(percount) := singleperson.lname; percount := percount + 1; END LOOP; END;

31

PROCEDURE lastname (inname IN VARCHAR2, ssn OUT tssn, fname OUT tfname, lname OUT tlname) IS CURSOR person_cur IS SELECT ssn, fname, lname FROM person WHERE lname = inname;

percount NUMBER DEFAULT 1;

BEGIN FOR singleperson IN person_cur LOOP ssn(percount) := singleperson.ssn; fname(percount) := singleperson.fname; lname(percount) := singleperson.lname; percount := percount + 1; END LOOP; END;

END;

Table ‘Person’ Contents: *SSN .FNAME .LNAME *======.======.======| 555662222|Sam |Goodwin | 555882222|Kent |Clark | 666223333|Jane |Doe | 123662200|Mary |Goodwin

32

6.2.5 Oracle DB - ResultSet w/REF Cursor, w/Microsoft providers This example is similar to the previous example that retrieves a result set from an Oracle database using a Microsoft data provider (ODBC or OLEDB) for Oracle. In this example, we use a “REF CURSOR” in the procedure rather than tables. The advantage of using the REF CURSOR is that we do not need to specify the max row count in the syntax. Note that the Microsoft data provider for Oracle does not support ‘output’ parameters if you are returning a result set.

The procedure ‘open_join_cursor1’ is in the package ‘curspkg_join’, which is shown blow. The procedure accesses the table ‘Dept’. In the procedure specification, we define a REF CURSOR that is assigned to “io_cursor”. In the procedure body, we perform a SELECT into the temporary cursor “v_cursor’, which is later assigned to our output cursor ‘io_cursor’. Then the Microsoft data provider for Oracle uses the following syntax to retrieve the result set:

{resultset 0,refcursor} where resultset - is a keyword that flags this operation

0 - (zero) not used, placeholder for row count

refcursor - is the name of REF Cursor with the result set

The refcursor name must match the name defined in the procedure. For more information on this, refer to the Microsoft Knowledge Base articles – 255043.

BIS Script: . Oracle DB - ResultSet w/REF Cursor, MS provider for Oracle *======@. Setup database variables @. MS OLEDB Provider @ ldv,p s20=msora-ole,s20=scott,s20=tiger . @. MS ODBC Provider @ . ldv,p s20=msora-odb,s20=scott,s20=tiger . @ lgn,60,y,0,a, '',,, . Do the logon @ ldv i4=2 . Input - selected dept @. @ ldv,p s80=\ '{call curspkg_join.open_join_cursor1(?, {resultset 0, io_cursor})}' . @ spi,0,i,0060,,y,e,n,n i . Execute it @0060:. @ dsp,-0 . Display the results @ lgf,,, ...... END REPORT .....

Results: . Results of Procedure: {call curspkg_join.open_join_cursor1(?, {resultset 0, io_cursor})} *EMPNO .ENAME .DEPTNO .DNAME *======.======.======.======| 2|John | 20|RESEARCH ..... END REPORT .....

33

Package Contents: Here is the package specification.

CREATE PACKAGE CURSPKG_JOIN AS TYPE t_cursor IS REF CURSOR ;

Procedure open_join_cursor1 (n_EMPNO IN NUMBER, io_cursor IN OUT t_cursor); END curspkg_join;

Here is the package body.

CREATE PACKAGE BODY CURSPKG_JOIN AS Procedure open_join_cursor1 (n_EMPNO IN NUMBER, io_cursor IN OUT t_cursor) IS v_cursor t_cursor; BEGIN IF n_EMPNO <> 0 THEN OPEN v_cursor FOR SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO AND EMP.EMPNO = n_EMPNO;

ELSE OPEN v_cursor FOR SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO; END IF;

io_cursor := v_cursor; END open_join_cursor1; END curspkg_join;

34

Table Specifications (Dept & Emp): CREATE TABLE DEPT (DEPTNO NUMBER(2,0) NOT NULL, DNAME VARCHAR2(14) NULL, LOC VARCHAR2(13) NULL, PRIMARY KEY (DEPTNO) );

CREATE TABLE EMP (EMPNO NUMBER(4,0) NOT NULL, ENAME VARCHAR2(10) NULL, JOB VARCHAR2(9) NULL, MGR NUMBER(4,0) NULL, HIREDATE DATE NULL, SAL NUMBER(7,2) NULL, COMM NUMBER(7,2) NULL, DEPTNO NUMBER(2,0) NULL, (DEPTNO) REFERENCES DEPT(DEPTNO), PRIMARY KEY (EMPNO) );

35

6.2.6 Oracle DB – w/REF Cursor and %ROWTYPE In this example, we use a REF Cursor and %ROWTYPE in the procedure. %ROWTYPE is used to declare a record with the same types as found in the specified database table, , or cursor. The following example works with the Oracle ODBC data provider and the Microsoft ODBC data provider. This procedure accepts one input parameter and returns a result set.

BIS Script: . Oracle DB - w/REF Cursor and %ROWTYPE *======@. Setup database variables @. MS OLEDB provider @ . ldv,p s20=msora-ole,s20=scott,s20=tiger . @. Oracle ODBC provider @ ldv,p s20=ora-odb,s20=scott,s20=tiger . @ lgn,60,y,0,a, '',,, . Do the logon @ ldv,p s10=MANAGER . Input - selected job type @. @ ldv,p s80='{call RefTest.GetEmpData(?)}' . @ spi,0,i,0060,,y,e,n,n i . Execute it @0060:. @ dsp,-0 . Display the results @ lgf,,, ...... END REPORT .....

Results (w/ Oracle ODBC provider):

. Results of Procedure: {call RefTest.GetEmpData(?)} * ...... DEPT *EMPNO .ENAME .JOB .MGR .HIREDATE .SAL .COMM .NO *======.======.======.======.======.======.======.==== | 7566|JONES |MANAGER | 7839|1981-04-02 00:00:00| 2975| | 20 | 7698|BLAKE |MANAGER | 7839|1981-05-01 00:00:00| 2850| | 30 | 7782|CLARK |MANAGER | 7839|1981-06-09 00:00:00| 2450| | 10 ..... END REPORT .....

36

Package Contents:

Here is the package specification.

CREATE package REFTEST as cursor c1 is select * from emp; type empCur is ref cursor return c1%ROWTYPE;

Procedure GetEmpData(en in varchar2,EmpCursor in out empCur); END;

Here is the package body.

CREATE package body REFTEST as Procedure GetEmpData (en in varchar2,EmpCursor in out empCur) is begin open EmpCursor for select * from emp where job=en; end; end;

Table Specifications (Emp): CREATE TABLE EMP (EMPNO NUMBER(4,0) NOT NULL, ENAME VARCHAR2(10) NULL, JOB VARCHAR2(9) NULL, MGR NUMBER(4,0) NULL, HIREDATE DATE NULL, SAL NUMBER(7,2) NULL, COMM NUMBER(7,2) NULL, DEPTNO NUMBER(2,0) NULL, FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO), PRIMARY KEY (EMPNO) );

37

6.2.7 Oracle DB - w/REF Cursor; In, Out, & Resultset This example shows how to execute an Oracle procedure that has one input parameter, one output parameter and a result set. The procedure uses the input parameter to filter the ‘deptno’ and returns the error code as an output parameter. The following example works with the Oracle ODBC data provider and the Microsoft ODBC data provider.

For more information, refer to Oracle documentation for getting Result Sets with an ODBC provider http://otn.oracle.com/docs/tech/windows/odbc/htdocs/817help/sqoraEnabling_Result_Sets_Programming.htm

BIS Script: . Oracle DB - w/REF Cursor; In, Out, & Resultset *======@. Setup database variables @. Oracle ODBC provider @ ldv,p s20=ora-odb,s20=scott,s20=tiger . @. MS OLEDB provider @ . ldv,p s20=msora-ole,s20=scott,s20=tiger . @ lgn,0199,y,0,a, '',,, . Do the logon @ ldv,p s2=20 . Input - deptno @ ldv s6='' . Output - p_errorcode @. @ ldv,p s80='{call employees_orcl.getemprecords(?,?)}' . @ spi,0,i,0199,,y,e,n,n , i,o . Execute it @. @ ldv i6=STAT1$ . Save status of SPI statement @ rnm,-0 -1 . Save the results @ brk,0,f . Generate output display

Parameter Details: STAT1: // Input P01: // Output P02: // @. Add output area to the results of the SPI statement @ brk add,-0,-1 . @0199:. @ dsp,-0 . Display results @ lgf,,, ...... END REPORT .....

38

Results (w/Oracle ODBC provider): . Results of Procedure: {call employees_orcl.getemprecords(?,?)} * ...... DEPT *EMPNO .ENAME .JOB .MGR .HIREDATE .SAL .COMM .NO *======.======.======.======.======.======.======.==== | 1|Smith |Manager | 22|1950-01-01 00:00:00| 50000| 123| 20 | 2|John |Prog | 22|1965-06-15 00:00:00| 40000| 321| 20 | 7369|SMITH |CLERK | 7902|1980-12-17 00:00:00| 800| | 20 | 7566|JONES |MANAGER | 7839|1981-04-02 00:00:00| 2975| | 20 | 7788|SCOTT |ANALYST | 7566|1982-12-09 00:00:00| 3000| | 20 | 7876|ADAMS |CLERK | 7788|1983-01-12 00:00:00| 1100| | 20 | 7902|FORD |ANALYST | 7566|1981-12-03 00:00:00| 3000| | 20

Parameter Details: STAT1: / 6001/ Input P01: /20/ Output P02: /42 / ..... END REPORT .....

39

Package Contents: Here is the package specification.

CREATE PACKAGE EMPLOYEES_ORCL AS TYPE empcur IS REF CURSOR;

PROCEDURE GetEmpRecords(indeptno IN NUMBER, p_cursor OUT empcur, -- Notice the REF CURSOR -- parameter is in the middle! p_errorcode OUT NUMBER);

END employees_orcl;

Here is the package body.

CREATE PACKAGE BODY EMPLOYEES_ORCL AS PROCEDURE GetEmpRecords(indeptno IN NUMBER, p_cursor OUT empcur, p_errorcode OUT NUMBER) IS BEGIN p_errorcode := 0; OPEN p_cursor FOR SELECT * FROM emp WHERE deptno = indeptno ORDER BY empno; p_errorcode := 42; EXCEPTION WHEN OTHERS THEN p_errorcode := SQLCODE; END GetEmpRecords; END employees_orcl;

Table Specifications (Emp): CREATE TABLE EMP (EMPNO NUMBER(4,0) NOT NULL, ENAME VARCHAR2(10) NULL, JOB VARCHAR2(9) NULL, MGR NUMBER(4,0) NULL, HIREDATE DATE NULL, SAL NUMBER(7,2) NULL, COMM NUMBER(7,2) NULL, DEPTNO NUMBER(2,0) NULL, FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO), PRIMARY KEY (EMPNO) );

40

7. Executing Stored Procedures from BIS JavaScript The SPI statement can also be accessed through the new BIS JavaScript to execute stored procedures. Access to the SPI metadata options is not available via the BIS JavaScript interface. Using the “Execute” method of the “Database” object, you can execute stored procedures. The DatabaseArguments object handles the stored procedure parameters, both input and output. Refer to the JavaScript Developer’s Help for more details.

The ‘cmdText’ property provided to the Execute method is the same text provided to SPI’s sp-syntax field. The number of DatabaseArguments specified must match the number of parameter markers (?) in the ‘cmdText’ property. Any returned result set must be stored in a Dataset object (results of Execute method). Any error messages are stored in the “ErrorText” property of the Database object.

Figure 2 – BIS JavaScript Stored Procedure Execution Flow

41

7.1 BIS JavaScript Related Syntax Some of the BIS JavaScript syntax related to executing stored procedures is included here for convenience.

7.1.1 Execute Method of Database Object

Syntax database.execute(cmdText, drawer{, oDbArgs})

Parameters database The name of the Database object instance that is invoking the stored procedure.

cmdText Specifies the stored procedure command to invoke.

drawer The identifier of the drawer for the dataset result. If the stored procedure does not return a dataset, specify "" (an empty string) for this parameter. An exception is returned if a drawer is specified and the stored procedure does not return any dataset result or if an empty string is specified and the stored procedure does return a dataset result.

oDbArgs Optional (depending on the stored procedure being executed). Identifies the DatabaseArguments object instance containing the argument criteria. These are the parameters for the Stored Procedure.

7.1.2 DatabaseArguments Object

Syntax oDbArgs.argument[n].info(directionalType, {argumentValue}) oDbArgs.argument[n].value

Parameters oDbArgs The name of the DatabaseArguments object instance for which this input is specified. n The array index that identifies this argument. info The info method specifies input argument names in the following syntax: info(directionalType, {argumentValue}) directionalType A keyword that identifies the direction of the argument as follows: Keyword Description dbInputArg Indicates the argument is input only to the stored procedure. dbOutputArg Indicates the argument is output only from the stored procedure. dbInOutArg Indicates the argument is input to and output from the stored procedure. dbReturnValue Indicates the argument is an output from the stored procedure based on the cmdText argument ?=call syntax. There can only be at most one argument[] with this directionalType, and it must be the first argument. ArgumentValue Optional. Contains the argument value passed to the stored procedure. The value can be up to 998 characters long. value This read-only property retrieves the return value of the argument specified by argument[n].

42

7.2 JavaScript Example This example demonstrates how to call a stored procedure from a BIS JavaScript. This example uses the same procedure used in example 6.2.2 (SQL Server - Output Parameters with Result set) – “custOdr1999” in a SQL Server database.

A BIS script is setup to call the BIS JavaScript, which executes the stored procedure. The BIS JavaScript run (JSEXP) must be a registered run and flagged as a JavaScript run. Use the Agenda tool to register runs. An ODBC data source must be configured to the SQL Server and the database must be registered in BIS (use the MRIDBA tool).

The BIS script passes one input parameter and receives three output parameters from the called BIS JavaScript. The JavaScript function (GETORD) passes one input parameter to the stored procedure (Custord1999) and receives 2 output parameters. The results from the stored procedure are used to build output data from the BIS JavaScript run, that are then used by the BIS script to display the final result.

BIS Script: .Calling JS Run Example *======@. This run calls a JavaScript registered run, @. which executes a stored procedure. @. @ ldv,p s4='13' . Customer ID @ ldv s80 . Setup result variables @ ldv s80 . @ ldv s80 . @. @. Call the JavaScript registered run @. JSEXP - the registered run - customer id input @. GETORD - the function in the run. ,, - output @ call,"JSEXP" GETORD (,,,) . @. @ lzr,-0,0100 . Check if there is a result @ rnm,-0 -1 . Save the output to -1 @0100:brk,0,f . Generate output Display

Results of Example for Customer ID = @ brk . @ lzr,-1,0110 . Check if -1 was created @. Add current output area to the results of JSEXP call @ add,-0,-1 . @0110:. @ dsp,-0 . Display results ..... END REPORT .....

43

BIS JavaScript: .JavaScript Example - Calling Stored Proc JSEXP *======function GETORD(custid,&min,&max,&cnt) // custid - input customer id { // min, max, cnt - output values try { // Initialize variables var oDs = new Dataset(); // Create new Dataset var oDb = new Database(); // Create new Database var oDbArgs = new DatabaseArguments(); // Create new DBArgs var drawer = "F0"; // Specify drawer type for dataset // Load the input param and Setup the output params oDbArgs.argument[1].info(dbInputArg, custid); oDbArgs.argument[2].info(dbOutputArg); oDbArgs.argument[3].info(dbOutputArg); // Stored Procedure statement var spn = "{call Custord1999(?,?,?)}";

// Logon, and execute Sp with resultset in oDs oDb.logon("acme-odb", "mri", "mri"); // logon to DB oDs = oDb.execute(spn, drawer, oDbArgs); // execute SP

// Process the results & return to caller min = "Min Order Date: " + oDbArgs.argument[2].value; max = "Max Order Date: " + oDbArgs.argument[3].value; cnt = "Number of records: " + oDs.recordCount; ReturnDataset(oDs); // return the dataset

// Process Errors } catch (e) { throw e;

// Final cleanup } finally { oDb.logoff(); // logoff the DB } } ..... END REPORT .....

44

Final Results: (only the 1st 80 characters of each row are shown)

. Results of Procedure: {call Custord1999(?,?,?)} *OrderNumber.Rep .Description .CustomerName *======.======.======.======... | 99110555|JIL |ELASTOPLAST COVERLET KNUCKLE 100'S |WIMMERS MEATS | 99110555|JIL |CLOTTER TOPICAL BLOOD QUIK-STAT 3 OZ |WIMMERS MEATS | 99110555|JIL |TAPE ADH WATER REPELLANT 1"X10 YD |WIMMERS MEATS | 99117287|JIL |BANDAGE ELASTOPLAST 1"X3" 100'S |WIMMERS MEATS | 99117287|JIL |OINTMENT BACITRACIN 1/32 OZ 144/BX |WIMMERS MEATS | 99122950|JIL |BANDANA COOLING NAVY PRINT |WIMMERS MEATS | 99122950|JIL |HEADBAND COOLING W/VELCRO ROYAL |WIMMERS MEATS | 99122950|JIL |NECK WRAP COOLING ROYAL |WIMMERS MEATS | 99125637|JIL |NECK WRAP COOLING ROYAL |WIMMERS MEATS | 99125637|JIL |HEADBAND COOLING W/VELCRO ROYAL |WIMMERS MEATS | 99125637|JIL |BANDANA COOLING NAVY PRINT |WIMMERS MEATS | 99126244|JIL |OINTMENT BACITRACIN 1/32 OZ 144/BX |WIMMERS MEATS | 99126244|JIL |WIPES CLEANSING 10'S |WIMMERS MEATS | 99126244|JIL |BANDAGE ELASTOPLAST 1"X3" 100'S |WIMMERS MEATS | 99126244|JIL |BURN CERTICAINE SPRAY 2 OZ |WIMMERS MEATS | 99126244|JIL |EYE WASH DACRIOSE 4 OZ |WIMMERS MEATS

Results of Example for Customer ID = 13 Min Order Date: 1999-04-23 00:00:00.000 Max Order Date: 1999-07-07 00:00:00.000 Number of records: 16 ..... END REPORT .....

Procedure Contents:

Same as procedure shown in example 6.2.2 SQL Server - Output Parameters with Result set.

45

46

47

For more information visit www.unisys.com

© 2013 Unisys Corporation. All rights reserved.

Unisys, the Unisys logo and ClearPath are registered trademarks of Unisys Corporation. All other brands and products referenced herein are acknowledged to be trademarks or registered trademarks of their respective holders.

Printed in the United States of America 07/13 13-0159