+ All Categories
Home > Technology > PHP and IBM i - Database Alternatives

PHP and IBM i - Database Alternatives

Date post: 12-May-2015
Category:
Upload: zendcon
View: 3,398 times
Download: 0 times
Share this document with a friend
Description:
Talk by Tony Cairns of IBM at ZendCon 2009
Popular Tags:
73
8 Copyright IBM Corporation, 2009. All Rights Reserved. This publication may refer to products that are not currently available in your country. IBM makes no commitment to make available any products referred to herein. PHP and IBM i – Database Alternatives Tony Cairns ([email protected]) Software Developer IBM Systems & Technology Group, Systems Software
Transcript
Page 1: PHP and IBM i - Database Alternatives

8 Copyright IBM Corporation, 2009. All Rights Reserved.

This publication may refer to products that are not currently available in your country. IBM makes no commitment to make available any products referred to herein.

PHP and IBM i – Database Alternatives

Tony Cairns ([email protected])Software DeveloperIBM Systems & Technology Group, Systems Software

Page 2: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Agenda

• Zend Toolkit– Native I/O Calls

– Web Enabling DB2 with PHP using the i5 Toolkit

• DB2 Language Extensions– SQL Compliant Syntax

• IBM DBi Storage Engine

Page 3: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Web Enabling DB2 with PHPNative I/O Calls

Page 4: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 Toolkit APIs

• Are shipped with Zend products

– Zend core for i5/OS

– Zend Platform for i5/OS

• Geared towards accessing i5 data and resources from PHP

– Similar in purpose to the IBM Toolbox for Java

• Note: the I5_COMD job must be running in the ZEND subsystem

– Use the Zend menu to start:• GO ZENDCORE/ZCMENU

• Option 5 (Service Management menu)

• Option 8 (Start I5_COMD service)

Page 5: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Toolkit for i5/OS – list of functions• Connection management

–i5_connect–i5_close–i5_adopt_authority–i5_error–i5_errno–i5_errormsg

»• Command calls

–i5_command»

• Program calls–i5_program_prepare–i5_program_prepare_PCML–i5_program_call–i5_program_close

• Data retrieval

– i5_fetch_array

– i5_fetch_assoc

– i5_fetch_object

– i5_fetch_row

– i5_info

– i5_field_len

– i5_field_name

– i5_field_scale

– i5_field_type

– i5_list_fields

– i5_num_fields

– i5_result

• Native file access

– i5_open

– i5_addnew

– I5_edit

– I5_delete

– i5_cancel_edit

– i5_setvalue

– i5_update

– i5_range_from

– i5_range_to

– i5_range_clear

– i5_data_seek

– i5_seek

– i5_bookmark

– i5_free_file

– i5_new_record

– i5_update_record

– i5_get_keys

Page 6: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Toolkit functions• System values

–i5_get_system_value

»

• Data areas

–i5_data_area_prepare

–i5_data_area_receive

–i5_data_area_send

–i5_data_area_close

• Print/Get spooled file –i5_spool_list

–i5_spool_list_read

–i5_spool_list_close

–i5_spool_get_data

–i5_spool_from_file

• Job logs

–i5_jobLog_list

–i5_jobLog_list_read

–i5_jobLog_list_close

• Active jobs

–i5_job_list

–i5_job_list_read

–i5_job_list_close

• Objects list

–i5_object_list

–i5_object_list_read

–i5_object_list_close

• User space

–i5_userspace_crearte

–i5_userspace_prepare

–i5_userspace_get

–i5_userspace_put

• Data Queue

–i5_dtaq_prepare

–i5_dtaq_recieve

–i5_dtaq_send

–i5_dtaq-close

Page 7: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Toolkit for i5/OS – list of functions

• Connection management–i5_connect–i5_close–i5_adopt_authority–i5_error–i5_errno–i5_errormsg

»• Command calls

–i5_command»

• Program calls–i5_program_prepare–i5_program_prepare_PCML–i5_program_call–i5_program_close

• Data retrieval

– i5_fetch_array

– i5_fetch_assoc

– i5_fetch_object

– i5_fetch_row

– i5_info

– i5_field_len

– i5_field_name

– i5_field_scale

– i5_field_type

– i5_list_fields

– i5_num_fields

– i5_result

• Native file access

– i5_open

– i5_addnew

– I5_edit

– I5_delete

– i5_cancel_edit

– i5_setvalue

– i5_update

– i5_range_from

– i5_range_to

– i5_range_clear

– i5_data_seek

– i5_seek

– i5_bookmark

– i5_free_file

– i5_new_record

– i5_update_record

– i5_get_keys

Page 8: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Toolkit functions• System values

–i5_get_system_value

»

• Data areas

–i5_data_area_prepare

–i5_data_area_receive

–i5_data_area_send

–i5_data_area_close

• Print/Get spooled file –i5_spool_list

–i5_spool_list_read

–i5_spool_list_close

–i5_spool_get_data

–i5_spool_from_file

• Job logs

–i5_jobLog_list

–i5_jobLog_list_read

–i5_jobLog_list_close

• Active jobs

–i5_job_list

–i5_job_list_read

–i5_job_list_close

• Objects list

–i5_object_list

–i5_object_list_read

–i5_object_list_close

• User space

–i5_userspace_crearte

–i5_userspace_prepare

–i5_userspace_get

–i5_userspace_put

• Data Queue

–i5_dtaq_prepare

–i5_dtaq_recieve

–i5_dtaq_send

–i5_dtaq-close

Page 9: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record-level access

•i5_open– Pass in library/file and type of "open" mode

• I5_OPEN_READ, IT_OPEN_READWRITE, I5_OPEN_COMMIT, I5_OPENSHRRD, I5_OPEN_SHRUPD

