You are on page 1of 32

Invoking Web services from SQL

Integrating relational data with Web services using DB2


Skill Level: Intermediate Tim Brown DB2 Universal Database Solutions Expert IBM James Magowan Web Services and Data Grids IBM

09 Jan 2003 Developing applications that access both Web services and database management systems can be an overwhelming task. It doesn't need to be. This tutorial demonstrates how to generate DB2 user-defined functions (UDFs) that provide access to Web services. The generated UDFs can be used in SQL statements to combine relational data with dynamic data retrieved from a Web service. Several different examples are provided.

Section 1. Before you start


About this tutorial
Web services provide access to distributed applications. They are increasingly used to integrate information processing within and between enterprises. When building service-based applications, Web services often need to be integrated with relational data. To accomplish this, applications must access both Web services and database management systems. The Web services consumer converts existing WSDL interfaces into DB2 table or
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 1 of 32

developerWorks

ibm.com/developerWorks

scalar functions. Web service consumer User Defined Functions (UDFs) can enable databases to directly invoke Web services using SQL. By using SQL to access Web Services data, you save effort because you can manipulate the data within the context of an SQL statement. You might think using these Web service consumer UDFs in SQL statements could be time consuming or require advanced programming skills. This tutorial will show you otherwise. It will guide you through the steps to: Enable your database for Web Service consumer UDFs Create Web service consumer UDFs using WebSphere Studio Application Developer wizard Create Web service consumer UDFs using the DB2 command line After generating and deploying the UDFs, they can be used by application programs to combine relational data with dynamic data retrieved from the Web service. Examples are given to show how to use the UDFs in SQL statements. This tutorial assumes basic knowledge of Web services, DB2 SQL, and WebSphere Studio Application Developer V5.1.1. If you are not familiar with Web services, or you could use a refresher, developerWorkshas an excellent introductory tutorial on Web services (see Resources ).

Prerequisites
To complete the steps in this tutorial, you'll need the following software installed and running: DB2 Universal Database V8.1 FixPack 4 WebSphere Studio Application Developer V5.1.1. This is optional - you can use the DB2 command line but Application Developer makes it much easier. A free trial version DB2 Universal Database V8.1 is available from the developerWorks download page. This tutorial has been revised from one originally created by Marcus Schneider and Dan Wolfson (IBM Distinguished Engineer).

Notices and trademarks


Copyright, 2003 International Business Machines Corporation. All rights reserved.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 2 of 32

ibm.com/developerWorks

developerWorks

IBM, DB2, DB2 Universal Database, DB2 Information Integrator, WebSphere and WebSphere MQ are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both. Other company, product, and service names may be trademarks or service marks of others.

Section 2. Getting started


Enable XML Extender
DB2 Web service consumer user-defined functions have been available as standard since Fix Pack 2 for DB2 v8. They are not, however, enabled by default and do require DB2 XML Extender functionality to be enabled. DB2 XML Extender allows XML documents to be stored intact and indexed in side tables, or as a collection of relational tables. It uses an XML document format called the Document Access Definition (DAD) to define the mapping between XML and relational data. If you have any problems with the following instructions, refer to the DB2 Web services consumer documentation available from Resources. To enable XML Extender execute the following commands from a DB2 command line: 1. 2. Connect to the database you want to enable: db2 connect to database_name Enable the database for XML Extender: dxxadm enable_db database_name

Issuing these commands against the sample database results in the following output:
DXXA002I Connecting to database "SAMPLE". DXXA005I Enabling database "SAMPLE". Please wait. DXXA006I The database "SAMPLE" was enabled successfully.

Five system user-defined functions to handle SOAP are provided. These must be registered by issuing the following command:

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 3 of 32

developerWorks

ibm.com/developerWorks

db2enable_soap_udf -n database_name -u username -p password [-force] The -forceattempts to drop any existing functions. To disable the SOAP UDFs, use the following command: db2disable_soap_udf -n database_name -u username -p password The enable command copies the shared library containing the implementation of the soap functions to your sqllib/function directory. To check that you enabled the database correctly, verify the following UDFs are defined. From within the Control Center, go to Application Objects =>User Defined Functions. This should list the following:
Name SOAPHTTPV SOAPHTTPV SOAPHTTPC SOAPHTTPC SOAPHTTPCL Schema DB2XML DB2XML DB2XML DB2XML DB2XML Specific Name SOAPHTTPVIVO SOAPHTTPCIVO SOAPHTTPCICO SOAPHTTPVICO Result VARCHAR VARCHAR CLOB CLOB Input Parameters

