PHP and IBM i - Database Alternatives
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

PHP and IBM i - Database Alternatives

on

  • 4,604 views

Talk by Tony Cairns of IBM at ZendCon 2009

Talk by Tony Cairns of IBM at ZendCon 2009

Statistics

Views

Total Views
4,604
Views on SlideShare
4,591
Embed Views
13

Actions

Likes
3
Downloads
63
Comments
0

1 Embed 13

http://www.slideshare.net 13

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

PHP and IBM i - Database Alternatives Presentation Transcript

  • 1. PHP and IBM i – Database Alternatives Tony Cairns (adc@us.ibm.com) Software Developer IBM Systems & Technology Group, Systems Software 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.
  • 2. 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 • • • © 2009 IBM Corporation
  • 3. Web Enabling DB2 with PHP Native I/O Calls © 2009 IBM Corporation
  • 4. 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) © 2009 IBM Corporation
  • 5. PHP Toolkit for i5/OS – list of functions • Connection management • Data retrieval • Native file access –i5_connect – i5_fetch_array – i5_open –i5_close – i5_fetch_assoc – i5_addnew –i5_adopt_authority – i5_fetch_object – I5_edit –i5_error – i5_fetch_row – I5_delete –i5_errno – i5_cancel_edit – i5_info –i5_errormsg – i5_setvalue – i5_field_len » – i5_update – i5_field_name • Command calls – i5_range_from – i5_field_scale –i5_command – i5_range_to – i5_field_type » – i5_range_clear • Program calls – i5_list_fields – i5_num_fields – i5_data_seek –i5_program_prepare – i5_result – i5_seek –i5_program_prepare_PCML – i5_bookmark –i5_program_call –i5_program_close – i5_free_file – i5_new_record – i5_update_record – i5_get_keys – © 2009 IBM Corporation
  • 6. PHP Toolkit functions • System values • Job logs • User space –i5_get_system_value –i5_jobLog_list –i5_userspace_crearte » –i5_jobLog_list_read –i5_userspace_prepare • Data areas –i5_jobLog_list_close –i5_userspace_get –i5_data_area_prepare – –i5_userspace_put –i5_data_area_receive • Active jobs – –i5_data_area_send –i5_job_list • Data Queue –i5_data_area_close –i5_job_list_read –i5_dtaq_prepare – –i5_job_list_close –i5_dtaq_recieve • Print/Get spooled file – –i5_dtaq_send –i5_spool_list • Objects list –i5_dtaq-close –i5_spool_list_read –i5_object_list – –i5_spool_list_close –i5_object_list_read –i5_spool_get_data –i5_object_list_close –i5_spool_from_file – – – • – © 2009 IBM Corporation
  • 7. PHP Toolkit for i5/OS – list of functions • Connection management • Data retrieval • Native file access –i5_connect – i5_fetch_array – i5_open –i5_close – i5_fetch_assoc – i5_addnew –i5_adopt_authority – i5_fetch_object – I5_edit –i5_error – i5_fetch_row – I5_delete –i5_errno – i5_cancel_edit – i5_info –i5_errormsg – i5_setvalue – i5_field_len » – i5_update – i5_field_name • Command calls – i5_range_from – i5_field_scale –i5_command – i5_range_to – i5_field_type » – i5_range_clear • Program calls – i5_list_fields – i5_num_fields – i5_data_seek –i5_program_prepare – i5_result – i5_seek –i5_program_prepare_PCML – i5_bookmark –i5_program_call –i5_program_close – i5_free_file – i5_new_record – i5_update_record – i5_get_keys – © 2009 IBM Corporation
  • 8. PHP Toolkit functions • System values • Job logs • User space –i5_get_system_value –i5_jobLog_list –i5_userspace_crearte » –i5_jobLog_list_read –i5_userspace_prepare • Data areas –i5_jobLog_list_close –i5_userspace_get –i5_data_area_prepare – –i5_userspace_put –i5_data_area_receive • Active jobs – –i5_data_area_send –i5_job_list • Data Queue –i5_data_area_close –i5_job_list_read –i5_dtaq_prepare – –i5_job_list_close –i5_dtaq_recieve • Print/Get spooled file – –i5_dtaq_send –i5_spool_list • Objects list –i5_dtaq-close –i5_spool_list_read –i5_object_list – –i5_spool_list_close –i5_object_list_read –i5_spool_get_data –i5_object_list_close –i5_spool_from_file – – – • – © 2009 IBM Corporation
  • 9. 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 © 2009 IBM Corporation
  • 10. 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> © 2009 IBM Corporation
  • 11. 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"; © 2009 IBM Corporation
  • 12. 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 © 2009 IBM Corporation
  • 13. Record-level access: PHP code Example Form and Output © 2009 IBM Corporation
  • 14. Web Enabling DB2 with PHP Using the i5 Toolkit © 2009 IBM Corporation
  • 15. PHP Get Records (i5 toolkit SQL model) • Recall from our previous function model_connect() discussion that before any of the { global $MODEL; $db_options = array(I5_OPTIONS_JOBNAME=>"DVDSEARCH"); APIs from the i5 toolkit can be $MODEL ['conn'] = i5_pconnect ( $MODEL ['database'], used we must establish a $MODEL ['db_user'], $MODEL ['db_password'], connection to the i5 toolkit ); $db_options daemon process (PGM- if (! $MODEL ['conn']) { model_error_i5("Connect fail"); EASYCOM job) return False; } • The i5_pconnect() API is being return model_chglibl(); used to establish a persistent NOTE: Each browser button click will connection and avoid costly IBM i run back through the i5_pconnect() startup and termination code; however since the connection is associated in the cached for each Apache worker job the i5_connect() and actual processing time is minimal. i5_close() APIs. • Establish a connection is a fairly NOTE: In this case each button click will common activity so a site not find it’s way back to the same worker common include comes in handy job (more on this later). © 2009 IBM Corporation
  • 16. 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!! © 2009 IBM Corporation
  • 17. 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) © 2009 IBM Corporation
  • 18. 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. © 2009 IBM Corporation
  • 19. 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; } } © 2009 IBM Corporation
  • 20. 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; } © 2009 IBM Corporation
  • 21. DB2 for i5/OS Language Extensions © 2009 IBM Corporation
  • 22. Accessing DB2/400 • Server/connection • Errors – db2_bind_param • Fetch – db2_fetch_array – db2_conn_error – db2_client_info – db2_fetch_assoc – db2_conn_errormsg – db2_close – db2_fetch_both – db2_stmt_error – db2_connect – db2_fetch_object – db2_stmt_errormsg – db2_cursor_type – db2_fetch_row • Column/Procedure – db2_exec • Field information – db2_column_privileges  db2_execute – db2_field_display_ size – db2_columns  db2_prepare – db2_field_name – db2_procedure_column – db2_pconnect s – db2_server_info – db2_field_num – db2_procedures – db2_statistics – db2_field_precision – db2_special_columns – db2_field_scale • Result • Table information – db2_field_type – db2_free_result – db2_num_fields – db2_field_width – db2_next_result • Key information – db2_num_rows – db2_result – db2_foreign_keys – db2_table_privileges • Commit/Rollback – db2_primary_keys – db2_tables – db2_autocommit • Statement – db2_commit – db2_free_stmt documented online at php.net All of these APIs are – db2_rollback  - Preferred db2_ SQL statement execution APIs (performance) • - Non-preferred db2_ SQL statement execution API © 2009 IBM Corporation
  • 23. Server connection – db2_connect API • 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. – – ● Tip: Use WRKRDBDIRE to get the database name on the remote © 2009 IBM Corporation
  • 24. 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_” © 2009 IBM Corporation
  • 25. i5 Toolkit vs. DB2 Extensions i5_* I5_COMD Zend Core I5/OS Resource PASE db2_* i5/OS TCP/IP db2_* I5/OS Resource i5/OS © 2009 IBM Corporation
  • 26. Anatomy of a Web-Enabled DB2 for i5/OS (via PHP) application © 2009 IBM Corporation
  • 27. 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. © 2009 IBM Corporation
  • 28. 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> <?php define("PAGE_TITLE", "Employee Update"); define("PHP_FILE_NAME", "employee_update.php") ?> <title><?= PAGE_TITLE . " - " . PHP_FILE_NAME; ?></title> <body> <?php ?> </body> </html> © 2009 IBM Corporation
  • 29. 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. © 2009 IBM Corporation
  • 30. 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 */ 1 if ((include "../i5_properties.php") == false) { echo("Problem encountered loading i5_properties.php include file"); } /* Set up connection for each pass through this application */ 2 $dbh = db2_connect($db, $user, $password); if (!$dbh) : 3 die ("Problems connecting to the database."); endif; 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) © 2009 IBM Corporation
  • 31. 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 */ 1 $sql = 'select * from i5schema.employee where lastname like '' .$_POST["lastname"]. '%''; /* Execute the DB2 SQL statement, place results into $stmt */ 2 $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>'; 3 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. 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 © 2009 IBM Corporation
  • 32. Database 4 while ($row = db2_fetch_array($stmt)) { if (!$row=="") { Query $customerNumber = $row[0]; $customerName = $row[3]; $customerFirst = $row[1]; $workdept = $row[4]; $job = $row[7]; $salary = $row[11]; print '<tr><td align=center><a 5 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>'; 6 /* Print the DB2 SQL statement which was executed - Informational */ print "<p>Echo of dynamically-built sql: ".$sql."</p>"; } 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. © 2009 IBM Corporation
  • 33. 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 © 2009 IBM Corporation
  • 34. 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 1 $customerNumber = $_GET["customerNumber"];2 /* Determine which form to display based upon the state of the application */ 2 if ($customerNumber == "") { 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 © 2009 IBM Corporation
  • 35. 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 = '' 1 .$_GET["customerNumber"]. '''; /* Execute the DB2 SQL statement, place results into $stmt */ 2 $stmt = db2_exec($dbh, $sql, array('cursor' => DB2_SCROLLABLE)); /* Place the field information returned into array $row */ $row = db2_fetch_array($stmt); 3 /* If there is data, move information from result array into fields */ /* which will be used for screen display */ if (!$row=="") { $customerNumber = $row[0]; 4 $customerName = $row[3]; $customerFirst = $row[1]; $workdept = $row[4]; $job = $row[7]; $salary = $row[11]; } 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. © 2009 IBM Corporation
  • 36. 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 />'; 5 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. A series of print statements are used to output text labels as well as the contents of the returned record © 2009 IBM Corporation
  • 37. 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 © 2009 IBM Corporation
  • 38. 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"]; } © 2009 IBM Corporation
  • 39. 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 */ © 2009 IBM Corporation
  • 40. Record Update • The following block of code would be placed before the else { /* Edit the selected customer number record */ statement 1 } 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"].'','. 2 ' workdept = ''.$_GET["workdept"].'','. ' job = ''.$_GET["job"].'','.3 ' salary = '.$_GET["salary"]. ' where empno = '' .$customerNumber.''';4 3 $result = db2_exec($dbh, $sql); 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. © 2009 IBM Corporation
  • 41. Record Update if (!$result) { 4 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 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. 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 © 2009 IBM Corporation
  • 42. 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 © 2009 IBM Corporation
  • 43. 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. © 2009 IBM Corporation
  • 44. 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 <?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 */ ?> • 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 © 2009 IBM Corporation
  • 45. 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. © 2009 IBM Corporation
  • 46. PHP Get Records (ibm_db2 model) Using db2_pconnect vs db2_connect • The db2_pconnect() API supports function model_connect() { global $MODEL; persistent connections $db_options = array("i5_naming"=>DB2_I5_NAMING_ON); $MODEL ['conn'] = db2_pconnect • The db2_connect() API does not ( $MODEL ['database'], $MODEL ['db_user'], support persistent connections $MODEL ['db_password'], $db_options • Use of the db2_pconnect() API ); if (! $MODEL ['conn']) can improve performance of web- { model_error_db2("Connect failed"); sites when they are experiencing } return False; heavy user web demand return model_chglibl(); } • 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.Use of persistent connections is absolutely required if the site services multiple requests Tip! Setting DB2_I5_NAMING_ON per second. for the whole set simply works better on IBM i. Mixing DB2_I5_NAMING_ON/OFF almost The php.ini configuration file can be updated always leads to problems on the site to force all db2_connect() calls to use db2_pconnect() instead © 2009 IBM Corporation
  • 47. 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!!! © 2009 IBM Corporation
  • 48. 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 Tip! Mixing db2_pconnect(“”,””,””) spawned there will be little and db2_pconnect(“*LOCAL”,”uid”,”pwd”) difference between profiles can lead to unpredictable results – pick a (assuming that db2_pconnect() profile or two to handle web clients and was used) stick with those. © 2009 IBM Corporation
  • 49. 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. • © 2009 IBM Corporation
  • 50. 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) © 2009 IBM Corporation
  • 51. db2_prepare() and db2_execute() Code Sample (slide 1 of 2) <?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; © 2009 IBM Corporation
  • 52. db2_prepare() and db2_execute() Code Sample (slide 2 of 2) 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; } © 2009 IBM Corporation
  • 53. 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); © 2009 IBM Corporation
  • 54. 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) ); } } } © 2009 IBM Corporation
  • 55. 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 © 2009 IBM Corporation
  • 56. Methods (APIs) for fetching data • There are a number of choices in PHP for fetching data: db2_fetch_array() Returns an array, index by column position, that represents a row in a result set. Column indexing starts at 0. db2_fetch_assoc() Returns an array, indexed by column name, that represents a row in a result set. db2_fetch_both() 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_object() Returns an object in which each property represents a column returned in the row fetched from a result set. © 2009 IBM Corporation
  • 57. 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"]; } 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; } NOTE: In all these different All of the db2_fetch options discussed bring the examples, $prep represents the contents of the entire row back to PHP in one resource that contains the result set. system call via the SQLBindCol interface © 2009 IBM Corporation
  • 58. What about db2_fetch_row() / db2_result() • Second-tier APIs such as $conn = db2_pconnect("","",""); // persistent connect db2_fetch_row() and $stmt = db2_prepare($conn,"sql"); // prepare statement $retc = db2_execute($prep); // execute prepared statement db2_result() should be used { $name = db2_result($stmt, 0); // another syscall here while (db2_fetch_row($stmt)) // syscall here only when other fetch } $breed = db2_result($stmt, 1); // another syscall here options fail. • • 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 • © 2009 IBM Corporation
  • 59. 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_get_option • db2_column_privileges • db2_num_fields • db2_columns • db2_num_rows • db2_cursor_type • db2_primary_keys • db2_escape_string • db2_procedure_columns • db2_field_display_ size • db2_procedures • db2_field_name • db2_server_info • db2_field_num • db2_set_option • db2_field_precision • db2_special_columns • db2_field_scale • db2_statistics • db2_field_type • db2_table_privileges • db2_field_width • db2_tables • db2_foreign_keys NOTE: Detailed information on this APIs can be found in the online PHP manual (http://www.php.net/manual/en © 2009 IBM Corporation
  • 60. IBMDB2i Storage Engine © 2009 IBM Corporation
  • 61. 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 © 2009 IBM Corporation
  • 62. 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. © 2009 IBM Corporation
  • 63. 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, … Application Written to MySQL MyISAM Specialty MySQL (Example server Storage storage SugarCRM) Engine engines DB2i Storage DB2 alter table tablename ENGINE=IBMDB2i Engine storage engine © 2009 IBM Corporation
  • 64. 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 Existing PHP New RPG Application Application MySQL IBMDB2I DB2 for i © 2009 IBM Corporation
  • 65. Leveraging MySQL Data with DB2 Web Query • SugarCRM is a PHP application written to MySQL DB2 Web • DB2 Storage Engine enables SugarCRM Query SugarCRM data to be stored Writes to in DB2 Accesses MySQL Data • DB2 WebQuery can access SugarCRM data Data stored in • Using DB2 Web Query SDK and DB2 for i Report Broker you can integrate reporting into SugarCRM © 2009 IBM Corporation
  • 66. Storage Engine Comparison • Comparison of features between popular MySQL Storage Engines MyISAM InnoDB IBMDB2I Usage Fastest for read heavy Fully ACID compliant Fully ACID compliant; applications transactions data visible externally Locking Large-grain table Multi-versioning, row- Row-level locking locks, no non-locking level locking reads Durability Table recovery Durability recovery Durability recovery Supports NO YES YES Transactions Supports foreign keys NO YES YES Allows access NO NO YES through DB2 for i interfaces Storage Engine Also supports • DB2  Multiple character sets (ASCII, Far East, and Unicode)  All MySQL replication configurations  All widely-used data types (including LOB-based) • © 2009 IBM Corporation
  • 67. 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; • © 2009 IBM Corporation
  • 68. 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. • Client MySQL QSQSRVR Client IBMDB2I QSQSRVR © 2009 IBM Corporation
  • 69. 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. • © 2009 IBM Corporation
  • 70. 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 MySQL 3. 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 engine 5. 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 © 2009 IBM Corporation
  • 71. 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. • © 2009 IBM Corporation
  • 72. Expanding Access To Data ILE Applications (RPG, Cobol, etc) DB2 server* DB2 storage IBMDB2I AMP Stack for i Apache PHP MySQL IBM i * Leverage IBM i functions such as journaling, SAV/RST and DB2 Web Query © 2009 IBM Corporation
  • 73. © 2009 IBM Corporation