••i5_list_fields

– Get an array of the names of the fields in the file

•i5_fetch_row– Get an array of the fields in a record, passing in which record to fetch

• I5_READ_SEEK (current)

• I5_READ_NEXT (default)

• I5_READ_PREV

• I5_READ_FIRST

• I5_READ_LAST

Page 10: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record-level access: HTML code

•<form method="post" action=“i5_fetch.php">

•Library (schema): <input type="text" name="lib"><br>

•File (table): <input type="text" name="tbl"><br>

•<input type="reset"> <input type="submit" value="Display records">

•</form>

Page 11: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record-level access: PHP code•// Get input data•$dbfile = $_POST['tbl'];•$dblib = $_POST['lib'];••// Open the file•$file = i5_open("$dblib/$dbfile", I5_OPEN_READ);•if (!$file)• die("Error while attempting to open file mode=READ");••// Print a table row of field names•$fields = i5_list_fields($file); // returns an array•print "<table border=1 cellpadding=3><tr bgcolor=#CCCCCC>";••// Parse the array•foreach ($fields as $value) {• print "<th>$value</th>";•}•print "</tr>\n";

Page 12: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record-level access: PHP code

•// Print records•$rec = i5_fetch_row($file, I5_READ_FIRST); // get array•while ($rec) { // while there is a record...• // Print each field in the array• foreach ($rec as $value) {• print “<td>$value</td>";• }• print "</tr>\n";• // Get next record• $rec = i5_fetch_row($file, I5_READ_NEXT);•}// loop••print "</table>"; // finish off the table

Page 13: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record-level access: PHP codeExample Form and Output

Page 14: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Web Enabling DB2 with PHPUsing the i5 Toolkit

Page 15: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Get Records (i5 toolkit SQL model)

• Recall from our previous discussion that before any of the APIs from the i5 toolkit can be used we must establish a connection to the i5 toolkit daemon process (PGM-EASYCOM job)

• The i5_pconnect() API is being used to establish a persistent connection and avoid costly IBM i startup and termination associated in the i5_connect() and i5_close() APIs.

• Establish a connection is a fairly common activity so a site common include comes in handy