(VARCHAR(),VARCHAR(),VARCHA (VARCHAR(),VARCHAR(),CLOB()) (VARCHAR(),VARCHAR(),CLOB())

(VARCHAR(),VARCHAR(),VARCHA

SOAPHTTPVICLO CLOB

(VARCHAR(),VARCHAR(),VARCHA

Also check to ensure db2soapudf.dll appears in your sqllib/function directory. Note:With Windows XP it may be necessary to drop the -u and -p options from the commands. HTTP proxies are not currently supported for Web Service Consumer User Defined Functions. That can cause problems when invoking the Web service.

Section 3. Create a UDF using the wizard


Launch the wizard
Before you create a Web service UDF, create a project for use with the Web service UDF. To create a new project:

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 4 of 32

ibm.com/developerWorks

developerWorks

1. 2. 3.

Click File =>New =>Project... from the menu bar. Use the Simple Project Template. Create a connection to the database that you just enabled. From the DB Servers view, right-click the view and select New Connection... To import the database to the project, right-click the connection and select Import to Folder... and import into your project.

You are now ready to generate your first Web service UDF. To start the wizard that generates the UDFs: 1. 2. Select File =>New =>Other. Select Dataand Web Service User-Defined Function as shown below.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 5 of 32

developerWorks

ibm.com/developerWorks

3.

Click Nextto proceed.

Select a WSDL
On the first page of the wizard, specify the WSDL file that will be used to generate the UDF. This can be done by using the Browse... button to select a WSDL file from the workspace or by specifying a URL. For this scenario, use a currency exchange rate Web service that takes two countries as input parameters and returns the currency exchange rate between them. Copy the following URL and paste it into the text field: http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 6 of 32

ibm.com/developerWorks

developerWorks

Click Next.

Select a database
The next page of the wizard shows the database connection and schema for which the UDF will be generated. The wizard requires that the database is enabled for the SOAP UDFs and XML Extender. This can be verified by the presence of the DB2XML schema. If no connection to the specified database is available, a pop-up window asks for connection information.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 7 of 32

developerWorks

ibm.com/developerWorks

1. 2.

Click Browseto select a database schema from the Application Developer workspace. Choose to deploy the generated UDF into the database immediately or generate a UDF model in the Application Developer workspace only. The UDF can be deployed later by selecting the newly created UDF in the dataview, right-click it and select Build.

3.

Click Next.

Select a UDF
This page shows operations from the WSDL document. The wizard will generate one UDF for every operation that is selected. Since the Web service used for this
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 8 of 32

ibm.com/developerWorks

developerWorks

example provides only one operation, this is automatically selected. Click Next.

Specify UDF options


For every operation selected, the options page appears. It allows you to specify options for the UDF, such as changing the function name and providing a comment. You can choose whether to build a scalar or table function. By default, a scalar function will be generated when a simple XML type is returned from the Web Service operation and a table function when a complex XML type is returned. The table

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 9 of 32

developerWorks

ibm.com/developerWorks

function automatically maps the complex XML type into one or more columns. Switching from a table function to a scalar function makes sense when the returned types should not be automatically mapped, but returned as an XML fragment. On the other hand, switching from a scalar to a table function enables the use of the UDF in a FROM clause. It also makes it possible to include the input parameters as columns in the output table when you select the echo input parameters check box. When the service location (the locationattribute of the soap:addresselement) is not specified in the WSDL document, a dynamic function must be generated. You can select this check box even when the service location is specified to make use of late binding. When a dynamic function is generated, you need to specify the service location at run time as a parameter of the UDF. When using a Web service that can return responses of more than 3000 characters, select big SOAP response. By default, small SOAP responseis selected because it results in better performance for most Web services. If you select small SOAP responseand the Web service returns a SOAP message that is too big, the UDF will return a descriptive error message. The ability to return the whole SOAP envelope without parsing it can be useful for debugging purposes.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 10 of 32

ibm.com/developerWorks

developerWorks

To review and/or change the mapping of WSDL types to DB2 SQL types for each parameter, click the Parameter tab

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 11 of 32

developerWorks

ibm.com/developerWorks

To specify the name for the UDF, click the Advance Options tab. If the name is not specified, then a unique name is automatically generated by the database when the UDF is deployed.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 12 of 32

ibm.com/developerWorks

developerWorks

Review your settings


The summary page shows the database, schema, and the create statement to be issued against the database. Clicking Finish generates the UDF. If you selected the generate and deploy option on the database connection page (see Select a database ), clicking Finish also deploys the UDF.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 13 of 32

developerWorks

ibm.com/developerWorks

Run the Web service UDF


Run the Web Service UDF directly from the workspace. If the UDF was generated but not deployed, you need to build the UDF. From the Data Definition view in the UDF folder, right-click the User-Defined Function you created and select Buildfrom the context menu. The generated UDF is placed in the UDF folder of the selected

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 14 of 32

ibm.com/developerWorks

developerWorks

database. To run the deployed UDF, right-click on the UDF and select Run. The Run Settings window is displayed.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 15 of 32

developerWorks

ibm.com/developerWorks

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 16 of 32

ibm.com/developerWorks

developerWorks

From the Run Settings window, enter the parameter values and click OK.

The result values of the UDF are shown in the Output view.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 17 of 32

developerWorks

ibm.com/developerWorks

Section 4. Create a UDF using the command line


The SOAP UDF's
In the previous section, you generated a UDF to act as Web Service consumer. This was done using the GUI tool provided in WebSphere Application Developer. An alternative to this, is to create the statement to generate the UDF manually and to use the DB2 command line to build the UDF. The first step is to introduce the Web services consumer UDFs and explain their parameters. Then, you'll see how to obtain the correct values for those parameters by going through the WSDL for the 'delayed Stock Quote' Web service, a Web service provided by xmethods. The db2xml.soaphttp()is a DB2 UDF that composes a SOAP request, posts the request to the service endpoint, receives the SOAP response, and returns the content of the SOAP body. The function is overloaded (either VARCHAR()or CLOB() ) depending on the soap body.
db2xml.soaphttpv returns VARCHAR(): db2xml.soaphttpv ( endpoint_url VARCHAR(256), soap_action VARCHAR(256), soap_body VARCHAR(3072)) | CLOB(1M)) RETURNS VARCHAR(3072)

db2xml.soaphttpc returns CLOB(): db2xml.soaphttpc ( endpoint_url VARCHAR(256), soapaction VARCHAR(256), soap_body VARCHAR(3072) | CLOB(1M)) RETURNS CLOB(1M)

db2xml.soaphttpcl returns CLOB() as locator: db2xml.soaphttpcl( endpoint_url VARCHAR(256), soapaction VARCHAR(256), soap_body varchar(3072)) RETURNS CLOB(1M) as locator

DB2 requires the following information to build a SOAP request and receive a SOAP response: Service endpoint, e.g. http://services.xmethods.net/soap/servlet/rpcrouter SOAP action URI reference (it is optional and may be null string i.e., '' )

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 18 of 32

ibm.com/developerWorks

developerWorks

XML content of SOAP body, which are: name of operation with request namespace URI, encoding style, and input arguments

From WSDL to Web service consumer function


Part of the WSDL for 'Delayed Stock Quote Request' Web service is shown below. It describes the details of the web service interface. It also provides the description such as how to connect to the Web service and invoke the operation. Below is an extract from the WSDL for the 'Delayed Stock Quote Request' Web service. Analyze the WSDL to find out how to map the elements of this WSDL to parameters of Web service consumer functions. The text in bold are the values used to define the UDF.
<![CDATA[<binding name='net.xmethods.services.stockquote.StockQuoteBinding' type='tns:net.xmethods.services.stockquote.StockQuotePortType'> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='getQuote'> <soap:operation soapAction=]]> 'urn:xmethods-delayed-quotes#getQuote' <![CDATA[/> <input> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </input> <output> <soap:body use='encoded' namespace=]]> 'urn:xmethods-delayed-quotes' encodingStyle= 'http://schemas.xmlsoap.org/soap/encoding/' <![CDATA[/> </output> </operation> </binding> <service name='net.xmethods.services.stockquote.StockQuoteService'> <documentation> net.xmethods.services.stockquote.StockQuote web service </documentation> <port name='net.xmethods.services.stockquote.StockQuotePort' binding='tns:net.xmethods.services.stockquote.StockQuoteBinding'> <soap:address location=]]> 'http://66.28.98.121:9090/soap' <![CDATA[/> </port> </service> ]]>

Test the Web service consumer functions

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 19 of 32

developerWorks

ibm.com/developerWorks

Test the Web service consumer functions by accessing the stock quote for IBM: 1. 2. 3. Open a DB2 command window. Connect to the database that you enabled for SOAP functions (example: SAMPLE). Create a file called getquote.sql and copy the following command into the file and save it.

<![CDATA[VALUES db2xml.soaphttpv ( ]]> 'http://66.28.98.121:9090/soap' <![CDATA[, ]]> 'urn:xmethods-delayed-quotes#getQuote' <![CDATA[, varchar ('<stock:getQuote xmlns:stock=]]> " urn:xmethods-delayed-quotes "<![CDATA[ SOAP-ENV:encodingStyle=]]> " http://schemas.xmlsoap.org/soap/encoding/ "<![CDATA[> <symbol xsi:type="xsd:string"> ]]> IBM <![CDATA[</symbol> </stock:getQuote> ' ) );]]>

Using the DB2 command window execute the UDF:


db2 -tvf getquote.sql

The results should be similar to the following:


<![CDATA[<n:getQuoteResponse xmlns:n="urn:xmethods-delayed-quotes"> <Result xsi:type="xsd:float"> 97.33</Result> </n:getQuoteResponse> ]]>

Create a wrapper UDF for a Web service

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 20 of 32

ibm.com/developerWorks

developerWorks

To improve the readability of code, wrap the call to a Web service in another UDF and invoke this UDF every time you want to invoke a Web service operation. In this case, instead of calling db2xml.sopahttpv(...)every time you make a stock quote request, create a wrapper UDF that takes only the stock symbol as a parameter and internally calls the db2xml.soaphttpv(...). Define the wrapper UDF getStockQuote which takes only one parameter, namely, symbol as a VARCHAR(256) and returns Result as FLOAT. Below is the code for the getStockQuote UDF. The result of the call to db2xml.soaphttpvis a CLOB. Hence we extract the value contained in the Result element pointed to by the XPath <![CDATA['/*/Result']]> .
<![CDATA[CREATE FUNCTION ]]> SchemaName <![CDATA[.getStockQuote (symbol VARCHAR(100))RETURNS DECIMAL(5,2) SPECIFIC xmethods_getQuote LANGUAGE SQL CONTAINS SQL EXTERNAL ACTION NOT DETERMINISTIC RETURN db2xml.extractREAL( db2xml.xmlclob( db2xml.soaphttpv( ]]> 'http://66.28.98.121:9090/soap' <![CDATA[, ]]> 'urn:xmethods-delayed-quotes#getQuote' <![CDATA[, varchar('<m:getQuote xmlns:m="]]> urn:xmethods-delayed-quotes <![CDATA[" SOAP-ENV:encodingStyle="]]> http://schemas.xmlsoap.org/soap/encoding/ <![CDATA["> <symbol xsi:type="xsd:string"> ' || ]]> symbol <![CDATA[ || '</symbol></m:getQuote> ' ) ) ), '/*/Result' )]]>

This UDF can be invoked in the DB2 command line as follows:


DB2 VALUES SchemaName. getStockQuote('IBM')

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 21 of 32

developerWorks

ibm.com/developerWorks

Test the Web service consumer table functions


So far the consumer UDF for Web services returned only a single value. DB2 also allows the writing of UDF's that invoke Web services returning multiple results. In such cases a table with each row containing one result element is returned. For example, take the Web service Xignite News provided by Xignite.com. The WSDL for this is available at http://www.xignite.com/xnews.asmx?WSDL. One of the operations provided by this Web service is GetStockHeadlines. The following UDF shown below, can be used to access this Web service operation.
<![CDATA[CREATE FUNCTION ]]> SchemaName <![CDATA[.GetStockHeadlines (Symbols VARCHAR(100), HeadlineCount INTEGER ) RETURNS TABLE (StockNews VARCHAR(3000)) LANGUAGE SQL CONTAINS SQL EXTERNAL ACTION NOT DETERMINISTIC RETURN Select * from Table (db2xml.extractVarchars( db2xml.xmlclob( db2xml.soaphttpc( 'http://www.xignite.com/xnews.asmx', 'http://www.xignite.com/services/GetStockHeadlines', '<m:GetStockHeadlines xmlns:m="http://www.xignite.com/services/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> ' || '<m:Symbols> ' || Symbols || '</m:Symbols> ' || '<m:HeadlineCount> ' || rtrim(char(HeadlineCount) ) || '</m:HeadlineCount> ' || '</m:GetStockHeadlines> ' ) ), '//StockNews/Headline') ) as X ]]>

In this wrapper UDF, only the Headline elements from the result of the Web service is extracted, a table is constructed from these elements and then the table is returned. You can invoke this UDF as follows: select * from table ( SchemaName. GetStockHeadlines('IBM', 10)) as x By issuing the above query, you should see 10 or less news headlines related to IBM stock as can be seen in the results below.
<![CDATA[STOCKNEWS --------------------------------------------------------------------IBM and ATB Financial Sign Largest IT Services Agreement of Its Kind in Western Canada [external] IBM Seen Struggling With Growth Problems

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 22 of 32

ibm.com/developerWorks

developerWorks

SCO Escalates Legal Battle on Three Fronts Hewlett-Packard Unveils High-End Copy Machines [external] Oracle Needs to See Beyond PeopleSoft [external] NEWS: Online Extra: What It "Boils Down To" For Kodak Coverage initiated on IBM by Banc of America Sec [external] ONLINE ASIA: An Irresistable Offshore Tide for Jobs [external] Hewlett-Packard Set to Make Amends Sun gives key certification to two small software cos 10 record(s) selected.]]>

Section 5. Using the user-defined function


Example data
The generated UDFs allow you to use data from Web services together with relational data. The following tables are used in examples throughout this section to show how Web service UDFs can be used. Below is the required DDL and SQL to build and populate these tables. The code which is used to create the UDF to consume from the Currency Exchange Web service is also included. To create and populate the tables for this example, run the following DDL and SQL at a DB2 command prompt:
db2 create table countries( COUNTRY VARCHAR(5)) db2 insert into countries values('us'),('euro'),('uk') db2 create table products( PRODUCT CHARACTER(5), PRICE DECIMAL(10,2)) db2 insert into products values('GEAR', 950.00), ('NUT', 50.00), ('BOLT', 100.00), ('SCREW', 40.00)

The results should look similar to the following tables. Products


Product GEAR NUT BOLT SCREW Price 950.00 50.00 100.00 40.00

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 23 of 32

developerWorks

ibm.com/developerWorks

Countries
Country us euro uk

Following is the code which creates the UDF to consume the Currency Exchange Web service.
<![CDATA[CREATE FUNCTION schemaname.getRate (country1 VARCHAR(100), country2 VARCHAR(100)) RETURNS DECIMAL(10,5) SPECIFIC xmethods_getRate LANGUAGE SQL CONTAINS SQL EXTERNAL ACTION NOT DETERMINISTIC RETURN db2xml.extractREAL( db2xml.xmlclob( db2xml.soaphttpv( 'http://66.28.98.121:9090/soap', 'urn:xmethods-CurrencyExchange#getRate', varchar( '<m:getRate xmlns:m="urn:xmethods-CurrencyExchange" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <country1 xsi:type="xsd:string"> ' || country1 || '</country1> <country2 xsi:type="xsd:string"> ' || country2 || '</country2> </m:getRate> ' ) ) ), '/*/Result' );]]>

Example 1
To test the function, use the following command, which will give you the exchange rate for Euro's per Dollar:
db2 values schemaname.getrate('us','euro')

The result is
0.80680

. The currency exchange rate function can be used to display price information in
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 24 of 32

ibm.com/developerWorks

developerWorks

Euros instead of US dollars by accessing real-time exchange rates. Note that the built-in decimalfunction is used to cast the price information into a more readable output format.
db2 select product, decimal(schemaname.getRate('us', 'euro') * price, 10, 2) as "EUR_Price" from products

Product GEAR NUT BOLT SCREW

EUR_Price 766.46 40.34 80.86 32.27

Example 2
You can also use relational data as input to the Web service. This example shows how the currency exchange rate function can be used to display price information in different currencies.
db2 SELECT p.product, c.country, decimal(schemaname.getRate('us', c.country) * price, 10, 2) as Price FROM products p, countries c

Product GEAR NUT BOLT SCREW GEAR NUT BOLT SCREW GEAR NUT BOLT SCREW

Country us us us us euro euro euro euro uk uk uk uk

Price 950.00 50.00 100.00 40.00 766.46 40.34 80.86 32.27 511.48 26.92 53.84 21.53

If this query is commonly issued, it might be convenient to define a view to provide a


Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 25 of 32

developerWorks

ibm.com/developerWorks

simpler interface. The definition of this view is:


CREATE VIEW prices AS SELECT p.product, c.country, decimal(schemaname.getRate('us', c.country) * price, 10, 2) as Price FROM p.products, c.countries

The following simple query obtains the results:


SELECT * FROM prices

Example 3
The statement in this example illustrates how a UDF generated as a table function can be used in a FROM clause. For this example, the getRate-UDF was regenerated as a table function and the input parameters were echoed into the output table (see Specify UDF options ).
SELECT t.* FROM countries c, table( schemaname.getRate('us', c.countries) ) t

Country1 us us us

Country2 us euro uk

Result +1.00000000000000E+000 +1.07280000000000E+000 +6.84800000000000E-001

Section 6. Application scenario


Purchase order example
Let's look at a more comprehensive example to demonstrate the abilities of Web service UDFs. In the following example, we look at a manufacturing company that works with a number of suppliers around the world. To achieve a cost-effective and fast business process, the company and its suppliers agree on three capabilities that allow the company to get price quotes for proposed purchases, make a purchase, and check on the order status. By implementing these capabilities as Web services,

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 26 of 32

ibm.com/developerWorks

developerWorks

users in the company are able to call these services from a wide variety of platforms and application environments, including a DB2 application. Each supplier offers three Web service operations that can be expressed with the following abstract signatures: getQuote (in String partNum, in Integer qty, in Date desiredDate, out Decimal price, out String currency, out Date proposedDate) purchase (in String partNum, in Integer qty, out String poNumber, out Date commitDate) getStatus (in String poNum, out String status)

Dynamic invocation
As shown in earlier sections, having a WSDL description makes it relatively easier to generate Web service UDFs for these operations. However, in this example, there are multiple service providers (suppliers) that all offer the same Web service. Here you can make use of dynamic invocation and generate one UDF for each operation that can access multiple service providers. On the Specify options page of the wizard (see Specify UDF options ), select late bindingfor the UDF. Next, you need to specify the location of the Web service as the first parameter of the UDF. From the getStatusoperation, generate a UDF with this signature:
varchar(20) GET_STATUS (url varchar(80), po_num varchar(20))

The return value is the purchase order (PO) status, and the input parameters are the URL to which the request is to be sent and the identity of the purchase order in question. Table 1 shows outstanding purchase orders, and Table 2 contains information about the Web service operations each supplier offers. Table 1: Table for purchase_orders
supplier SupplierA SupplierB SupplierC po_num 12345 22345 32345 date 3/20/02 6/20/02 5/04/02 part_num A4 C7 D7 qty 34 43 3

Table 2: Table for supplier_ops


supplier SupplierA SupplierA operation getStatus getStatus url http://www.suppliera.com/getStatus http://www.suppliera.com/getStatus
Trademarks Page 27 of 32

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

developerWorks

ibm.com/developerWorks

SupplierA SupplierB SupplierB

getQuote getQuote getStatus

http://www.suppliera.com/getQuote http://www.supplierb.com/services/getQuote http://www.supplierb.com/services/getStatus

To find the status of a specific purchase order from a single supplier, issue the following SQL statement:
values GET_STATUS('http://www.suppliera.com/getStatus', '12345')

To obtain the status of all outstanding purchase orders from SupplierA:


SELECT supplier, po_num, GET_STATUS('http://www.suppliera.com/getStatus', po_num) AS po_status FROM purchase_orders WHERE supplier = 'SupplierA'

To find the status of all outstanding purchase orders from suppliers who offer a Web service interface, perform the operation over a set of service providers:
SELECT p.supplier, p.po_num, GET_STATUS (s.url, p.po_num) AS po_status FROM purchase_orders p, supplier_ops s WHERE p.supplier = s.supplier AND s.operation = 'getStatus'

Table functions
So far, you have been working with a function that returns a single value. The getQuote function returns multiple values. Therefore, create this function as a DB2 table function with input and output parameters as shown in Table 3. Note that the Echo input parameters check box was selected on the Specify options page (see Specify UDF options ) to include all the input values in the return table. Table 3: Parameters for the GET_QUOTE table function
Name Input url supplier part_num qty desired_date Output url supplier
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Type varchar(80) varchar(30) varchar(20) integer date varchar(80) varchar(30)


Trademarks Page 28 of 32

ibm.com/developerWorks

developerWorks

part_num qty desired_date price currency proposed_date

varchar(20) integer date decimal varchar(10) date

To invoke the GET_QUOTE table function within a query:


SELECT * FROM TABLE(GET_QUOTE('http://www.suppliera.com/getQuote', 'SupplierA', '52435FFA', 25, '7/1/2001')) t

This statement returns a table containing a single row with the response from SupplierA. To handle suppliers in other countries, the GET_QUOTE function contains currency units. To convert the price into dollars, use the getRate function from the currency exchange Web service:
SELECT t.supplier, t.part_num, t.qty, (t.desired_date - t.proposed_date) AS timeliness, getRate('us', t.currency)* t.price AS cost FROM TABLE(GET_QUOTE('http://www.suppliera.com/getQuote', 'SupplierA', '52435FFA', 25, '7/1/2001')) t

To reflect the difference between the desired date and the date proposed by the supplier for the part, make the columns explicit and define an output column, timeliness. Again, this query returns a single row with the quote from a single vendor for a single part. Table 4 contains a list of needed parts. Table 4: Parameters for the GET_QUOTE table function
part_num 34asfd 253kkb kj324 qty 20 34 10 desired_date 7/1/2001 8/1/2001 6/30/2001

To get a quote on all these parts from the supplier:


SELECT t.supplier, n.part_num, n.qty, (n.desired_date - t.proposed_date) AS timeliness, getRate('us', t.currency)* t.price AS cost FROM TABLE(GET_QUOTE('http://www.suppliera.com/getQuote', 'SupplierA', n.part_num, n.qty, n.desired_date)) t

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 29 of 32

developerWorks

ibm.com/developerWorks

This query returns a row of quotes for each part listed in the needed_parts table from SupplierA. To get quotes for each of the suppliers:
SELECT t.supplier, n.part_num, n.qty, (n.desired_date - t.proposed_date) AS timeliness, getRate('us', t.currency)* t.price AS cost FROM needed_parts n, supplier_ops s, TABLE(GET_QUOTE(s.url, s.supplier, n.part_num, n.qty, n.desired_date)) t WHERE s.operation = 'GET_QUOTE' ORDER BY cost, timeliness

This query generates quotes for all the needed parts from all the suppliers that offer the getQuote Web service and returns a table of these quotes ordered by part number and timeliness.

Section 7. Wrap up
Summary
This tutorial showed you how to generate Web service UDFs with WebSphere Studio Application Developer V5.1.1 and the DB2 command line to access Web services from database applications. Using the wizard, you can quickly generate and easily test Web service UDFs. The generated UDFs facilitate access to dynamic data sources and allow them to be easily integrated into DB2 applications.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 30 of 32

ibm.com/developerWorks

developerWorks

Resources
Learn WebSphere Studio Application Developer developerworks Web services zone W3C Simple Object Access Protocol (SOAP) 1.2 W3C Web Services Description Language (WSDL) 1.1 "Web services - the Web's next revolution" An excellent introduction to Web services. XML Extender Administration and Programming (PDF) Stay current with developerWorks technical events and webcasts. Get products and technologies DB2 Universal Database DB2 XML Extender Build your next development project with IBM trial software, available for download directly from developerWorks. Discuss Participate in the discussion forum for this content.

About the authors


Tim Brown Tim Brown is certified as a DB2 Universal Database Solutions Expert and is part of IBM Software Group Services. He has been with IBM for 6 years and currently works with a small team of DB2 experts who provide technical consultants services to customers across many industries in the UK and across Europe. Tim's expertise covers problem determination, problem correction, database administration, database design, database application development, database replication and skills transfer. More recently Tim has spent his time working with DB2's Web services functionality and has written a document which looks at how to implement and use all the Web services functionality provided with DB2.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 31 of 32

developerWorks

ibm.com/developerWorks

James Magowan James Magowan has spent 7 years with IBM working on leading edge customer facing projects. He has worked in High Performance Computing with large SP installations before playing with Linux clusters ahead of IBM's Linux strategy. He has recently worked on Grid Computing Projects since January 2001 including European DataGrid and OGSA-DAI (Open Grid Services Architecture - Database Access and Integration) and was heavily involved within the Global Grid Forum chairing two working groups. These Grid projects have given him experience with Service Orientated Architectures and Data Grids. He has been working with Web Services and Data Grids for the last 3 years.

Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.

Trademarks Page 32 of 32

You might also like