Vous êtes sur la page 1sur 6

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

Published on System iNetwork (http://systeminetwork.com)

MySQL Database Access from RPG


By tzura Created Apr 17 2006 - 07:00 By: Scott Klement [1] For years, I've been asked, "How do I access a third-party database from an RPG program?" I've been asked this question about Sybase, Oracle, Clipper, MySQL, PostgreSQL, dBase, and SQL Server. My answer has always been "RPG's support for Java makes it possible to call JDBC drivers." Recently, I needed to do this myself, because my company has two FreeBSD machines running MySQL, and I needed access to them from an RPG program. In this article, I show you the steps that I took to make it possible for me, a lowly RPG programmer, to access a MySQL database. Install the JDBC Driver Before you can use the MySQL JDBC driver from your RPG program, you need to install the driver on your system. MySQL calls its JDBC driver Connector/J. You can get it from MySQL.com [2] by clicking Developer Zone|Downloads|MySQL Connector/J. The current stable version of Connector/J is version 3.1. Here's a direct link to the download page for that version: http://dev.mysql.com/downloads/connector/j/3.1.html [3] If you have a Windows desktop, you're probably better off downloading the ZIP archive of the source and binaries. If you're a Linux or Unix user, you can use a TAR.GZ version. In either case, download the file to your PC and extract it into a temporary folder. Inside the ZIP or TAR archive that you download from MySQL.com is the JDBC driver in a JAR file. Because I downloaded version 3.1.12, the JAR file is named as follows:
mysql-connector-java-3.1.12-bin.jar

You need to install that JAR file on your iSeries. The way you do that is by copying it to the /QIBM/UserData/Java400/ext directory in your system's IFS. I chose to do that using FTP in binary mode, but you could also use Windows Networking or iSeries Navigator. If you have no access to the /QIBM/UserData/Java400/ext directory, another alternative is to upload the file to a different spot in your IFS, and include it in your CLASSPATH. For example, if you place it in the /test directory of the IFS, you could use the following CL command to add it to your CLASSPATH:
ADDENVVAR ENVVAR(CLASSPATH) + VALUE('/test/mysql-connector-java-3.1.12-bin.jar:.')

1 di 6

18/02/2011 19.34

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

You need to set this before loading the Java Virtual Machine (JVM) in each job. If you place the file in the /QIBM/UserData/Java400/ext directory, you do not need to change your CLASSPATH variable at all. Test the Driver from Java Now that the driver is installed, it makes sense to run a quick Java program to verify that that the driver is working. I wrote a simple one that connects to the server and lists the user IDs and hostnames from the MySQL user database that I use for testing the driver. I named the program testMySql.java and included it with the code download for this article. Before you try out the testMySql.java program, you should edit the source code and look for the following three lines (near the top):
String mysqlurl String userid String password = "jdbc:mysql://test.example.com/mysql"; = "klemscot"; = "bigboy";

You need to change that to point to the server that you want to test. In this example, I'm connecting to a server named test.example.com and using the user ID klemscot and the password bigboy. After that Java code has been updated with the correct values for your server, you can compile it from QShell on the iSeries by typing the following command:
javac testMySql.java

After it has compiled, you can run it from QShell as follows:


java testMySql

If you receive errors about classes not being defined, it means that Java can't find the MySQL JAR file. Either you installed it in the wrong location, or your CLASSPATH is set up improperly. If you receive errors about not being able to connect, make sure that your iSeries is properly configured for your network and that no firewall is blocking you from accessing the MySQL server. If you get really stumped and can't get the test program to work, consider asking for help in iSeriesNetwork.com's C/C++ and Java forum [4]. Connecting from RPG Now that JDBC is installed, it's time to use RPG to access it. To simplify this process, I created a service program called JDBCR4. In that service program, I created a subprocedure called MySQL_Connect(), which connects to a MySQL database server. Here's what my MySQL_Connect() subprocedure looks like:
P MySQL_Connect D MySQL_Connect D server D database D userid D password D D D D D prop drv temp url conn B PI 256A 256A 50A 50A s s s s s export like(Connection) varying const options(*varsize) varying const options(*varsize) varying const options(*varsize) varying const options(*varsize) like(Properties) like(Driver) like(Connection) varying like(Connection)

1024A

/free monitor; jdbc_begin_object_group(1000);

2 di 6

18/02/2011 19.34

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

// Create connection properties object prop = new_Properties(); setProperty(prop: s('user') : s(userid)); setProperty(prop: s('password'): s(password)); // Register a MYSQL driver drv = new_MySQL(); registerDriver(drv); // Connect to database server url = 'jdbc:mysql://' + %trim(server) + '/' + %trim(database); temp = Driver_Connect( drv : s(url): prop ); jdbc_end_object_group(temp: conn); on-error; return *NULL; endmon; return conn; /end-free P E

The subprocedure starts by creating a Java Properties object. This is an object that stores some properties about a connection. In this case, I add user and password properties to the Properties object. I use this later to log in to the MySQL server. Next, it loads the JDBC driver for MySQL. The new_MySQL() prototype is actually a call to the com.mysql.jdbc.Driver() routine in that JAR file that I uploaded earlier. The registerDriver() prototype calls Java's DriverManager to register the MySQL driver with the system. Finally, the subprocedure calls the Driver_Connect() prototype to create a connection to the MySQL database. It passes the Properties object so that a user and password can be used to log in to the MySQL server. The MySQL_Connect() subprocedure shown here is the only routine in my JDBCR4 service program that's MySQL specific. If you want to connect to a different database platform, you need to register that platform's JDBC driver instead of the MySQL one, and you have to pass the appropriate properties for that driver. When I want to connect to a MySQL database, I call the MySQL_Connect() subprocedure as follows:
D conn s . . conn = MySql_Connect( : : : like(Connection) 'test.example.com' 'myDatabaseName' %trim(userid) %trim(passwrd) );

The JDBCR4 service program also contains a subprocedure called JDBC_close() for closing the connection when I'm done working with the database. I won't show you the code for the JDBC_close() subprocedure here, but it's included in the code download for this article. To disconnect from the server, I call JDBC_close() at the end of my program:
JDBC_close(conn);

3 di 6

18/02/2011 19.34

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

Running Non-Query Statements JDBC has two types of SQL statements that you can run: those that return a set of records, which I like to call "queries," and those that do not return anything. JDBC refers to the latter as "update" statements, because most of the time you use them to perform an Insert or Update SQL statement. To execute these SQL statements that don't return anything, I coded a subprocedure called JDBC_ExecUpd(). For example, if I want to create a new table named RpgTest, I call the JDBC_ExecUpd() subprocedure as follows:
D rc /free s 10I 0

rc = JDBC_ExecUpd( conn : 'Create Table RpgTest' + '(' + ' ItemNo Dec(5,0) Not Null, ' + ' Count Int Not Null, ' + ' LastChg Timestamp ' + ' Default CURRENT_TIMESTAMP, ' + ' LastSold Date Default Null, ' + ' TimeTest Time Default Null, ' + ' Price Dec(7,2) Not Null, ' + ' Description VarChar(25) not Null, ' + ' Primary Key( ItemNo )' + ')' ); if (rc < 0); ErrMsg = 'Unable to CREATE table'; endif;

The first parameter to the JDBC_ExecUpd() subprocedure is the connection object returned by the MySQL_Connect() API. The second parameter is the SQL statement to execute, in this case the Create Table statement. The return value is the number of records that the SQL statement affected. If the SQL statement doesn't operate on records, it returns 0. If an error occurs, it returns -1. Running Queries When an SQL statement does return information, it's stored in a result set. A result set is similar to the cursors that we use in embedded SQL in RPG it's an object containing the results of the query, and I can read record and field information from it. To work with queries, I created three subprocedures in the JDBCR4 service program. JDBC_ExecQry() executes a query and returns a Java ResultSet object. JDBC_NextRow() positions the ResultSet to the next row (or "record" to us old-fashioned RPG guys), and JDBC_GetCol() gets a column (or "field") from the current row. When I'm done reading the result set, I call the JDBC_FreeResult() subprocedure in JDBCR4 so that the memory can be returned to the system. Here's an example of running a query and reading the results:
D rs s like(ResultSet) . . rs = jdbc_ExecQry( conn : 'Select ItemNo,Description' + ' from RpgTest' + ' where LastSold < DATE("2003-01-01")' ); dow (jdbc_nextRow(rs)); ItemNo = %int(jdbc_getCol(rs: 1)); Desc = jdbc_getCol(rs: 2); except; // print the itemNo and Desc fields enddo; jdbc_freeResult(rs);

4 di 6

18/02/2011 19.34

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

The JDBC_GetCol() procedure takes a column number for its second parameter. This is the number of the column in the result set. For example, in my Select statement, I requested two fields, ItemNo and Description, to be returned for each record in my result set. When I call JDBC_getCol() with a column number of 1, I get the ItemNo field for the current record. When I call it with a column number of 2, I get the Description field. Prepared Statements My JDBCR4 service program also has routines that let you prepare SQL statements with parameter markers. This is great for inserts and updates because you can use the parameter markers to insert data from your RPG fields. Here's an example of using a prepared statement to insert a record into the RpgTest table:
D rc D stmt /free stmt = JDBC_PrepStmt(conn : 'Insert Into RpgTest ' + '(ItemNo, Count, LastChg, LastSold, ' + 'TimeTest, Price, Description)' + ' values (?,?,?,?,?,?,?)' ); if (stmt = *NULL); ErrMsg = 'Prepare Statement failed!'; return *OFF; endif; JDBC_setDecimal (stmt: JDBC_setInt (stmt: JDBC_setTimeStamp(stmt: JDBC_setDate (stmt: JDBC_setTime (stmt: JDBC_setDecimal (stmt: JDBC_setString (stmt: 1: 2: 3: 4: 5: 6: 7: ItemNo); Count); LastChg ); LastSold ); TimeTest ); Price ); Description ); s s 10I 0 like(PreparedStatement)

rc = JDBC_ExecPrepUpd( stmt ); if (rc < 0); ErrMsg = 'Execute Prepared Failed!'; return *OFF; endif; JDBC_FreePrepStmt( stmt );

The JDBC_PrepStmt() prepares an SQL statement. In this case, it's an Insert statement in which I set the values of the fields to ?,?,?,?,?,?,?. These question marks are parameter markers and are replaced with data from my variables when the statement is executed. To supply the values, I call the JDBC_setDecimal(), JDBC_setString(), and other JDBC_setXXXX() routines. When I pass a 1 for the second parameter to the JDBC_setXXXX() routines, it replaces the first question mark with my variable. When I pass a 2, it replaces the second question mark, and so on. Like the other SQL statements that I demonstrated, prepared statements come in two varieties: those that return a result set, and those that do not. In the preceding example, the statement does not return a result set, so I call the JDBC_ExecPrepUpd() subprocedure to run it. If I used a prepared statement for a query, I'd call JDBC_ExecPrepQry() to run it, and it'd return a result set that I could read in my program. Get Your Own Copy If you'd like to download and try out my JDBCR4 service program, you can obtain it in the code download for this article. At the top of the JDBCR4.rpgle source member, there are instructions for how to compile the service program. I also include a MYSQLTEST.rpgle source member (with its own compile instructions) that demonstrates how to call the routines in JDBCR4.

5 di 6

18/02/2011 19.34

MySQL Database Access from RPG

http://systeminetwork.com/print/17927

You can download the source code for this article from the following link: http://systeminetwork.com/files/RpgAndJdbc.zip [5] 2011 Penton Media, Inc. Source URL: http://systeminetwork.com/article/mysql-database-access-rpg
Links: [1] http://systeminetwork.com/author/scott-klement [2] http://www.mysql.com [3] http://dev.mysql.com/downloads/connector/j/3.1.html [4] http://www.iseriesnetwork.com/isnetforums/forums.php [5] http://systeminetwork.com/files/RpgAndJdbc.zip

6 di 6

18/02/2011 19.34

Vous aimerez peut-être aussi