function model_connect() { global $MODEL; $db_options = array(I5_OPTIONS_JOBNAME=>"DVDSEARCH"); $MODEL ['conn'] = i5_pconnect ( $MODEL ['database'], $MODEL ['db_user'], $MODEL ['db_password'], $db_options ); if (! $MODEL ['conn']) { model_error_i5("Connect fail"); return False; } return model_chglibl();

NOTE: Each browser button click will run back through the i5_pconnect() code; however since the connection is cached for each Apache worker job the actual processing time is minimal.

NOTE: In this case each button click will not find it’s way back to the same worker job (more on this later).

Page 16: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 toolkit browser clicks route to different Apache jobs

• Persistent i5 connections means that each “stateless” Apache job will have a common connection to the i5 toolkit

– This common connection will be used by all PHP i5 toolkit applications running, not a single application or job

• Persistent connections does not mean that each browser click will return to the same job

– Do not attempt commit transactions across multiple browser clicks!!

Page 17: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5_pconnect() results in many PGM-EASYCOM jobs

• Supplying a user-id and password to the i5_pconnect() call will spawn multiple PGM-EASYCOM server processes for each different user profile specified

– This behavior is dependent on the Apache user peak demand

•• It is good practice to limit the

number of “active” web profiles.•• A “private” connection can be

used for traditional “state full” RPG applications (more on this later)

Page 18: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5_prepare() and i5_execute()

• The i5 toolkit API combination of i5_prepare() and i5_execute() allows the DB2 engine to optimize and reuse SQL statements many times.

– This can provide improved performance on high volume web sites that have many DB2 calls.

• The i5 toolkit SQL code shown on the following pages replaces the RPG back-end.

• The same function names are used in the i5 toolkit SQL MVC as the i5 toolkit model function names (model_search)

– When we replace the model code with i5 toolkit SQL the view and control code do not have to change (the 5250 code can also remain the same)

Reminder: The i5 toolkit model used APIs to call the RPG model.

Page 19: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 Toolkit SQL code example (slide 1 of x)

<?php function model_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num, &$items) { global $MODEL, $categories; if (!model_connect ()) { False; } $items = array ( ); $prepare = null; $sql = ""; switch($browsetype) { case 'title': $sql .= "select * from products"; $sql .= " where TITLE like '%$browse_title%'"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = i5_prepare($sql); break; case 'actor': $sql .= "select * from products"; $sql .= " where ACTOR like '%$browse_actor%'"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = i5_prepare($sql); break; case 'category': // oops did not plan ahead for this for ($i=1;$i<=count($categories);$i++) { if ($categories[$i-1]==$browse_category) { break; } }

Page 20: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 Toolkit SQL code example (slide 2 of x) $sql .= "select * from products"; $sql .= " where CATEGORY = $i"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = i5_prepare($sql); break; default: break; } if (!$prepare) { model_error_i5("prepare $sql"); return False; } // execute prepared statement $execute = i5_execute($prepare); if (!$execute) { model_error_i5("execute"); return False; } // fetch the row data $i=0; while ($row = i5_fetch_assoc($prepare, I5_READ_NEXT)) { array_push ( $items, array ( $row["PROD_ID"], $row["TITLE"], $row["ACTOR"], $row["PRICE"] ) ); $i++; } if (!$i) { model_error_i5 ( "No DVDs found" ); return False; } return True; }

Page 21: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

DB2 for i5/OS Language Extensions

Page 22: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Accessing DB2/400

• Server/connection– db2_bind_param – db2_client_info – db2_close – db2_connect – db2_cursor_type – db2_exec db2_executedb2_prepare – db2_pconnect – db2_server_info – db2_statistics

• Result– db2_free_result– db2_next_result– db2_result

• Commit/Rollback– db2_autocommit – db2_commit– db2_rollback

• Errors– db2_conn_error

– db2_conn_errormsg – db2_stmt_error – db2_stmt_errormsg

• Column/Procedure– db2_column_privileges

– db2_columns – db2_procedure_column

s – db2_procedures– db2_special_columns

• Table information– db2_num_fields– db2_num_rows– db2_table_privileges– db2_tables

• Fetch– db2_fetch_array– db2_fetch_assoc– db2_fetch_both– db2_fetch_object– db2_fetch_row

• Field information– db2_field_display_

size– db2_field_name– db2_field_num– db2_field_precision– db2_field_scale– db2_field_type– db2_field_width

• Key information– db2_foreign_keys– db2_primary_keys

• Statement– db2_free_stmt All of these APIs are documented online at php.net

- Preferred db2_ SQL statement execution APIs (performance)• - Non-preferred db2_ SQL statement execution API

Page 23: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

• There are few connections options in PHP– db2_connect(“”,””,””) – local server

• The database connection job is create under the same user as the Apache httpd server profile NOBODY (*USER).

– db2_connect(“*LOCAL", “SAM", “PASSWROD")– local server • The database connection job is created under the user profile SAM/PASSWROD.

– db2_connect(“10.1.1.33", “SAM", “PASSWROD") – remote database connection job is created under the user server

• The profile SAM/PASSWROD.

– –

Server connection – db2_connect API

● Tip: Use WRKRDBDIRE to get the database name on the remote

Page 24: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 Toolkit vs. DB2 Extensions

• The i5 Toolkit represents functions for accessing native i5/OS resources– The toolkit is specific to the Zend products for i5/OS

– The toolkit functions can only access local resources (i.e., resources on the same i5/OS partition as Zend Core) unless you setup remote connections (such as DDM) outside of the Zend Core environment.

– All i5 Toolkit functions begin with the characters “i5_”

• The DB2 functions represent an extension to the PHP language– The DB2 extensions are starting to become part of the mainstream php language

offering and will be available on platforms other the i5/OS– The DB2 extensions can access both local and remote DB2 resources through

established network connections– All DB2 functions begin with the characters “db2_”

Page 25: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

i5 Toolkit vs. DB2 Extensions

PASE

i5_*I5_COMD

i5/OS

TCP/IP

i5/OS

Zend Core

db2_*

I5/OS

Resource

I5/OS

Resource

db2_*

Page 26: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Anatomy of a Web-Enabled DB2 for i5/OS (via PHP) application

Page 27: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Application Description

• We will take a look at a single PHP application.

• The application will create an employee information search and retrieval form

• All of the following code would be saved in a single file (ex: employee_update.php)

– As you will see, we can use HTML form fields to allow the application to re-call itself for different functions within the application.

Page 28: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Employee Search Form

• When invoked (through a Web Browser) this code will generate a blank web page with a title bar of “Employee Update – employee_update.php”)

<html><?phpdefine("PAGE_TITLE", "Employee Update");define("PHP_FILE_NAME", "employee_update.php")?><title><?= PAGE_TITLE . " - " . PHP_FILE_NAME; ?></title><body><?php ?></body></html>

Page 29: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Employee Search Form

• The following block of code will cause the Employee Search form to be displayed. This block of code is inserted between the <?php tag and the corresponding ?> tag

/* Display the initial Employee Search form and the $_POST lastname field *//* When the Search button is selected. */print '<h1>Enter the first few characters of the employee records you' . 'wish to view/edit in the last name field.</h1>';print '<h2>For example, "JO":</h2>';print '<form action="employee_update.php" method="POST">';print 'Last Name: <input type="text" name="lastname" /> <br />';print '<input type="submit" name="action" value="Search" />';print <'/form>';

• This block of code outputs in the HTML stream instructs for what is to be entered into the form along with the HTML to generate the form information.

Page 30: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Search Action

• The following block of code implements the search function– This function uses the values entered on the Employee Search Form to open the database and

perform the search action– This block of code would be inserted between the <?php tag and the /* Display comment

/* Include System i connection information */if ((include "../i5_properties.php") == false) { echo("Problem encountered loading i5_properties.php include file");}

/* Set up connection for each pass through this application */$dbh = db2_connect($db, $user, $password);if (!$dbh) :die ("Problems connecting to the database.");endif;

1

2

3

1. The if statement causes a separate PHP file that contains a number of variable definitions for the program (including database name, user credential information) to be included

2. The db2_connect() call is one of the calls from the DB2 for i5/OS extensions – it establishes a connection to the database server and returns a handle to the indicated database.

3. The if statement tests that a valid handle to the database was returned and if not the application terminates (via the die language construct)

Page 31: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Database Query

• The next section of code performs the database query and places the results on the Employee Search Results form.

– The code would be placed between the </form> line and the second ?> php end tag } else

{ /* Query file using input from form and deliver results to client */ /* Construct SQL statement, using lastname as the search substring */ $sql = 'select * from i5schema.employee where lastname like \'' .$_POST["lastname"]. '%\''; /* Execute the DB2 SQL statement, place results into $stmt */ $stmt = db2_exec($dbh, $sql, array('cursor' => DB2_SCROLLABLE)); /* Print Employee Search Results header and table setup */ print '<h1>Employee Records On System i starting with ' . $_POST["lastname"]. '</h1>'; print '<br><table border=1 cellpadding=5 cellspacing=5>'; /* Iterate through result set, printing one table line per */ /* record returned. Note that the customerNumber field will */ /* be an "active field" which will $_GET the customerNumber */ /* and reinvoke the employee_update.php application*/

1

2

3

1. This statement assigns an SQL select statement to the $sql variable. The SQL statement includes values entered on the Employee Search from

2. The db2_exec() statement causes the SQL statement to be executed against the database that was opened previously with the db2_connect() function call.

3. The print statements will output in the HTML stream for the first part of the search results form which includes a header line indicating what records are being displayed as well as a table that will contain the returned records

Page 32: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Database Query

while ($row = db2_fetch_array($stmt)) { if (!$row=="") { $customerNumber = $row[0]; $customerName = $row[3]; $customerFirst = $row[1]; $workdept = $row[4]; $job = $row[7]; $salary = $row[11]; print '<tr><td align=center><a href=employee_update.php?customerNumber=' . $customerNumber . '>' . $customerNumber . '</a><td>'. $customerName.'<td>'. $customerFirst.'<td>'. $workdept.'<td>'. $job.'<td>'. $salary.'</td></tr>'; } } /* Close table */ print '</table><br>'; /* Print the DB2 SQL statement which was executed - Informational */ print "<p>Echo of dynamically-built sql: ".$sql."</p>";}

4

5

6

4. The while loop iterates through the records returned by the db2_exec() function call (as represented by the $stmt variable) and outputs them into the HTML table.

• Each time through the loop the db2_fetch_array() function will return an array of values representing a row in the result set

5. Notice that the employee number ($customerNumber) is output as an actionable tag (i.e., it will be a selectable link on the HTML page)

• This is accomplished through the ‘href’ statement which causes this php application to be re-called when the tag is selected

6. The HTML tag to close the HTML table is output along with outputting the SQL statement that was executed.

Page 33: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Database Query Notes• Using the db2_exec() statement to insert PHP variable values into an

SQL statement can be considered a security exposure. – Rather then using the db2_exec() statement the db2_prepare() statement

could be used to prepare an SQL statement with parameter markers for input values.

– Then the db2_execute() statement could be used rather then the db2_exec() statement to pass in the input values.

• When the PHP file is invoked (from a Web Browser) the search form is displayed. Entering data into the Last Name field and selecting the [Search] button causes the Query code to be executed and the results to be displayed in the web form

Page 34: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Database Query – Employee Record Edit

• This code will determine which record to place on the Edit form. The code is invoked when an employee number is selected from the search results window

– This code would be placed between the $action = $_POST[“action”] and the if(!$action) lines

$customerNumber = $_GET["customerNumber"];2 /* Determine which form to display based upon the state of the application */if ($customerNumber == "") {

1

2

1. The employee number selected on the search results form is retrieved from the URL and assigned to the $customerNumber variable

2. The test of the $customerNumber field is performed to see if this block of code was reached after an employee number was selected from the search results window.

• Remember that this PHP code generates both the Employee Search as well as the Employee Search Results pages

Page 35: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Edit Record

• The following code displays the values of a record and allows the user to edit those values

– This code would be placed between the bracket (}) line and the second ?> php tag} else { /* Edit the selected customer number record */ /* Construct SQL statement, using customerNumber to select the record */ $sql = 'select * from i5schema.employee where empno = \'' .$_GET["customerNumber"]. '\''; /* Execute the DB2 SQL statement, place results into $stmt */ $stmt = db2_exec($dbh, $sql, array('cursor' => DB2_SCROLLABLE)); /* Place the field information returned into array $row */ $row = db2_fetch_array($stmt); /* If there is data, move information from result array into fields */ /* which will be used for screen display */ if (!$row=="") { $customerNumber = $row[0]; $customerName = $row[3]; $customerFirst = $row[1]; $workdept = $row[4]; $job = $row[7]; $salary = $row[11]; }

1

2

3

4

1. The select statement establishes the query using the customer number that the user selected from the HTML form

2. The db2_exec() function call executes the query

3. The db2_fetch_array() function call retrieves an array of fields values from a record in the return set from the db2_exec() function call

4. The if statement tests to ensure that a record was returned from the db2_fetch_array() call. If a record was returned, local variables are used to tore the field values.

Page 36: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Edit Record/* Display the Employee Edit form and $_GET all fields */ /* when Update button is selected. */ print '<h1>Edit an Employee record:</h1>'; print '<form action="employee_update.php" method="GET">'; print 'Customer Number: <input type="text" name="customerNumber" value="'.$customerNumber.'" /> <br />'; print 'Last Name: <input type="text" name="customerName" value="'.$customerName.'" /> <br />'; print 'First Name: <input type="text" name="customerFirst" value="'.$customerFirst.'"/> <br />'; print 'Work Department: <input type="text" name="workdept" value="'.$workdept.'"/>'; print 'Job Type: <input type="text" name="job" value="'.$job.'"/> <br />'; print 'Salary: <input type="text" name="salary" value="'.$salary.'"/> <br />'; print '<input type="submit" name="action" value="Update" /><a href=employee_update.php?customerNumber=' . $customerNumber .'&customerName=' .$customerName.'&customerFirst='.$customerFirst.'&workdept='. $workdept.'&job='.$job.'&salary='.$salary.'&action='.$submit.'></a>'; print '</form>';}

