Le projet JDBCR4 de Scott Klement propose une utilisation de JDBC en RPG basée sur un programme de service à compiler et téléchargable à l'adresse: http://systeminetwork.com/files/RpgAndJdbc.zip la documentation est disponible à: http://www.scottklement.com/presentations/External%20Databases%20from%20RPG.pdf Pour utiliser un Driver JDBC celui-ci doit être de type 4 (écrit en Java) il est en général livré sous forme de fichier .jar MySQL: mysql-connector-java-3.1.12-bin.jar Oracle (thin): ojdbc14.jar SQL Server: sqljdbc.jar (version open source) : jtds-1.2.5.jar (les n° de version peuvent changer) DB2 for i: jt400.jar IBM DB2 (autre OS): db2jcc.jar Placez ce fichier dans un répertoire de l'IFS et modifiez votre CLASSPATH par ADDENVVAR ENVVAR(CLASSPATH) VALUE('.:/java:/java/mysql-connector.jar') , par exemple. |
Ecrivez ensuite un pgm java de test pour vérifier la validité du driver il vous faut connaitre la classe du driver SQL Server: com.microsoft.sqlserver.jdbc.SQLServerDriver jTDS : net.sourceforge.jtds.jdbc.Driver Oracle: oracle.jdbc.OracleDriver MySQL: com.mysql.jdbc.Driver DB2 for i: com.ibm.as400.access.AS400JDBCDriver DB2 Autre: com.ibm.db2.jcc.DB2Driver et l'URL de connexion SQL Server: jdbc:sqlserver://myserver.example.com:1433 jTDS : jdbc:jtds:sqlserver://myserver.example.com:1433 Oracle: jdbc:oracle:thin:@myserver.example.com:1521:myDataBase MySQL: jdbc:mysql://myserver.example.com/myDataBase DB2 for i: jdbc:as400://myserver.example.com DB2 Autre: jdbc:db2://myserver.example.com:50000/myDataBase |
import java.sql.*; public class testMySql { public static void main (String[] parameters) { String mysqlurl = "jdbc:mysql://localhost/mysql"; String userid = "root"; String password = "xxxxx"; Connection connection = null; try { DriverManager.registerDriver(new com.mysql.jdbc.Driver()); connection = DriverManager.getConnection ( mysqlurl, userid, password ); Statement select = connection.createStatement (); ResultSet rs = select.executeQuery("SELECT Host,User FROM user"); |
while (rs.next ()) { System.out.println (rs.getString(1) + "," + rs.getString(2)); } } catch (Exception e) { System.out.println (); System.out.println ("ERROR: " + e.getMessage()); } try { if (connection != null) connection.close (); } catch (SQLException e) { // Ignore. } } } |
Saisissez,par exemple avec EDTF (pensez bien au CCSID ASCII : 819 ou 1252) puis sous QSH, tapez : ==> javac testMySql.java vérifiez que vous avez obtenu un fichier testMySql.class lancez par ==> java testMySql vous devez obtenir un résultat sur l'écran de QSH Ces tests étant réalisés passont à l'écriture RPG -------------------------------------------------- La première fonction à utiliser est JDBC_Connect |
/copy JDBC_H D userid s 50a D passwrd s 50a D conn s like(Connection) /free userid = 'root'; passwrd = 'xxxxx'; conn = JDBC_Connect('com.mysql.jdbc.Driver' :'jdbc:mysql://myserver.example.com/myDataBase' :%trim(userid) :%trim(passwrd) ); if (conn = *NULL); errorMsg = 'Unable to connect to MYSQL database!'; // Afficher le message. endif; /end-free |
Si vous avez besoin de propriétés particulières à l'utilisation du driver écrivez plutôt : D userid s 50a D passwrd s 50a D conn s like(Connection) D prop s like(Properties) /free userid = 'root'; passwrd = 'xxxxx'; prop = JDBC_Properties(); JDBC_setProp(prop: 'user' : %trim(userid) ); JDBC_setProp(prop: 'password' : %trim(passwrd)); JDBC_setProp(prop: 'connectTimeout': '60' ); conn = JDBC_ConnProp('com.mysql.jdbc.Driver' :'jdbc:mysql://myserver.example.com/myDataBase' :prop) ); JDBC_freeProp(prop); |
par exemple la propriété databaseName pour SQL server ou naming pour jt400 (voir la liste des propriétés pour chaque driver) Bien sur vous pouvez (en allant à la "pêche" aux informations) utiliser des drivers non cités ici, comme celui pour PostGreSql(org.postgresql.Driver) une fois connecté, vous devez distinguer deux types d'ordres Les ordres immédiats sont interprétés et exécutés dans la foulée Les ordres préparés sont interprétés une fois et exécutés, éventuellement, plusieurs fois. lors de la préparation, ils peuvent contenir des marqueurs (?), qui seront remplacés par des valeurs à l'exécution. |
JDBC_ExecUpd( connexion : 'ordre SQL ne retournant rien') Exécute un ordre SQL comme CREATE..., UPDATE, DELETE, etc (pas de SELECT) retourne : 0 pour un ordre n'affectant aucune ligne n le nombre de lignes affectées -1 pour un ordre SQL en erreur exemple : /free rc = JDBC_ExecUpd( conn : 'delete from clients' + ' where nocli = 999 '); if (rc < 0); // signaler une erreur endif; |
JDBC_ExecQRry(connexion : 'ordre SQL de type SELECT') Exécute un ordre SQL retournant un jeu de résultats retourne : un objet ResultSet *NULL pour un ordre SQL en erreur exemple : D Resset s like(ResultSet) /free resset= JDBC_ExecQry( conn : 'select nocli, raisoc, ville, tel' + ' from clients where dep = 44'); if (resset = *null); // signaler une erreur endif; |
Pour lire un ResultSet utilisez les fonctions suivantes : JDBC_nextRow( ResultSet ) se positionne sur la ligne suivante. Retourne *OFF en cas de "fin de fichier", *ON dans le cas contraire JDBC_getCol(ResultSet : NumCol ) Retourne la valeur d'une colonne dont on fournit le n° dans le SELECT (la première colonne porte le n° 1) JDBC_getColByName( ResultSet : NomColonne ) Retourne la valeur d'une colonne dont on fournit le nom JDBC_freeResult( ResultSet ) Ferme le ResultSet et libère la mémoire (comme un CLOSE de curseur en SQLRPGLE) |
Exemple : /free dow JDBC_nextRow(Resset); Dept = JDBC_getCol(Resset: 1); EmpNo = %int(JDBC_getCol(Resset: 2)); Name = JDBC_getCol(Resset: 3); // traitement des données lues. enddo; JDBC_freeResult(Resset) La fonction GetCol retourne toujours une chaîne, quelque soit le type dans la base de données, à vous de convertir pour convertir en numérique : %int(), %uns(), %dec() pour les dates/heures : %date(), %time(), %timestamp() pour les variables Unicode : %ucs2() |
une fois le resultSet créé, vous pouvez obtenir les métaData, soit la définition de ce que vous allez recevoir (sorte de DSPFFD) JDBC_getMetaData( ResultSet ) Retourne un objet MetaData décrivant un ResultSet JDBC_getColCount( MetaData ) Retourne le nombre de colonnes JDBC_getColName( MetaData : NumCol)) retoune le nom d'une colonne dont on fournit le n° JDBC_getColDspSize( MetaData: NumCol ) retourne la taille (à l'affichage) d'une colonne JDBC_getColTypName( MetaData: NumCol ) retourne le type d'une colonne |
instructions préparées : JDBC_PrepStmt( connexion : 'ordre SQL valide') Retourne un objet PreparedStatement pour l'instruction SQL L'instruction est "compilée" et ses exécutions utérieures seront plus rapides. peut contenir des marqueurs représentant des valeurs fournies plus tard JDBC_ExecPrepUpd( PreparedStatement ) Exécute une instruction préparée qui ne retourne pas d'enregistrements JDBC_ExecPrepQry( PreparedStatement ) Exécute une instruction préparée qui retourne un jeu d'enregistrements JDBC_FreePrepStmt( PreparedStatement ) libère la mémoire associée à l'objet PreparedStatement |
Exemple : D Stmt s like(PreparedStatement) D ResSet s like(ResultSet) /free // suite à une connexion . . Stmt = JDBC_PrepStmt( conn : 'Select nocli, raisoc + dep, ville + from clients order by raisoc'); if ( stmt = *null ); // signaler l'erreur endif ResSet = JDBC_ExecPrepQry( Stmt ); if (ResSet = *null); // autre erreur endif; // lecture des enregistrement comme vu plus haut JDBC_freeResult( ResSet ); JDBC_freePrepStmt( stmt ); |
Si vous placez des marqueurs dans l'instruction préparée, vous devez fournir des valeurs avant l'exécution par : JDBC_setString( stmt : numéro paramètre : 'chaîne'); JDBC_setInt( stmt : numéro paramètre : zone binaire); JDBC_setDouble( stmt : numéro paramètre : zone virg. flottante ); JDBC_setDecimal( stmt : numéro paramètre : zone décimale); JDBC_setDate( stmt : numéro paramètre : zone date ); JDBC_setTime( stmt : numéro paramètre : zone heure);; JDBC_setTimestamp( stmt : numéro paramètre : zone horodatage); Exemple : nocli = 1234; JDBC_SetInt( stmt: 1: nocli ); |
Exemple complet avec un INSERT : /free Stmt = JDBC_PrepStmt( conn : 'Insert Into clients + (nocli, raisoc, dep, ville) values(? , ? , ? , ?) '); if ( stmt = *null ); // endif JDBC_setInt ( stmt: 1: 4321 ); // constantes OU variables JDBC_setString( stmt: 2: 'Volubis'); JDBC_setDecimal( stmt: 3: 44); JDBC_setString( stmt: 4: 'Carquefou'); if JDBC_execPrepUpd( stmt ) < 0; // endif; |
Les fonctions JDBC_getCol et JDBC_Setxxx (int, date, etc...) possèdent un paramètre supplémentaire, facultatif, de type indicateur. sur JDBC_getCol il sera positionné à *ON si la colonne est nulle, *OFF dans le cas contraire. sur JDBC_SetInt et les autres fonctions du même genre, vous l'envoyez à *ON pour signaler une valeur nulle, *OFF dans le cas contraire. Vous pouvez aussi utiliser des instructions préparées pour les procédures cataloguées : JDBC_PrepCall( Connection : 'instruction CALL') // préparation JDBC_RegisterOutParameter( CallableStatement: ParmNum: DataType ) // prévient JDBC que ce paramètre est en sortie (valeur retour) JDBC_ExecCall( CallableStatement ) // Exécution JDBC_FreeCallStmt( CallableStatement ) // libération mémoire |
La fonction JDBC_ExecCall peut retourner *ON si un jeu ou plusieurs jeux d'enregistrements sont retournées par la procédure. JDBC_getUpdateCount( CallableStatement ) Quand une procédure ne retourne pas de jeu d'enregistrements, nombre de lignes modifiées par la procédure. JDBC_getResultSet( CallableStatement ) retourne un jeu d'enregistrements comme ExecuteQuery JDBC_getMoreResults( CallableStatement ) passe au jeu d'enregistrements suivant, retourne *OFF s'il n'y en a pas JDBC_getString(), JDBC_getInt(), JDBC_getShort(), JDBC_getBoolean() permettent de récupérer les valeurs des paramètres en sortie Enfin, il existe deux fonctions pour gérer les transactions : JDBC_Commit() et JDBC_Rollback() |