® IBM Software Group EGL SQL – Advanced Development and Coding Concepts This Learning Module shows how to understand and use the EGL language abstractions to create advanced SQL database access, including custom cursors, prepared statements and calling stored procedures. © 2006 IBM Corporation EGL Custom SQL Coding The implicit and explicit SQL shown in the previous examples were simple and powerful ways of going about coding data access requests, and should be considered “best practice” solutions to requirements – whenever possible, as they increase development productivity and minimize maintenance risk and time. However, there will be many business requests with complex logical requirements that will mandate a lower-level or custom solution to data access. EGL supports this with the following constructs: Execute Open Prepare These keywords are actually used somewhat interchangeably in data access routines, and are best learned through example. 2 EGL – Execute Keyword The EGL execute verb allows you a custom coding way to write: Non-DML statements: Create Table Drop Table DML statements that update your database: Insert Update Delete With execute you: Have total control over the SQL code – so this is a statement for SQL-experts to use Do not have to reference sqlRecords – so this makes the database access: More independent of the table import and schema More time-consuming to write and test The format of execute is: execute #sql{ … your native SQL statement … } Notes: Any valid SQL statement (except for SELECT) Must surround the statement with curly braces #sql{ is all four characters together (no spaces) 3 EGL – Execute Keyword – Examples Non-DML Examples SQL DML Examples (no sqlRecord) 4 Workshops for EGL execute statement You will do the following labs, to help you understand the user of the EGL execute SQL I/O statement: Generate CREATE table – SQL DDL using the Data Tools, in the Data Perspective Create the following EGL execute #sql{ statements: Which will create a new (temporary) table Populate this temporary table with rows from EGL.Customer Do some EGL DML statements against the table using custom SQL statements Drop the table Test your code using the sqlTest program There will also be an optional workshop that will allow you to combine EGL Debugging and your temporary table work, with the Data Perspective 5 Data Perspective – Generate Create Table Statement – 1 of 2 From the Data Perspective – from the Database Explorer Reconnect to EGLDerbyR7 Right-click over Customer and select Generate DDL… From Options select CREATE statements From Objects select all From Save and Run DDL check Open DDL file for editing Click Next then Finish 6 Data Perspective – Generate Create Table Statement – 2 of 2 From script1.sql – loaded into the Content Area Select and copy all of the Create table statement ( you will use this in the next part of this workshop) Close the Data Perspective From the Web Perspective, leave script1.sql open !!! Cause you’ll be coming back to this generated DDL 7 Execute Keyword – Create Table In eglderby7.access/CustomerLib.egl Create a new function, named: execCreateTable as shown below Notes: Paste in the generated SQL Create table statement – as shown Code the execute #sql{ Change the table name to: EGL.CUSTOMERTEMP Copy and paste the try, HandleSuccess and onException clauses from other statements Pass the function (status StatusRec) as a parameter Press Ctrl/S – and remove all syntax errors 8 Execute Keyword – Insert Into Table In eglderby7.access/CustomerLib.egl Create another new function, named: execInsertIntoTable as shown below Notes: Copy the majority of the code from some other function in CustomerLib.egl …or… you can use Content Assist to build the statement 9 Execute Keyword – Drop Table In eglderby7.access/CustomerLib.egl Create another new function, named: execDropTable as shown below Notes: Copy the majority of the code from some other function in CustomerLib.egl …or… you can use Content Assist to build the statement Be sure to drop EGL.CUSTOMERTEMP …not EGL.CUSTOMER! 10 Execute Keyword – Update Table In eglderby7.access/CustomerLib.egl Create another new function, named: execUpdateSetLevel as shown below Notes: Copy the majority of the code from some other function in CustomerLib.egl Make sure your function parameters are correct Note the use of the host variable :idIn …in the WHERE clause 11 Execute Keyword – Delete From Table In eglderby7.access/CustomerLib.egl Create another new function, named: execDeleteSetLevel as shown below Notes: Copy the majority of the code from some other function in CustomerLib.egl Make sure your function parameters are correct Note the use of the host variable :idIn …in the WHERE clause Generate the CustomerLib – Ctrl/G 12 Execute Keyword – Debug using sqlTest.egl Program – 1 of 3 From Project Explorer, open: programs/sqlTest.egl Create another new function, named: testExecStatements() Notes: Ensure that all of your connections to the EGLDerbyR7 are closed (check the Data Perspective) Use Content Assist to build the CustomerLib. function invoke statements Add statements to main() in sqlTest.egl that invoke the new function(s) Add new Break Points as shown And remove the other Break Points from the program while you’re at it From Project Explorer – right-click on sqlTest.egl Debug the EGL program From Debug Click through your calls to the execute SQL statements From the Variables view, monitor the results of each call by expanding status Finish your debug session (run all of the statements in the program) Reopen the Web Perspective 13 StatusRec Execute Keyword – Debug using sqlTest.egl Program – 2 of 3 How often have you wanted to view the results of SQL statements – WHILE your programs were executing? Using a combination of the Debugger and Data Perspective – for certain kinds of testing use cases this is possible. Let’s see how! In /programs/sqlTest.egl In testExecStatements() – comment out the call to: // CustomerLib.execDropTable(status); Important. Please comment out this line and read the ***Notes section of this slide Save and Debug sqlTest.egl again each break point – this will create and populate the temp table Resume through Continue/Resume until your program/debug session has terminated Then reopen the Data Perspective 14 Execute Keyword – Debug using sqlTest.egl Program – 3 of 3 From the Data Perspective / From the Database Explorer Reconnect to EGLDerbyR7 Expand the folders down to…… Right-Click over CUSTOMERTEMP Select: Data > Sample Contents You should see the rows you inserted with your EGL program and CustomerLib function call using execute #sql (minus row #5 … because you deleted it ) 15 EGL – open Keyword The EGL open verb allows you to create custom SQL cursor processing, where you have complete control over the result set produced by your SELECT statement. This can be very helpful in several types of situations: You need to process each row returned from the database as soon as it’s returned You want control over the number of occurrences in the EGL record array created from the result set By using open, you can create an array of n size, open a cursor, and get exactly n rows into the array The format of open is: open resultSet into <sqlRecord.fld…> with #sql{ … code your SQL statement … }; forEach(from resultSet) //do something - like append to an array //Or update the row…etc. end Notes: Open creates a resultSet – a temporary area in the database that holds the results of your SELECT statement. A resultSet is like a DB2 cursor (on the mainframe). You can use get next resultSet … or … a keyword like forEach to return each row in the resultSet for processing 16 Optional Workshop - EGL – Open Keyword – with forEach to Process ResultSet Here’s a live example of an Open Keyword function that uses forEach as well. Code or copy/paste and add this function to: CustomerLib (the code is in the slide ***Notes) To call this function, make the following changes to sqlTest Comment out all the code in testExecStatements() Add a new function From main() call the new function 17 EGL – Open Keyword – with while to Process ResultSet “Conditionally” You may want more control over the loop that returns the resultSet. You can use While to explicitly bump through the rows in your resultSet – one at a time. Add another function to CustomerLib (the code is in the slide Notes) To call this function, make the following changes to sqlTest.egl Comment out all the code in testExecStatements() Add a new function: From main() call the new function 18 (NOT a workshop) EGL – Delete/Replace from ResultSet You may want to use the “UPDATE WHERE CURRENT OF CURSOR” construct in your EGL logic. Note that this is especially useful in batch processing. Typical logic flow: 1. 2. 3. Read a row Determine if that (specific) row should be updated or deleted Do so (update or delete the row) – through the cursor being maintained by the DBMS on the row Note from the example that you can either: - Delete an entire row - Replace an entire row - Replace specific columns in a row *** See Notes for: 1. Additional conceptual information on using where current of 2. Example code (as shown here) to try calling from your sqlTest.egl program 19 EGL – prepare Keyword The EGL prepare verb allows you to completely customize your SELECT, FROM, WHERE, and ORDER BY at run-time. It is very useful for requirements like custom search pages, where users may select 0 – n fields for processing, and build their own dynamic query conditions and specify custom sorting results. The format of prepare is: prepare preparedStmtID from stringVar; open resultSet with preparedStmtID into… forEach (from resultSet) //do something - like append to an array //Or update the row…etc. end Notes: prepare creates a DBMS preparedStatement. You can think of a preparedStatement as a temporary DECLARE for a custom SELECT statement compiled at run-time. Prepare’d statements can be subsequently opened and fetched (with get next as seen in the previous example) open creates a resultSet – a temporary area in the database that holds the results of your SELECT statement. It is like a DB2 cursor (on the mainframe). You can use get next resultSet … or … a keyword like forEach to return the rows for processing 20 *** Notes Prepare Keyword – Workshop – 1 of 2 In CustomerLib, add this function (code in the slide Notes) Read the comments Save your work 21 Prepare Keyword – Workshop – 2 of 2 In sqlTest – add the following function: Note the spaces in the string before WHERE and ORDER BY Why do you think this is necessary? Comment out the code in testOpenStatement() In main() add a statement to invoke: testDynamicSQL(); Debug sqlTest.egl 22 OPTIONAL Workshop – prepare With Dynamic SQL Variables – 1 of 2 In the previous example, although you used a dynamic SQL statement, host variables that would normally be supplied at run-time by (for instance) user choices on a search page – were not part of the example. You can supply host variables in prepare statements in two ways: 1. 2. By using ? (question mark) placeholders throughout the statement, where the open supplies the values as variables Through standard EGL variable values – in string fields (not shown below, but shown in an example on the next slide) The format of prepare that contains dynamically-supplied host variables is: strVar string = “SELECT stuff… FROM stuff…” + “ Where colm = ? And colm = ?”; prepare preparedStmtID from stringVar; //where stringVar is shown above open resultSet with preparedStmtID using var1, var2 for <sqlRecord>; forEach (from resultSet) //do something - like append to an array, etc. end Notes: Use a question mark – within a string variable to hold a place for an EGL variable, referenced by: with var1… in the open statement The datatypes of the variables reference by with must match their table column types You can pass a Schema name as a variable into the statements. This may be necessary for dynamic Schema table identifiers – although there are other techniques 23 *** Notes Truly OPTIONAL Workshop – prepare With Dynamic SQL Variables – 2 of 2 Here’s an example of a modified function (the code is in the Notes section of this slide) – that uses question marks (?) as placeholders for variable data, resolved at run-time. Note also that we are dynamically supplying the Schema name. This is a useful technique. Note: For <recordName> 24 Miscellaneous EGL/SQL Topics There are Reusing production SQL Null values Tables that contain reserved words in their names (or in the column names) Connecting to different databases Importing records with unqualified table names Stored Procedures SQL Performance SQLLIB Commit and Rollback Best Practices SysVar.sqldata 25 Reusing Production SQL In most “Legacy Modernization” projects you will probably want to reuse your production SQL statements. Here’s how this can be accomplished: Select (get) Create a new record for each unique combination of joined tables: – SQLRetrieve all tables that participate in the SELECT – HINT: Specify the table alias from the original statement in the Record’s tablenames [[…]] property [“tname”,”alias”], Create a new function for each production statement Code get <newSQLRecord>; Right-click and create either a single-row (Add with into) or multi-row (array add) explicit EGL/SQL statement – #sql{ select Copy the production SQL DECLARE statement from the original code and paste it over the explicit EGL/SQL statement inside the curly braces Validate the statement Test by running in the Data Perspective and Debug the statement, using a batch program (Alternatively) Use: open resultSet into <sqlRecord.fld…> with #sql{ Copy/Paste the original cursor DECLARE statement after the with #sql{ curly brace Reconcile host-variable records (into <sqlRecord.fld…> ) with the original FETCH statement SQL DDL and Insert/Update/Delete statements (add, replace, delete) Use: execute #sql{ Reconcile host-variable requirements with EGL records and variables 26 Dealing with Table Null Values – isSQLNullable=yes Null values are the “absence of information”. They are logical values and represent “not/available” …or… “not/applicable” status for a field If you accept the default setting for SQL nulls as generated by the Data Access wizard, EGL internally maintains a null indicator for each variable that has the following characteristics: Is in an SQLrecord Is declared with the property isSQLNullable = yes …or… Note that you could also Is defined with a ? After the type - CustomerId CustomerId?; declare a variable and add a question mark to the type, to allow null values in the field To test for NULL in a nullable host variable, use an EGL if statement. Example: if(orderDB.order_date == null) You can set-null an SQL table column in either of two ways: Use an EGL set statement to null a nullable host variable, then write the related SQL record to the database; set orderDB.order_date = null; Use the appropriate SQL syntax, either by writing an SQL statement from scratch or by customizing an SQL statement that is associated with the EGL add or replace statement. 27 Relational Tables With Reserved Words as Identifiers With the broad range of technology, it helps to pay close attention to naming conventions, else your code will step on some reserved word somewhere in: EGL Java SOAP SQL Easy to say – but harder in reality to achieve. In SQL, if there is a reserved word declared as a table or column name RDBMS’s typically allow you to enclose the reserved word with double-quotes – so that the various parsers don’t get confused. Here’s an example, from the Customer table Note the use of the Java escape character \ - to ensure that the double-quote is honored throughout the generated SQL 28 Debugging SQL – 1 of 2 In order to assist you in debugging SQL for your applications you can trace the events that occur at runtime by doing the following: For Web Applications Open \WebContent\WEB-INF\web.xml From the Variables tab, scroll down in the Environment Variables list until you find: EnvEntry vgj.trace.type Select it, and set its Value to: -1 Then select EnvEntry vgj.trace.device.option and set its value to: 1 For batch applications Open \Java Resources: src\rununit.properties Add two entries: vgj.trace.type=-1 vgj.trace.device.option=1 29 Debugging SQL– 2 of 2 When you run a page, you will get EGL trace information in the Console that shows the EGL functions, Library calls, and DB return codes When you debug a batch program, you will get the same kind of information in the Debugger Console 30 Tables With # signs SQL Names with # Signs Some (seems especially) RPG/System i users have pound signs in their table column names. Not a ANSI SQL standard practice, but you can allow them as EGL variables if you set Visual Age Generator – compatibility to true Under: Windows > Preferences > EGL Set VisualAge Generator compatibility Note that this will re-build/re-generate your application. Note also that by setting VisualAge Generator compatibility, your variable names can contain dashes ( - ) 31 Connecting to Different Databases – 1 of 3 The sqlLib.connect() system function creates a named connection to a database at run time, and makes that connection active. Example: sqllib.setCurrent(…) can be used to specify which connected database is the current one (in use) for a given SQL statement. This allows you to maintain open connections (and threads) among two or more databases and access them in an efficient manner. You connect to multiple physical database “connections” established either through the .EAR file – or in the application server itself. Here’s how… 32 Connecting to Different Databases – 2 of 3 Edit the .EAR file’s Deployment Descriptor. For each unique connection/Data Source/Schema add the following: ***Notes The JDBC Provider. One per DBMS Data Source. One per: Schema/Library Database – within the DBMS For the Data Source, use the currentSchema property – if you wish to provide different Schema names for unqualified Tables/Views/Synonyms 33 Connecting to Different Databases – 3 of 3 In your EGL logic part, you can connect through the SQL Data Source. Here’s an example – referring back to the previous .EAR file Data Source entries: 34 currentSchema and iSeries DB2 Access For the iSeries JDBC drivers, the property "currentSchema" does not exist. You need to use the "libraries" property which provides one library that will be used as the qualifier. If you want to use the library list of the user's job description, then you need to change "libraries" to the value of: *LIBL and the "naming" property to a value of system ***Notes 35 Importing Records with Unqualified Table Names Recall from a prior section of the course, that when you used the Data Access Application Wizard you checked Qualify table names – and all of the generated statements were fullyqualified. This worked well for our test database and application, but in many production scenarios the following naming standards are in play: unitTestSchemaName.Table integrationTestSchemaName.Table productionSchemaName.Table Where the same tableName is qualified with different schema names according to the environment you are working within How to handle this? By defining the: currentSchema property for your JNDI database properties in the EAR or Server’s Deployment descriptor (see below and previous slides) Then by simply un-checking: Qualify table names - when you do your Data Access import 36 *** Notes tableNameVariables – a Third Way to Qualify a Table Schema A final method of programmatically qualifying a table name, with the table schema is to use the EGL/SQL keyword: tableNameVariables= Note the following: tableNameVariables= clause “myTable” – becomes a variable name “Customer” – becomes a table alias in the statement produced at run-time column= clause without the Schema-Qualification CUSTOMER.STREET not EGL.CUSTOMER.STREET To use the tableNameVariables= technique 1. 2. 3. Declare a variable of type SQLRecord (for the tableNameVariables) record Define a variable “in scope” of the same name as the variable name in the clause, and assign it a runtime value, with the Schema Name Use the EGL data access verbs 37 *** Notes EGL Support for Stored Procedures Many production applications use SQL Stored Procedures – which are mini-programs running in the database that combine SQL with procedural business logic, using input and output parameters. Stored procedures are used for many different purposes but their primary attraction is SQL performance. Reliable benchmarks have been formalized Calling a stored procedure EGL’s open and execute statements can invoke a stored procedure. Use open when the procedure returns the results of a query (i.e. a SELECT statement), otherwise use execute. In both cases the SQL statement is a CALL. // Returns the results of a query (row select) open results with #sql{ call OwnerID.myProc1() }; // Returns nothing – most likely an insert/update/delete/create or drop statement execute #sql{ call OwnerID.myProc2() }; There are some restrictions on using Open with certain databases. If you are not using DB2, consult your IBM technical contact for details 38 Arguments to Stored Procedures Stored procedures have IN, OUT, and INOUT parameters, just like functions in EGL. You can pass literals or host variables from EGL. If a parameter is OUT or INOUT, the stored procedure can assign it a value, and you’ll see the new value in EGL after the call returns. a int; b decimal(7,0); open results with #sql{ call myProc3( :a, :b, 'hello' ) }; execute #sql{ call myProc4( :a, :b, 'hello' ) }; 39 Stored Procedure Example – 1 of 2 This function executes SQL to drop an existing stored procedure, then executes a statement to create a stored procedure (using the code shown here). try execute #sql{ drop PROCEDURE spdept3 }; end execute #sql{ CREATE PROCEDURE spdept3 ( in dept varchar(5) ) RESULT SETS 1 LANGUAGE SQL ------------------------------------------------------------------------- SQL Stored Procedure -----------------------------------------------------------------------P1: BEGIN -- Declare cursor DECLARE cursor1 CURSOR with return FOR SELECT * FROM SAMPLE.DEPARTMENT where deptno >= dept; -- Cursor left open for client application OPEN cursor1; END P1 }; 40 Stored Procedure Example – 2 of 2 This code calls the Stored Procedure, passing it a single Char variable, initialized to a department number. Finally, it issues an execute #sql{ statement to drop (delete) the Stored Procedure created in the previous slide deptNbr char(5) = "E01"; try open resultSet1 with #sql{ call spdept3( :deptNbr ) }; writeStdOut("getViaSP3()- dept: \"" + x + "\"" ); forEach (from resultSet1 into dept.deptno, dept.deptname, dept.location); writeStdOut(…show results…); End // end of forEach onException writeStdOut ("getViaSP3()- Problem with call to Stored Procedure" ); exit program; end // end of try block execute #sql{ drop PROCEDURE spdept3 }; 41 SQL Performance – 1 of 3 SQL Performance is a very big topic. If you are responsible for writing EGL code that must generate to high-performance SQL database access statements you should research this topic on the Internet, and with books written by experts such as Joe Celko and Craig Mullins (among others) Background SQL efficiency is a direct correlation to the # of rows physically accessed by the DBMS versus the # of rows needed by your business logic. As an example, if a list page only displays 10 rows at a time, but accesses 2,000 rows from the database per execution of the SQL function this is probably inefficient. However, if a batch process needs 225,000 rows for its business process, and accesses 300,000 rows to get them, this is relatively efficient. It’s the correlation of # of rows needed, versus DBMS work-to-be-done to get those rows that is the true measure of SQL efficiency. In order to determine the above, you must fully understand the service level requirements for your database access. Typically, you are concerned with web-page performance and user-wait time. Problems with pages occur when the SQL run to access the data for the page returns thousands (or tens or hundreds of thousands of rows). So, you will need to understand both the logical AND physical structure of your database – and its choices of data access, in order to completely understand how much effort it takes the database to get the data you need. This can be (read, “usually is”) a very complex and time-consuming process, unique to every different business application The best we can do in this tutorial is to give you general rules-of-thumb that will make queries “more” efficient. However, it is strongly recommended that you discuss this with your systems database administrator (DBA) – for any/all pages that require maximum SQL performance Note that there is no end of decent SQL performance articles – mostly database-specific on this topic available freely on the internet – and a # of good books as well. http://www-128.ibm.com/developerworks/db2/library/techarticle/0210mullins/0210mullins.html http://www.javaworld.com/javaworld/jw-02-2005/jw-0228-apm.html 42 SQL Performance – Rules of Thumb – 2 of 3 For Batch applications that process all or a significant % of table rows, index access is often inefficient. This is because the database must first read the index dataset – then read the table dataset to retrieve each row. Index access is efficient only when your SQL requirements are for a small percentage of the entire table: (typically less than 20%). For online/pages Attempt to limit the number of rows retrieved per get statement to the minimum needed per page view. This will require you to do at least two things (neither of which are easy or quick): Add additional WHERE clause conditions using SQL BETWEEN that reference database index columns – and in your EGL code manage the values so that the database is retrieving as close to the # of records needed per page view as possible Code your own programmatic paging – by incrementing the values in the SQL BETWEEN clauses per page forward – and decrement the values for page backward. Separate the database access from the page fields by using basicRecords to render the fields. In this tutorial, you have primarily dragged and dropped database records onto a form. This is not as efficient as doing the database access through sqlRecords, then moving the records return Using explicit SQL, select only the # of columns you need in your page view (i.e. if you are only showing 4 fields tied to a 30 column table row, delete the other 26 columns. Attempt to avoid ORDER BY unless it is on an indexed column AND the index exists in the same order you need for your sort process. Obviously this is driven by the business requirements, but database sorting can be very expensive. Statements that force sorts include: ORDER BY GROUP BY TABLE JOINS UNION Certain Sub-selects Avoid using SQL WHERE clause keywords that disallow index access Computations in the where clause Like – with the % or underscore before the literal data 43 SQL Performance – Rules of Thumb – 3 of 3 Attempt to limit the number of JSF dataTable cells rendered by EGL/JSF A cell is the intersection of a row and column in a dataTable, so that if you have 5,000 rows and 20 columns, you generating 100,000 cells. This will almost definitely cause severe page performance problems. As a rule of thumb, keep the number of total cells under 10,000 (i.e. 500 rows/20 columns), etc. Large-scale SQL performance improvements have been documented by so doing. SQL Stored Procedures will always out-perform dynamic SQL access. So for your ultra-performanceintensive pages, consider using SQL Stored Procedures. This has been well-documented in IBM Redbooks Use the EGL MAXSIZE property - to halt the fetch process from the database on potentially large queries. MAXSIZE, which you specify as a property of a dynamic array interacts with the database engine’s fetch looping, and once reached, closes the cursor and stops the database access process. You should note that the majority of the cost of the database access occurs when a cursor is OPEN’d. However, if your page only renders 10 rows at a time, and you are doing programmatic paging, specifying MAXSIZE = 10 will help performance – somewhat Use any of your DBMS’s SQL efficiency features. For example DB2 has several keywords that influence the Optimizer to access a stated # of rows: OPTIMIZE FOR n ROWS; //tells the optimizer you will probably only fetch n rows FETCH FIRST n ROWS ONLY; //tells the optimizer you will ONLY fetch n rows FOR READ ONLY //tells the optimizer you will not do any update where current of commands WITH UR //allows you to read uncommitted rows 44 EGL’s SQLLIB EGL’s SQLLIB system library provides a number of extremely useful system API calls. We’ve already seen connect. Others include: Check out: loadTable unloadTable Example1: Say you needed to: 1. show users rows in a dataTable. 2. Allow them to select certain rows. 3. Write these Rows out to a data file on the Server. You could use unloadTable to do this easily and efficiently, by: 1. Creating a new temporary table. 2. Insert the rows into that table. 3. Unloading the table to the file Example 2 – Reverse. Say you needed to read a .DAT file on a user’s desktop into a table. You could: 1. Use the JSF fileUpload component to transfer the file to the server. 2. Use the LOBLIB.updateBlobToFile API to Write the file to the server. 3. Use loadTable to populate an RDBMS table. 45 EGL’s System Variables – sysVAR.sqlData and sqlLib.sqlData sysVar.sqlData and sqlLib.sqlData are structured records that contain data available to your EGL programs used in SQL data access routines (primarily error-handling situations, but not necessarily limited to that). The variables in both records are updated after your program accesses a relational database. The differences between the two record The scope of sysVar.sqlData is limited to a program. For example, if programA calls programB and both programs access a relational database, each program has its own copy of sysVar.sqlData. The values set in programB are not available after you return to programA. The scope of sqlLib.sqlData is global across the programs in the run unit. For example, if programA calls programB and both programs access a relational database, the values set by the last relational database access in programB are available in programA immediately after the return to programA and until the next relational database access. Note – if you are using the Data Access Application wizard function calls, you’ve seen that the built-in library code initializes the statusRecord data after each DBMS SQL access. 46 EGL’s Commit/Rollback Processing Commit processing is managed by the EGL build file’s SQLCommitControl build descriptor option. Note that you’ll need to un-check: Show only specified options to see it You have three alternatives for transaction control – or commit processing in EGL: AUTOCOMMIT Which commits after each successful database update operation NOAUTOCOMMIT Which does not issue a commit after each successful database operation You can manually Commit/Rollback with calls to the EGL System Library functions: – syslib.commit(); – syslib.rollback(); NOCOMMIT Which never issues a commit, and is used primarily by certain Informix databases that do not allow transaction support Note that the end of every run-unit in EGL issues an implicit commit – this includes JSFHandlers. 47 EGL/SQL Summary and Best Practices The following chart lists the best practices approach to coding SQL and using the EGL SQL tools SQL Data Access Requirement Best Practice – EGL Keywords Simple SQL DML (Select, Insert, Update, Delete). Primary Key as Where & Order By clause Implicit SQL (get, add, replace, delete) SQL DML with reusable custom Where clause Create custom record with defaultSelectCondition SQL Select statements with custom WHERE clause Explicit SQL - get <sqlRecord> with #sql{ … } Table Join SQL Record > SQLRetrieve (and don’t forget to code the Join Condition) Derived Data in SELECT – Max(…), Avg(…), Select First_Name || ‘,’ || Last_Name, etc. Explicit SQL get with #sql{derived fields} – or custom record with column= specifying the derived or computed expression Complex or custom SQL Insert, Update or Delete add, replace, delete with #sql{…} …or… execute #sql{…} Non-DML SQL Statement - Create table…etc. execute #sql{…} Dynamic SQL (Prepare) execute #sql{…} prepare also Stored Procedure open resultSet with #sql{ call stored_proc (:hostVar) } Process individual rows of a SELECT statement’s result-set open resultSet with #sql{…} forEach(from resultSet)… or … while (SQLData.SQLCode == 0) Programmatic Paging Use Data Access Application code as example. (See slide Notes) Add data to your table Data Perspective/Table Editor Test your SQL Validate SQL, Run interactive SQL in SQL Editor of Data Perspective 48