5

5. A series of print statements are used to output text labels as well as the contents of the returned record

Page 37: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Edit Record – Notes

• The print ‘<form’> along with the print ‘<input> line (italicized in the code for emphasis) will cause the program to place the “Update” action onto the URL line when the Update button is selected

– Each of the field values are also placed into the URL string.

– This causes the application to “call” itself again.

– The URL string values are retrieved using the $_GET function and then used in the SQL update call (coming up)

• When the PHP program is invoked and a record is searched for and selected the Results form will display the Employee Edit Record form with the values from the selected record

Page 38: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record Update

• This code is invoked when the [Update] button is selected from the Edit page.

• The code updates the DB2 for i5/OS table using the user modified fields.• Once the record has been updated an HTML form is output with the SQL

statement along with an indication of whether or not the update was successful.

• The first section of code determines the state of the application, that is has the user selected the [Update] button from the Edit page.

• The following code would replace the $action = $_POST[“action”] line of code which is just prior to the $customerNumber = $_GET[“customerNumber’] statement

$action = $_GET["action"];/* if no value from $_GET, try $_POST */if (!$action) { $action = $_POST["action"];}

Page 39: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record Update

• The section of code that resembles the following

} } else { /* Edit the selected customer number record */

• Would be changed to resemble the following (i.e., remove the beginning close bracket on the else statement

} else { /* Edit the selected customer number record */

Page 40: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record Update

• The following block of code would be placed before the else { /* Edit the selected customer number record */ statement

} else { /* Update Employee table, or edit the selected customer record */ if ($action == "Update") { $sql = 'update i5schema.employee set lastname = 2 \''.$_GET["customerName"].'\','. ' firstnme = \''.$_GET["customerFirst"].'\','. ' workdept = \''.$_GET["workdept"].'\','. ' job = \''.$_GET["job"].'\','.3 ' salary = '.$_GET["salary"]. ' where empno = \'' .$customerNumber.'\'';4 $result = db2_exec($dbh, $sql);

1

2

3

1. The if statement determines whether or not the user requested the Update action from the Edit Record form.

• If the update action was invoked then the remaining code is executed

2. The assignment statement generates the SQL update statement using values passed from the calling form

3. The db2_exec() function call executes the SQL update statement returning the results into the $result variable.

Page 41: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record Update

if (!$result) { echo '<p>There was a problem inserting the user into the database.</p>'; print '<p>Echo of dynamically-built sql:<br>'.$sql.'</p>';5 } else { print '<h1>Update Successful</h1>';5 print '<form action="employee_update.php" method="POST">'; print '<p>Echo of dynamically-built sql:<br>'.$sql.'</p>'; print '<input type="submit" name="action" value="Continue" /><a href=employee_update.php></a>'; print '</form>'; } }

4

5

4. The if statement tests the result returned from the db2_exec() call. • If an error was encountered by the update statement an error message is output to the

HTML form.

• If the update statement was successful a success message is output along with the actual SQL statement that was executed by the db2_exec() function call.

5. The <form> line along with the <input> line causes the program to place the “Continue” action onto the URL string when the [Continue] button is selected. The program will then be automatically re-invoked.

• In addition to the above code a line containing a closing bracket (}) would need to be placed before the second ?> php end tag at the bottom of the application

Page 42: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Record Update – Notes Page

• Now when the application is invoked, searching for a set of records, selecting a record from the returned set, edit the values and selecting the [Update] button will cause the record to be updated and a web page similar to the following to be displayed

Page 43: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Continue

• The final piece of code that we need to look at is the code that processes selection of the [Continue] button.

• When the [Continue] button is selected, the application will be reset back to the Employee Search form

• In the following section of code:

/* Determine which form to display based upon the state of application */if ($customerNumber == "") {if (!$action) {

• The if (!$action) line would be replaced with the following

if ((!$action) or ($action == "Continue")) {

• The check for the “Continue” action will cause the Search form to be displayed when the [Continue] button is selected from the Update database form.

Page 44: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

<?php define('APP_BASE_DIR', '/www/zendcore/htdocs/qiwikiCode/'); include_once APP_BASE_DIR.'101Config.php'; /* Site: site configuration */ include_once APP_BASE_DIR.'101Connectdb2.php'; /* Model: ibm_db2 connect */ include_once APP_BASE_DIR.'101DB2Model.php'; /* Model: ibm_db2 SQL */ include_once APP_BASE_DIR.'101HtmlView.php'; /* View: plain old generated html */ include_once APP_BASE_DIR.'101HtmlControl.php'; /* Control: main loop html forms */ ?>

Why MVC

• Recall that we are using the MVC model to separate out the model, view, and controller components of the program

– This makes it easy to replace one component without affecting the others.

• In this example, the same PHP view/control code as in the previous i5 call RPG program example is used.

– Now a different include_once for the MVC ibm_db2 model is used

• In this example, the RPG back-end (the model) is being replaced with PHP ibm_db2

– A new DB2 model include_once is used to handle the connections to ibm_db2

Page 45: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Get Records (ibm_db2 model)Establish a connection • In an earlier module we looked at the i5_toolkit calls which uses the

i5_connect (and i5_pconnect) to connect to the PGM-EASYCOM jobs.– A daemon approach is used that monitors a socket for in-coming

connections that are started by the Zend core menus and subsystems.

• The ibm_db2 language extension uses in-line calling and/or special memory shipping if going between QSQ server jobs and Apache worker jobs.

• Simply put, different connection methods are used by these two facilities as then come from different sources. The ibm_db2 language extension comes from IBM while the i5_toolkit calls comes from another PHP vendor.

Page 46: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

PHP Get Records (ibm_db2 model)Using db2_pconnect vs db2_connect• The db2_pconnect() API supports

persistent connections

• The db2_connect() API does not support persistent connections

• Use of the db2_pconnect() API can improve performance of web-sites when they are experiencing heavy user web demand

function model_connect() { global $MODEL; $db_options = array("i5_naming"=>DB2_I5_NAMING_ON); $MODEL ['conn'] = db2_pconnect ( $MODEL ['database'], $MODEL ['db_user'], $MODEL ['db_password'], $db_options ); if (! $MODEL ['conn']) { model_error_db2("Connect failed"); return False; } return model_chglibl(); }

Use of persistent connections is absolutely required if the site services multiple requests per second.

The php.ini configuration file can be updated to force all db2_connect() calls to use db2_pconnect() instead

• Notice the array(“i5_naming”=>DB2_I5_NAMING_ON)

– libl changes via db2_set_option(“i5_libl”=>) will work with unqualified table names

– It is likely that for stored procedure calls to an RPG program, the RPG program would also likely need the library list set.

Tip! Setting DB2_I5_NAMING_ON for the whole set simply works better on IBM i. Mixing DB2_I5_NAMING_ON/OFF almost always leads to problems on the site

Page 47: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

db2_connect() browser clicks route to different Apache jobs

• The use of a persistent db2 connection only means that each “stateless” Apache job will have a common connection to db2

– This common connection will be used by all PHP ibm_db2 applications running, not just a single application or “job”.

• Persistent connections does not mean that each browser click will return to the same job

Tip! Do NOT attempt db2_commit() transactions across multiple browser clicks!!!

Page 48: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

db2_pconnect() results in many QSQ jobs

• Supplying a user-id and password to the db2_pconnect() call will spawn a QSQ db2 server process for each different user profile specified for each Apache worker job

Tip! It is a good practice to limit the number of “active” web profiles.

NOTE: Once the QSQ job has been spawned there will be little difference between profiles (assuming that db2_pconnect() was used)

Tip! Mixing db2_pconnect(“”,””,””) and db2_pconnect(“*LOCAL”,”uid”,”pwd”) can lead to unpredictable results – pick a profile or two to handle web clients and stick with those.

Page 49: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

What about db2_connect?

• Recall from the previous slide that a QSQ db2 server process is spawned for each different user profile for each Apache worker job

– In the case of db2_connect, the QSQ job starts and stops with each db2_connect() and db2_close() call.

– This is a performance degredation over the use of the persistent db2_pconnect() call – especially for those sites with heave traffic and many requests per second.

Page 50: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

db2_prepare() and db2_execute() vs. db2_exec()

• Use of the db2_prepare() and db2_execute() API combination allows the DB2 engine to optimize and reuse SQL statements many times.

– Use of these APIs on high volume web sites can provide a performance boast over db2_exec()

• The ibm_db2 code shown on the next slides replaces the RPG back end.

– The MVC model function names have been kept exactly the same as the i5 toolkit model function names (model_search)

– When the model code is replaced with ibm_db2 the view and control model do not change (the 5250 code will also remain the same)

Page 51: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

<?php function model_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num, &$items) { global $MODEL, $CATEGORIES; if (!model_connect ()) { return False; } $link_id = $MODEL ['conn']; $items = array ( ); $prepare = null; $sql = ""; switch($browsetype) { case 'title': $sql .= "select * from products"; $sql .= " where TITLE like '%$browse_title%'"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = db2_prepare( $link_id, $sql); break; case 'actor': $sql .= "select * from products"; $sql .= " where ACTOR like '%$browse_actor%'"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = db2_prepare( $link_id, $sql); break; case 'category': // oops did not plan ahead for this for ($i=1;$i<=count($CATEGORIES);$i++) { if ($CATEGORIES[$i-1]==$browse_category) { break; } } $sql .= "select * from products"; $sql .= " where CATEGORY = $i"; $sql .= " FETCH FIRST $limit_num ROWS ONLY"; $prepare = db2_prepare( $link_id, $sql); break;

db2_prepare() and db2_execute()Code Sample (slide 1 of 2)

Page 52: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

default: break; } if (!$prepare) { model_error_db2("prepare $sql"); return False; } // execute prepared statement $execute = db2_execute($prepare); if (!$execute) { model_error_db2("execute"); return False; } // fetch the row data $i=0; while ($row = db2_fetch_assoc($prepare)) { array_push ( $items, array ( $row["PROD_ID"], $row["TITLE"], $row["ACTOR"], $row["PRICE"] ) ); $i++; } if (!$i) { model_error_db2 ( "No DVDs found" ); return False; } return True; }

db2_prepare() and db2_execute()Code Sample (slide 2 of 2)

Page 53: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

db2_prepare() and db2_execute()Another Code Sample – Populate database table

• In this example, db2_prepare() and db2_execute() are being used to populate the database table

// Populate the products table $products = array ( // 1= Action array(1, 1, 'Death Car', 'Brad Baldwig', 3.22, 1), array(2, 1, 'Super Car', 'Gwen Midriff', 3.22, 1), // 2 = Animation array(3, 2, 'Happy Frog', 'Fred Flimflam', 6.22, 1), array(4, 2, 'Happy Toad', 'Fred Flinflam', 6.22, 1), // 3 = Horror array(5, 3, 'Creek of Doom', 'Chris Wock', 25.99, 1), array(6, 3, 'River of Doom', 'Chris Wock', 25.99, 1), // 4 = Sci-Fi array(7, 4, 'Alien of Troy', 'Chris Wock', 25.99, 1), // 5 = Sports array(8, 5, 'Runner Beware', 'Bruce Henpecked', 5.31, 1), // 6 = Travel array(9, 6, 'Ships, ships, ships','Bear Greenwood', 3.33, 1), ); $insert = "INSERT INTO $lib.PRODUCTS"; $insert .= " (PROD_ID, CATEGORY, TITLE, ACTOR, PRICE, SPECIAL)"; $insert .= " VALUES (?,?,?,?,?,?)"; $stmt = db2_prepare($conn, $insert);

Page 54: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

db2_prepare() and db2_execute()Another Code Sample – Populate database table

• In this example, db2_prepare() and db2_execute() are being used to populate the database table

if($stmt) { foreach($products as $row) { $r = db2_execute($stmt, $row); if (!$r) { die("<br>bad insert ".db2_stmt_errormsg() ); } else { $nrows = db2_num_rows($stmt); echo ("<br>INSERT $nrows row data = ".implode(",", $row) ); } } }

Page 55: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

API Level Check

• A quick level check on some of the APIs that we’ve talked about:

• The db2_pconnect() API should be used over the db2_connect() API as db2_pconnect() supports persistent connections:

$conn = db2_pconnect("","",""); // persistent connect

• The db2_prepare() and db2_execute() APIs should be used over the db2_exec() API for optimization and reuse of SQL statements

$prep = db2_prepare($conn,"sql"); // prepare statement $retc = db2_execute($prep); // execute prepared statement

Page 56: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Methods (APIs) for fetching data

• There are a number of choices in PHP for fetching data:

Returns an object in which each property represents a column returned in the row fetched from a result set.

db2_fetch_object()

Returns an array, indexed by both column name and position, that represents a row in a result set. Keep in mind that the row returned by db2_fetch_both() will require more memory than the single-indexed arrays returned by db2_fetch_assoc() or db2_fetch_array()

db2_fetch_both()

Returns an array, indexed by column name, that represents a row in a result set.

db2_fetch_assoc()

Returns an array, index by column position, that represents a row in a result set. Column indexing starts at 0.

db2_fetch_array()

Page 57: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Methods (APIs) for fetching data

• There are a number of choices in PHP for fetching data:

while ($row = db2_fetch_array($prep)) // one syscall per row (SQLBindCol) { $name = $row[0]; $breed = $row[1]; }

while ($row = db2_fetch_assoc($prep)) // one syscall per row (SQLBindCol) { $name = $row["NAME"]; $breed = $row["BREED"]; }

NOTE: In all these different examples, $prep represents the resource that contains the result set.

while ($row = db2_fetch_both($prep)) // one syscall per row (SQLBindCol) { $name = $row[0]; $breed = $row[1]; // -- or – $name = $row["NAME"]; $breed = $row["BREED"]; }

while ($row = db2_fetch_object($prep)) // one syscall per row (SQLBindCol) { $name = $row->NAME; $breed = $row->BREED; }

All of the db2_fetch options discussed bring the contents of the entire row back to PHP in one system call via the SQLBindCol interface

Page 58: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

What about db2_fetch_row() / db2_result()

• Second-tier APIs such as db2_fetch_row() and db2_result() should be used only when other fetch options fail.

$conn = db2_pconnect("","",""); // persistent connect $stmt = db2_prepare($conn,"sql"); // prepare statement $retc = db2_execute($prep); // execute prepared statement while (db2_fetch_row($stmt)) // syscall here { $name = db2_result($stmt, 0); // another syscall here $breed = db2_result($stmt, 1); // another syscall here }

• A performance issue with db2_fetch_row() / db2_result() will be encountered

– Fields are retrieved by systems calls all the way through the i5 kernel via SQLGetData

Page 59: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Avoid meta data APIs• The following ibm_db2 APIs should be used as a last option as of the DB2 meta

data APIs result in a heavy performance impact– If possible avoid use these in the main application flow path

• db2_client_info

• db2_column_privileges

• db2_columns

• db2_cursor_type

• db2_escape_string

• db2_field_display_ size

• db2_field_name

• db2_field_num

• db2_field_precision

• db2_field_scale

• db2_field_type

• db2_field_width

• db2_foreign_keys

• db2_get_option

• db2_num_fields

• db2_num_rows

• db2_primary_keys

• db2_procedure_columns

• db2_procedures

• db2_server_info

• db2_set_option

• db2_special_columns

• db2_statistics

• db2_table_privileges

• db2_tables

NOTE: Detailed information on this APIs can be found in the online PHP manual (http://www.php.net/manual/en

Page 60: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

IBMDB2i Storage Engine

Page 61: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Storage Engines•• A key strength of MySQL is it’s pluggable storage architecture.• This architecture allows you to select a specialized storage engine for a particular

application need• Different storage engines can be used for different tables within the same

database schema

• Key differentiations– Concurrency/Locking

– Transaction Support

– Physical Storage

– Index Support

– Memory Caches

– Performance Aids

Page 62: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Storage Engines

• Two tier approach– Upper tier includes the SQL parser and optimizer– Lower tier comprises a set of storage engines

•• The SQL tier is free of dependencies on which storage engine manages any

given table•• Clients do not need to be concerned about which engines are involved in

processing SQL statements.

Page 63: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Integrating MySQL with DB2• DB2 Storage Engine for MySQL supports open source applications while

simplifying data management– Applications written to MySQL, but data stored in DB2

– One database to manage, backup, and protect

• Integrates access to MySQL data from RPG, DB2 Web Query, …

MySQL server

Application Written to MySQL (Example

SugarCRM)

alter table tablename ENGINE=IBMDB2iDB2 DB2

storage storage engineengine

MyISAM Storage Engine

SpecialtySpecialtystoragestorageenginesengines

DB2i Storage Engine

Page 64: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

IBMDB2i – the newest MySQL storage engine

• Developed to allow existing MySQL-based applications to use DB2 for i for the data store.

• Only general-purpose storage engine designed to allow access to data from outside of MySQL

• Fully-featured, it implements all applicable storage engine operations (some occasional restrictions apply)

• Can be used as a drop-in replacement with most web applications

• Distributed and supported by MySQL

DB2 for i

New RPGApplication

Existing PHPApplication

MySQLIBMDB2I

Page 65: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Leveraging MySQL Data with DB2 Web Query• SugarCRM is a PHP application

written to MySQL

• DB2 Storage Engine enables SugarCRM data to be stored in DB2

• DB2 WebQuery can access SugarCRM data

• Using DB2 Web Query SDK and Report Broker you can integrate reporting into SugarCRM

SugarCRM

MySQL

DB2 for i

Writes to

Data stored in

AccessesData

DB2 Web Query

Page 66: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Storage Engine Comparison

• Comparison of features between popular MySQL Storage Engines

MyISAM InnoDB IBMDB2I

Usage Fastest for read heavy applications

Fully ACID compliant transactions

Fully ACID compliant; data visible externally

Locking Large-grain table locks, no non-locking reads

Multi-versioning, row-level locking

Row-level locking

Durability Table recovery Durability recovery Durability recovery

Supports Transactions

NO YES YES

Supports foreign keys NO YES YES

Allows access through DB2 for i interfaces

NO NO YES

• DB2 Storage Engine Also supports Multiple character sets (ASCII, Far East, and Unicode) All MySQL replication configurations All widely-used data types (including LOB-based)•

Page 67: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Getting started with IBMDB2I• Requirements:

– IBM i 5.4 or later– MySQL version 5.1 for IBM i (IBMDB2I plugin is included by default)– Enabling PTFs (PTF numbers still pending)

• Starting MySQL and installing the IBMDB2I storage engine plugin--just three easy steps

1. Start the MySQL server• bin/mysqld_safe &

2. Start a client connection• bin/mysql –u root

3. Install the plugin (requires appropriate MySQL user authority)• INSTALL PLUGIN ibmdb2i SONAME “ha_ibmdb2i.so”;

• Now MySQL tables can be created directly into DB2– CREATE TABLE test.t1 (i INT) ENGINE=ibmdb2i;

Page 68: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

How does it work?• An SQL statement on an IBMDB2I table is sent to the MySQL server.

• The server parses and optimizes the statement.– No DB2 optimization involved

• The IBMDB2I storage engine is called by the server to perform operations associated with the statement.

• IBMDB2I passes the operation to the QSQSRVR job associated with the MySQL application connection

– DDL operations (CREATE TABLE, ADD INDEX, etc.) are re-constructed as DB2 SQL statements and executed.

– I/O (read/insert/delete/update) is done row-by-row via a native I/O interface

• Results are returned to the server and then to the client.

MySQLClient

Client IBMDB2I

QSQSRVR

QSQSRVR

Page 69: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Usage Notes

• Most MySQL identifiers are stored in DB2 with outer quotes to preserve case sensitivity.

– create table db1.sales (orderno int) engine = ibmdb2i;– The above creates the DB2 table ”sales” in schema “db1”.

•• DB2 triggers, constraints, and indexes can be added outside of MySQL but are not

used by MySQL.•• Errors are mapped to MySQL errors when possible.•• However, DB2-specific errors are often reported as messages in the joblog of the

corresponding QSQSRVR job. The MySQL error log contains detailed information about the error and the job (when possible).

•• Security on DB2 tables is handled by the normal IBM i and DB2 mechanisms

– All DB2 tables accessed by IBMDB2I are accessed under the profile used to start the mysqld program.

– Existing MySQL user security mechanisms control access to the tables via MySQL. MySQL users are distinct from IBM i user profiles.

Page 70: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Getting MySQL to Recognize Existing DB2 tables

• The IBMDB2I storage engine does not recognize DB2 tables and indexes that are created outside of MySQL

– The storage engine does not have the ability to auto-detect existing DB2 tables

•• To enable MySQL to access an existing DB2 table, need to dump the table definition

& data from DB2 and create the table definition & data in MySQL – There are data attributes and features in DB2 that are not supported in MySQL

•• Example Steps

1. Generate the Data Definition Language from the DDS. This is done through the QSQGNDDL API

2. Scrub the resulting DDL to make it compliant with MySQL3. Dump the records from the DB2 table into a CSV file. This is done using the copy from

import file (CPYFRMIMPF) command.4. Using the MySQL command ‘mysqldump’ to import the table definition. Make sure that

you have specified the DB2i storage engine5. Use the MySQL command ‘LOAD DATA INFILE’ to load the data into the MySQL data.

Make sure that you have specified the DB2i storage engine

Page 71: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Using the DB2 Storage Engine• --default_storage_engine=ibmdb2i

– Causes tables to be created with IBMDB2I if no engine is explicitly specified. Useful when installing third party applications. The default storage engine is MyISAM otherwise.

• --ibmdb2i_rdb_name=xxxxxx– Causes IBMDB2I to use the specified RDB. Only tables in this RDB can be used when this

option is specified. Default is QSYS.–

• --ibmdb2i_transaction_unsafe=0/1– Specifies whether transactions should be respected. Setting this to 1 causes IBMDB2I to

approximate MyISAM transactional behavior. Default is 0.–

• The storage engine associated with a table can be switched at any time– As easy as ‘ALTER TABLE myisamtable ENGINE=ibmdb2i;’– Causes all data to be copied over during the alter.– Makes moving existing MySQL web app data into DB2 trivial.

Page 72: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation

Expanding Access To Data

DB2 DB2 storagestorage

ILE Applications (RPG, Cobol, etc)

IBMDB2I

DB2 server*

* Leverage IBM i functions such as journaling, SAV/RST and DB2 Web Query

PHP

MySQL

IBM i

Apache

AMP Stack for i

Page 73: PHP and IBM i - Database Alternatives

© 2009 IBM Corporation


Recommended