1 import java.sql.*; 2 import java.util.*; 3 import java.io.*; 4 5 /* 6 * Note: 7 * This provider invokes JNI in the following way: a C API calls some Java code through JNI, which in turn calls 8 * some C code as native method. To exchange pointers, the C pointers are converted to the "long" java type, which is mapped 9 * to the "jlong" C type which is always 64 bits long, refer to http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html 10 * 11 * In C code, when passing a C pointer to a method, it needs to be converted to a jlong, and the jni_cpointer_to_jlong() 12 * function must be used. 13 */ 14 15 /* 16 * This class will be instantiated once for each GdaJdbcProvider created. 17 */ 18 class GdaJProvider { 19 private static native void initIDs(); 20 private String driver; 21 22 // Constructor 23 public GdaJProvider (String driver) { 24 this.driver = driver; 25 } 26 27 // Connection opening 28 public GdaJConnection openConnection (String cnc_string, String username, String password) throws Exception { 29 Connection cnc; 30 try { 31 Class.forName (driver); 32 cnc = DriverManager.getConnection (cnc_string, username, password); 33 } 34 catch (Exception e) { 35 throw e; 36 } 37 GdaJConnection jcnc = new GdaJConnection (cnc, driver); 38 return jcnc; 39 } 40 41 // Get a list of all the known drivers 42 // See also http://www.devx.com/tips/Tip/28818 for a list of drivers 43 public static String getDrivers () { 44 try { 45 Class driverClass = Class.forName ("org.hsqldb.jdbcDriver"); 46 } 47 catch (Exception e) { 48 // ignore exceptions, they mean some drivers are not available 49 } 50 51 java.util.Enumeration e = DriverManager.getDrivers(); 52 String res = null; 53 while (e.hasMoreElements ()) { 54 Driver driver = (Driver) e.nextElement(); 55 if (res == null) 56 res = driver.getClass().getName(); 57 else 58 res = res + ":" + driver.getClass().getName(); 59 if (false) 60 System.out.println ("FOUND DRIVER " + driver.getClass().getName()); 61 62 // Properties list, for DSN spec creation. 63 if (false) { 64 System.out.println("===== DEBUG: Properties for " + driver.getClass().getName()); 65 try { 66 Properties ep = new Properties(); 67 DriverPropertyInfo[] props = driver.getPropertyInfo ("", ep); 68 if (props != null) { 69 for (int i = 0; i < props.length; i++){ 70 DriverPropertyInfo prop = props[i]; 71 System.out.println (" Prop name = "+prop.name); 72 System.out.println (" Prop description = "+prop.description); 73 System.out.println (" Prop value = "+prop.value); 74 if (prop.choices != null) { 75 for (int j = 0; j < prop.choices.length; j++) { 76 System.out.println (" prop choice "+j 77 +" = "+prop.choices[j]); 78 } 79 } 80 } 81 } 82 } 83 catch (Exception ex) { 84 ex.printStackTrace (); 85 } 86 } 87 } 88 return res; 89 } 90 91 public static Connection openConnection (String driver, String cnc_string) { 92 System.out.println ("JAVA openConnection() requested"); 93 return null; 94 } 95 96 // main(): in case someone tries to exetute the JAR 97 public static void main (String args[]) { 98 System.out.println ("This JAR is not intended to be executed directly, " + 99 "but used as Libgda's JDBC provider!"); 100 } 101 102 // class initializer 103 static { 104 if (System.getProperty("os.name").indexOf ("Win") >= 0) { 105 // If we are running on Windows, then we need to set the full library name 106 // because our library is still called libgda-jdbc.dll 107 System.loadLibrary ("libgda-jdbc"); 108 } 109 else { 110 System.loadLibrary ("gda-jdbc"); 111 } 112 initIDs (); 113 114 try { 115 /* dummy objects creation to force class loading */ 116 byte[] data = {'e'}; 117 GdaInputStream is = new GdaInputStream (data); 118 } 119 catch (Exception e) { 120 System.out.println ("Coult not initialize some JAVA classes"); 121 e.printStackTrace (); 122 } 123 } 124 } 125 126 127 /* 128 * This class will be instantiated once for each GdaConnection object 129 */ 130 class GdaJConnection { 131 private static native void initIDs(); 132 public Connection cnc = null; 133 private HashMap<String,Savepoint> svp_map = new HashMap<String,Savepoint>(); 134 private GdaJMeta jmeta = null; 135 String driver; 136 137 // Constructor 138 public GdaJConnection (Connection cnc, String driver) throws Exception { 139 this.cnc = cnc; 140 this.driver = driver; 141 } 142 143 // Connection close 144 public void close () throws Exception { 145 this.cnc.close (); 146 jmeta = null; 147 } 148 149 // get server version 150 public String getServerVersion () throws Exception { 151 DatabaseMetaData meta_data; 152 meta_data = cnc.getMetaData (); 153 return meta_data.getDatabaseProductName() + " " + meta_data.getDatabaseProductVersion (); 154 } 155 156 // prepare statement 157 public GdaJPStmt prepareStatement (String sql) throws Exception { 158 GdaJPStmt ps; 159 PreparedStatement pstmt; 160 161 pstmt = cnc.prepareStatement (sql); 162 ps = new GdaJPStmt (pstmt); 163 return ps; 164 } 165 166 // direct execution of a SELECT with no parameters 167 public GdaJResultSet executeDirectSQL (String sql) throws Exception { 168 Statement st; 169 st = cnc.createStatement (); 170 return new GdaJResultSet (st.executeQuery (sql)); 171 } 172 173 // Transaction management 174 public void begin () throws Exception { 175 if (cnc.getAutoCommit() == false) { 176 throw new Exception ("Transaction already started"); 177 } 178 cnc.setAutoCommit (false); 179 } 180 181 public void rollback () throws Exception { 182 if (cnc.getAutoCommit() == true) { 183 throw new Exception ("No transaction started"); 184 } 185 cnc.rollback (); 186 cnc.setAutoCommit (true); 187 } 188 189 public void commit () throws Exception { 190 if (cnc.getAutoCommit() == true) { 191 throw new Exception ("No transaction started"); 192 } 193 cnc.commit (); 194 cnc.setAutoCommit (true); 195 } 196 197 public void addSavepoint (String svp_name) throws Exception { 198 Savepoint svp; 199 if (cnc.getAutoCommit() == true) { 200 throw new Exception ("No transaction started"); 201 } 202 203 svp = svp_map.get (svp_name); 204 if (svp != null) { 205 throw new Exception ("Savepoint '" + svp_name + "' already exists"); 206 } 207 svp = cnc.setSavepoint (svp_name); 208 svp_map.put (svp_name, svp); 209 } 210 211 public void rollbackSavepoint (String svp_name) throws Exception { 212 Savepoint svp = null; 213 if (cnc.getAutoCommit() == true) { 214 throw new Exception ("No transaction started"); 215 } 216 svp = svp_map.get (svp_name); 217 if (svp == null) { 218 throw new Exception ("No savepoint '" + svp_name + "' found"); 219 } 220 cnc.rollback (svp); 221 svp_map.remove (svp_name); 222 } 223 224 public void releaseSavepoint (String svp_name) throws Exception { 225 Savepoint svp = null; 226 if (cnc.getAutoCommit() == true) { 227 throw new Exception ("No transaction started"); 228 } 229 svp = svp_map.get (svp_name); 230 if (svp == null) { 231 throw new Exception ("No savepoint '" + svp_name + "' found"); 232 } 233 cnc.releaseSavepoint (svp); 234 svp_map.remove (svp_name); 235 } 236 237 // meta data retrieval 238 public GdaJMeta getJMeta () throws Exception { 239 if (jmeta == null) { 240 String name= driver.replace (".", "_") + "Meta"; 241 try { 242 Class<?> r = Class.forName (name); 243 java.lang.reflect.Constructor c = 244 r.getConstructor (new Class [] {Class.forName ("java.sql.Connection")}); 245 jmeta = (GdaJMeta) c.newInstance (new Object [] {cnc}); 246 } 247 catch (Exception e) { 248 if (driver.contains ("org.apache.derby.jdbc")) { 249 try { 250 name = "org_apache_derbyMeta"; 251 Class<?> r = Class.forName (name); 252 java.lang.reflect.Constructor c = 253 r.getConstructor (new Class [] {Class.forName ("java.sql.Connection")}); 254 jmeta = (GdaJMeta) c.newInstance (new Object [] {cnc}); 255 } 256 catch (Exception e1) { 257 // nothing 258 } 259 } 260 else if (driver.contains ("sqlserver") || 261 driver.contains ("com.ashna.jturbo.driver.Driver") || 262 driver.contains ("com.inet.tds.TdsDriver")) { 263 try { 264 name = "sqlserverMeta"; 265 Class<?> r = Class.forName (name); 266 java.lang.reflect.Constructor c = 267 r.getConstructor (new Class [] {Class.forName ("java.sql.Connection")}); 268 jmeta = (GdaJMeta) c.newInstance (new Object [] {cnc}); 269 } 270 catch (Exception e1) { 271 // nothing 272 } 273 } 274 } 275 if (jmeta == null) 276 jmeta = new GdaJMeta (cnc); 277 } 278 return jmeta; 279 } 280 281 // class initializer 282 static { 283 initIDs (); 284 } 285 } 286 287 /* 288 * Represents a prepared statement 289 */ 290 class GdaJPStmt { 291 private static native void initIDs(); 292 private PreparedStatement ps; 293 private Vector<GdaJValue> param_values; 294 295 // Constructor 296 public GdaJPStmt (PreparedStatement ps) { 297 this.ps = ps; 298 param_values = new Vector<GdaJValue> (0); 299 } 300 301 // declares the expected type for the parameters 302 public void declareParamTypes (long cnc_c_pointer, byte types[]) throws Exception { 303 int nparams = ps.getParameterMetaData().getParameterCount (); 304 int i; 305 if (types.length != nparams) { 306 throw new Exception ("Number of types differs from number of parameters: got " + types.length + 307 " and expected " + nparams); 308 } 309 310 for (i = 0; i < nparams; i++) { 311 GdaJValue cv = GdaJValue.proto_type_to_jvalue (types[i]); 312 cv.setGdaConnectionPointer (cnc_c_pointer); 313 param_values.add (cv); 314 //System.out.println ("JAVA: param " + i + " as type " + types[i]); 315 } 316 } 317 318 // sets a parameter's value 319 // if c_value_pointer is 0, then the parameter should be set to NULL 320 public void setParameterValue (int index, long c_value_pointer) throws Exception { 321 GdaJValue cv = param_values.elementAt (index); 322 cv.getCValue (ps, index, c_value_pointer); 323 } 324 325 // Clear previous set parameters 326 public void clearParameters () throws Exception { 327 ps.clearParameters (); 328 } 329 330 // Execute 331 public boolean execute () throws Exception { 332 return ps.execute (); 333 } 334 335 // Fetch result set 336 public GdaJResultSet getResultSet () throws Exception { 337 return new GdaJResultSet (ps.getResultSet ()); 338 } 339 340 public int getImpactedRows () throws Exception { 341 return ps.getUpdateCount (); 342 } 343 344 // class initializer 345 static { 346 initIDs (); 347 } 348 } 349 350 351 /* 352 * This class represents meta data information for a GdaJResultSet. 353 * 354 * All the fields are read-only 355 */ 356 class GdaJResultSetInfos { 357 private static native void initIDs(); 358 public Vector<GdaJColumnInfos> col_infos; 359 private int ncols; 360 361 // Constructor 362 public GdaJResultSetInfos (ResultSetMetaData md) throws Exception { 363 int i; 364 ncols = md.getColumnCount (); 365 col_infos = new Vector<GdaJColumnInfos> (0); 366 for (i = 0; i < ncols; i++) { 367 GdaJColumnInfos ci; 368 int rcol = i + 1; 369 ci = new GdaJColumnInfos (md.getColumnName (rcol), md.getColumnLabel (rcol), md.getColumnType (rcol)); 370 col_infos.add (ci); 371 } 372 } 373 374 public GdaJResultSetInfos (Vector<GdaJColumnInfos> col_infos) { 375 this.col_infos = col_infos; 376 ncols = col_infos.size (); 377 } 378 379 // describe a column, index starting at 0 380 public GdaJColumnInfos describeColumn (int col) throws Exception { 381 return (GdaJColumnInfos) col_infos.elementAt (col); 382 } 383 384 // class initializer 385 static { 386 initIDs (); 387 } 388 } 389 390 class GdaJColumnInfos { 391 private static native void initIDs(); 392 String col_name; 393 String col_descr; 394 int col_type; 395 396 public GdaJColumnInfos (String col_name, String col_descr, int col_type) { 397 this.col_name = col_name; 398 this.col_descr = col_descr; 399 this.col_type = col_type; 400 } 401 402 // class initializer 403 static { 404 initIDs (); 405 } 406 } 407 408 /* 409 * This class represents a result set: the result of a SELECT statement 410 */ 411 class GdaJResultSet { 412 private static native void initIDs(); 413 private ResultSet rs; 414 415 private int ncols; 416 protected Vector<GdaJValue> col_values; 417 418 // Constructor 419 public GdaJResultSet (ResultSet rs) throws Exception { 420 this.rs = rs; 421 if (rs != null) { 422 ncols = rs.getMetaData().getColumnCount(); 423 col_values = new Vector<GdaJValue> (ncols); 424 } 425 } 426 427 protected GdaJResultSet (int ncols) { 428 this.ncols = ncols; 429 col_values = new Vector<GdaJValue> (ncols); 430 } 431 432 // get result set's meta data 433 public GdaJResultSetInfos getInfos () throws Exception { 434 return new GdaJResultSetInfos (rs.getMetaData ()); 435 } 436 437 /* 438 * declares the expected type for the column 439 */ 440 public void declareColumnTypes (long cnc_c_pointer, byte types[]) throws Exception { 441 int i; 442 if (types.length != ncols) { 443 throw new Exception ("Number of types differs from number of columns: expected " + ncols + " got " + 444 types.length); 445 } 446 for (i = 0; i < ncols; i++) { 447 GdaJValue cv = GdaJValue.proto_type_to_jvalue (types[i]); 448 cv.setGdaConnectionPointer (cnc_c_pointer); 449 cv.setGdaRowColumn (i); 450 col_values.add (cv); 451 } 452 columnTypesDeclared (); 453 } 454 455 protected void columnTypesDeclared () { 456 // do nothing here, let sub classes do it. 457 } 458 459 /* 460 * move iterator to next row and fills row 461 * @c_pointer is a pointer to the new GdaRow to fill values 462 * Returns: false if no more row available 463 */ 464 public boolean fillNextRow (long c_pointer) throws Exception { 465 int i; 466 if (! rs.next ()) 467 return false; 468 for (i = 0; i < ncols; i++) { 469 GdaJValue cv = col_values.elementAt (i); 470 cv.setCValue (rs, i, c_pointer); 471 } 472 return true; 473 } 474 475 // class initializer 476 static { 477 initIDs (); 478 } 479 } 480 481 482 /* 483 * Classes to represent value transport between the JAVA and C worlds: 484 * - JAVA -> C when reading through a resultset 485 * - C -> JAVA when setting the parameter's values of a prepared statement 486 */ 487 abstract class GdaJValue { 488 private static native void initIDs(); 489 protected long cnc_c_pointer = 0; 490 protected int gda_row_column = -1; 491 protected boolean convert_lc = false; // true if strings must be converted to lower case (ignored by non String) 492 protected boolean no_null = false; // converts a NULL value to "" for a string (ignored by non String) 493 494 /* 495 * @c_pointer points to a GdaRow 496 * @col starts at 0 497 */ 498 native void setCString (long c_pointer, int col, String string); 499 native void setCInt (long c_pointer, int col, int i); 500 native void setCChar (long c_pointer, int col, byte b); 501 native void setCDouble (long c_pointer, int col, double d); 502 native void setCFloat (long c_pointer, int col, float f); 503 native void setCLong (long c_pointer, int col, long l); 504 native void setCShort (long c_pointer, int col, short s); 505 native void setCBoolean (long c_pointer, int col, boolean b); 506 native void setCDate (long c_pointer, int col, int year, int month, int day); 507 native void setCTime (long c_pointer, int col, int hour, int min, int sec); 508 native void setCTimestamp (long c_pointer, int col, int year, int month, int day, int hour, int min, int sec); 509 native void setCBinary (long c_pointer, int col, byte[] data); 510 native void setCBlob (long c_pointer, int col, long cnc_c_pointer, GdaJBlobOp blob); 511 native void setCNumeric (long c_pointer, int col, String str, int precision, int scale); 512 513 /* 514 * @c_pointer points to a GValue, may NOT be 0 ( <=> NULL ) 515 */ 516 native String getCString (long c_pointer); 517 native int getCInt (long c_pointer); 518 native byte getCChar (long c_pointer); 519 native double getCDouble (long c_pointer); 520 native float getCFloat (long c_pointer); 521 native long getCLong (long c_pointer); 522 native short getCShort (long c_pointer); 523 native boolean getCBoolean (long c_pointer); 524 native java.sql.Date getCDate (long c_pointer); 525 native java.sql.Time getCTime (long c_pointer); 526 native java.sql.Timestamp getCTimestamp (long c_pointer); 527 native byte[] getCBinary (long c_pointer); 528 native GdaInputStream getCBlob (long c_pointer); 529 native java.math.BigDecimal getCNumeric (long c_pointer); 530 531 /* 532 * Sets the C GValue's value from @rs at column @col (@c_pointer points to the GdaRow 533 * which contains the GValues) 534 */ 535 abstract void setCValue (ResultSet rs, int col, long c_pointer) throws Exception; /* @col starts at 0 */ 536 537 /* 538 * Set @ps's parameter at index @index from the C GValue pointed by @c_pointer (if @c_pointer is 0, then 539 * the parameter is set to NULL) 540 */ 541 abstract void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception; /* @index starts at 0 */ 542 543 public void setGdaConnectionPointer (long cnc_c_pointer) { 544 this.cnc_c_pointer = cnc_c_pointer; 545 } 546 547 public void setGdaRowColumn (int col) { 548 gda_row_column = col; 549 } 550 551 552 // (year, month, day) -> java.sql.Date 553 public static java.sql.Date createDate (int year, int month, int day) { 554 Calendar cal = GregorianCalendar.getInstance(); 555 cal.set (year, month, day); 556 return new java.sql.Date (cal.getTimeInMillis ()); 557 } 558 559 // (hour, minute, sec) -> java.sql.Time 560 public static java.sql.Time createTime (int hour, int min, int sec) { 561 Calendar cal = GregorianCalendar.getInstance(); 562 cal.set (0, 0, 0, hour, min, sec); 563 return new java.sql.Time (cal.getTimeInMillis ()); 564 } 565 566 // (year, month, day, hour, minute, sec) -> java.sql.Timestamp 567 public static java.sql.Timestamp createTimestamp (int year, int month, int day, int hour, int min, int sec) { 568 Calendar cal = GregorianCalendar.getInstance(); 569 cal.set (year, month, day, hour, min, sec); 570 return new java.sql.Timestamp (cal.getTimeInMillis ()); 571 } 572 573 // types conversions 574 public static GdaJValue proto_type_to_jvalue (byte type) throws Exception { 575 GdaJValue cv; 576 switch (type) { 577 case 0: /* GDA_TYPE_NULL */ 578 cv = new GdaJNull (); 579 break; 580 case 1: /* G_TYPE_STRING */ 581 cv = new GdaJString (); 582 break; 583 case 2: /* G_TYPE_INT */ 584 cv = new GdaJInt (); 585 break; 586 case 3: /* G_TYPE_CHAR */ 587 cv = new GdaJChar (); 588 break; 589 case 4: /* G_TYPE_DOUBLE */ 590 cv = new GdaJDouble (); 591 break; 592 case 5: /* G_TYPE_FLOAT */ 593 cv = new GdaJFloat (); 594 break; 595 case 6: /* G_TYPE_BOOLEAN */ 596 cv = new GdaJBoolean (); 597 break; 598 case 7: /* G_TYPE_DATE */ 599 cv = new GdaJDate (); 600 break; 601 case 8: /* GDA_TYPE_TIME */ 602 cv = new GdaJTime (); 603 break; 604 case 9: /* GDA_TYPE_TIMESTAMP */ 605 cv = new GdaJTimestamp (); 606 break; 607 case 10: /* GDA_TYPE_BINARY */ 608 cv = new GdaJBinary (); 609 break; 610 case 11: /* GDA_TYPE_BLOB */ 611 cv = new GdaJBlob (); 612 break; 613 case 12: /* G_TYPE_INT64 */ 614 cv = new GdaJInt64 (); 615 break; 616 case 13: /* GDA_TYPE_SHORT */ 617 cv = new GdaJShort (); 618 break; 619 case 14: /* GDA_TYPE_NUMERIC */ 620 cv = new GdaJNumeric (); 621 break; 622 623 default: 624 throw new Exception ("Unhandled protocol type " + type); 625 } 626 return cv; 627 } 628 629 // Same as gda-jdbc-recordset.c::jdbc_type_to_g_type 630 // see http://docs.oracle.com/javase/6/docs/api/constant-values.html#java.sql.Types.ARRAY for reference 631 public static String jdbc_type_to_g_type (int type) { 632 switch (type) { 633 case java.sql.Types.VARCHAR: 634 return "gchararray"; 635 case java.sql.Types.ARRAY: 636 return "GdaBinary"; 637 case java.sql.Types.BIGINT: 638 return "gint64"; 639 case java.sql.Types.BINARY: 640 return "GdaBinary"; 641 case java.sql.Types.BIT: 642 return "gboolean"; 643 case java.sql.Types.BLOB: 644 return "GdaBlob"; 645 case java.sql.Types.BOOLEAN: 646 return "gboolean"; 647 case java.sql.Types.CHAR: 648 return "gchararray"; 649 case java.sql.Types.CLOB: 650 case java.sql.Types.DATALINK: 651 return "GdaBinary"; 652 case java.sql.Types.DATE: 653 return "GDate"; 654 case java.sql.Types.DECIMAL: 655 return "GdaNumeric"; 656 case java.sql.Types.DISTINCT: 657 return "GdaBinary"; 658 case java.sql.Types.DOUBLE: 659 return "gdouble"; 660 case java.sql.Types.FLOAT: 661 return "gfloat"; 662 case java.sql.Types.INTEGER: 663 return "gint"; 664 case java.sql.Types.JAVA_OBJECT: 665 return "GdaBinary"; 666 case java.sql.Types.LONGNVARCHAR: 667 return "gchararray"; 668 case java.sql.Types.LONGVARBINARY: 669 return "GdaBinary"; 670 case java.sql.Types.LONGVARCHAR: 671 return "gchararray"; 672 case java.sql.Types.NCHAR: 673 return "gchararray"; 674 case java.sql.Types.NCLOB: 675 return "GdaBinary"; 676 case java.sql.Types.NULL: 677 return "GdaNull"; 678 case java.sql.Types.NUMERIC: 679 return "GdaNumeric"; 680 case java.sql.Types.NVARCHAR: 681 return "gchararray"; 682 case java.sql.Types.OTHER: 683 return "GdaBinary"; 684 case java.sql.Types.REAL: 685 return "gfloat"; 686 case java.sql.Types.REF: 687 return "GdaBinary"; 688 case java.sql.Types.ROWID: 689 return "gchararray"; 690 case java.sql.Types.SMALLINT: 691 return "GdaShort"; 692 case java.sql.Types.SQLXML: 693 return "gchararray"; 694 case java.sql.Types.STRUCT: 695 return "GdaBinary"; 696 case java.sql.Types.TIME: 697 return "GdaTime"; 698 case java.sql.Types.TIMESTAMP: 699 return "GdaTimestamp"; 700 case java.sql.Types.TINYINT: 701 return "gchar"; 702 case java.sql.Types.VARBINARY: 703 default: 704 return "GdaBinary"; 705 } 706 } 707 708 public static String toLower (String string) { 709 String s2 = string.toUpperCase(); 710 if (s2 == string) 711 return string.toLowerCase(); 712 else 713 return string; 714 } 715 716 // class initializer 717 static { 718 initIDs (); 719 } 720 } 721 722 class GdaJString extends GdaJValue { 723 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 724 String string; 725 string = rs.getString (col + 1); 726 if (string == null) { 727 if (no_null) 728 setCString (c_pointer, gda_row_column, ""); 729 } 730 else { 731 if (convert_lc) { 732 String s2 = string.toUpperCase(); 733 if (s2 == string) 734 string = string.toLowerCase(); 735 } 736 setCString (c_pointer, gda_row_column, string); 737 } 738 } 739 740 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 741 if (c_pointer == 0) 742 ps.setNull (index + 1, java.sql.Types.VARCHAR); 743 else { 744 String string; 745 string = getCString (c_pointer); 746 ps.setString (index + 1, string); 747 } 748 } 749 } 750 751 class GdaJInt extends GdaJValue { 752 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 753 int i; 754 i = rs.getInt (col + 1); 755 if ((i != 0) || !rs.wasNull ()) 756 setCInt (c_pointer, gda_row_column, i); 757 } 758 759 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 760 if (c_pointer == 0) 761 ps.setNull (index + 1, java.sql.Types.INTEGER); 762 else { 763 int i; 764 i = getCInt (c_pointer); 765 ps.setInt (index + 1, i); 766 } 767 } 768 } 769 770 class GdaJDouble extends GdaJValue { 771 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 772 double d; 773 d = rs.getDouble (col + 1); 774 if ((d != 0) || !rs.wasNull ()) 775 setCDouble (c_pointer, gda_row_column, d); 776 } 777 778 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 779 if (c_pointer == 0) 780 ps.setNull (index + 1, java.sql.Types.DOUBLE); 781 else { 782 double d; 783 d = getCDouble (c_pointer); 784 ps.setDouble (index + 1, d); 785 } 786 } 787 } 788 789 class GdaJFloat extends GdaJValue { 790 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 791 float f; 792 f = rs.getFloat (col + 1); 793 if ((f != 0) || !rs.wasNull ()) 794 setCFloat (c_pointer, gda_row_column, f); 795 } 796 797 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 798 if (c_pointer == 0) 799 ps.setNull (index + 1, java.sql.Types.FLOAT); 800 else { 801 float f; 802 f = getCFloat (c_pointer); 803 ps.setFloat (index + 1, f); 804 } 805 } 806 } 807 808 class GdaJBoolean extends GdaJValue { 809 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 810 boolean b; 811 b = rs.getBoolean (col + 1); 812 if (b || !rs.wasNull ()) 813 setCBoolean (c_pointer, gda_row_column, b); 814 } 815 816 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 817 if (c_pointer == 0) 818 ps.setNull (index + 1, java.sql.Types.BOOLEAN); 819 else { 820 boolean b; 821 b = getCBoolean (c_pointer); 822 ps.setBoolean (index + 1, b); 823 } 824 } 825 } 826 827 class GdaJDate extends GdaJValue { 828 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 829 java.sql.Date date; 830 date = rs.getDate (col + 1); 831 if (date != null) { 832 Calendar cal = GregorianCalendar.getInstance(); 833 cal.setTime (date); 834 setCDate (c_pointer, gda_row_column, cal.get (Calendar.YEAR), 835 cal.get (Calendar.MONTH) + 1, cal.get (Calendar.DAY_OF_MONTH)); 836 } 837 } 838 839 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 840 if (c_pointer == 0) 841 ps.setNull (index + 1, java.sql.Types.DATE); 842 else { 843 java.sql.Date d; 844 d = getCDate (c_pointer); 845 ps.setDate (index + 1, d); 846 } 847 } 848 } 849 850 class GdaJTime extends GdaJValue { 851 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 852 java.sql.Time time; 853 time = rs.getTime (col + 1); 854 if (time != null) { 855 Calendar cal = GregorianCalendar.getInstance(); 856 cal.setTime (time); 857 setCTime (c_pointer, gda_row_column, cal.get (Calendar.HOUR_OF_DAY), 858 cal.get (Calendar.MINUTE) + 1, cal.get (Calendar.SECOND)); 859 } 860 } 861 862 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 863 if (c_pointer == 0) 864 ps.setNull (index + 1, java.sql.Types.TIME); 865 else { 866 java.sql.Time t; 867 t = getCTime (c_pointer); 868 ps.setTime (index + 1, t); 869 } 870 } 871 } 872 873 class GdaJTimestamp extends GdaJValue { 874 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 875 java.sql.Timestamp ts; 876 ts = rs.getTimestamp (col + 1); 877 if (ts != null) { 878 Calendar cal = GregorianCalendar.getInstance(); 879 cal.setTime (ts); 880 setCTimestamp (c_pointer, gda_row_column, cal.get (Calendar.YEAR), 881 cal.get (Calendar.MONTH) + 1, cal.get (Calendar.DAY_OF_MONTH), 882 cal.get (Calendar.HOUR_OF_DAY), 883 cal.get (Calendar.MINUTE) + 1, cal.get (Calendar.SECOND)); 884 } 885 } 886 887 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 888 if (c_pointer == 0) 889 ps.setNull (index + 1, java.sql.Types.TIMESTAMP); 890 else { 891 java.sql.Timestamp ts; 892 ts = getCTimestamp (c_pointer); 893 ps.setTimestamp (index + 1, ts); 894 } 895 } 896 } 897 898 class GdaJBinary extends GdaJValue { 899 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 900 byte[] bin; 901 bin = rs.getBytes (col + 1); 902 if (bin != null) { 903 setCBinary (c_pointer, gda_row_column, bin); 904 } 905 } 906 907 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 908 if (c_pointer == 0) 909 ps.setNull (index + 1, java.sql.Types.BINARY); 910 else { 911 byte[] bin; 912 bin = getCBinary (c_pointer); 913 ps.setBytes (index + 1, bin); 914 } 915 } 916 } 917 918 class GdaJBlob extends GdaJValue { 919 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 920 java.sql.Blob blob; 921 blob = rs.getBlob (col + 1); 922 if (blob != null) { 923 setCBlob (c_pointer, gda_row_column, cnc_c_pointer, new GdaJBlobOp (blob)); 924 } 925 } 926 927 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 928 if (c_pointer == 0) 929 ps.setNull (index + 1, java.sql.Types.BLOB); 930 else { 931 GdaInputStream is; 932 is = getCBlob (c_pointer); 933 ps.setBinaryStream (index + 1, is, (int) is.size); 934 } 935 } 936 } 937 938 class GdaJChar extends GdaJValue { 939 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 940 Byte b; 941 b = rs.getByte (col + 1); 942 if ((b != 0) || !rs.wasNull ()) 943 setCChar (c_pointer, gda_row_column, b); 944 } 945 946 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 947 if (c_pointer == 0) 948 ps.setNull (index + 1, java.sql.Types.CHAR); 949 else { 950 byte b; 951 b = getCChar (c_pointer); 952 ps.setByte (index + 1, b); 953 } 954 } 955 } 956 957 class GdaJInt64 extends GdaJValue { 958 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 959 long l; 960 l = rs.getLong (col + 1); 961 if ((l != 0) || !rs.wasNull ()) 962 setCLong (c_pointer, gda_row_column, l); 963 } 964 965 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 966 if (c_pointer == 0) 967 ps.setNull (index + 1, java.sql.Types.BIGINT); 968 else { 969 long l; 970 l = getCLong (c_pointer); 971 ps.setLong (index + 1, l); 972 } 973 } 974 } 975 976 class GdaJShort extends GdaJValue { 977 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 978 short s; 979 s = rs.getShort (col + 1); 980 if ((s != 0) || !rs.wasNull ()) 981 setCShort (c_pointer, gda_row_column, s); 982 } 983 984 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 985 if (c_pointer == 0) 986 ps.setNull (index + 1, java.sql.Types.SMALLINT); 987 else { 988 short s; 989 s = getCShort (c_pointer); 990 ps.setShort (index + 1, s); 991 } 992 } 993 } 994 995 class GdaJNumeric extends GdaJValue { 996 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 997 java.math.BigDecimal bd; 998 999 bd = rs.getBigDecimal (col + 1); 1000 if (bd != null) { 1001 setCNumeric (c_pointer, gda_row_column, bd.toString(), bd.precision(), bd.scale()); 1002 } 1003 } 1004 1005 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 1006 if (c_pointer == 0) 1007 ps.setNull (index + 1, java.sql.Types.NUMERIC); 1008 else { 1009 java.math.BigDecimal bd; 1010 bd = getCNumeric (c_pointer); 1011 ps.setBigDecimal (index + 1, bd); 1012 } 1013 } 1014 } 1015 1016 class GdaJNull extends GdaJValue { 1017 void setCValue (ResultSet rs, int col, long c_pointer) throws Exception { 1018 // nothing to do 1019 } 1020 1021 void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception { 1022 ParameterMetaData md; 1023 int i = index + 1; 1024 md = ps.getParameterMetaData (); 1025 ps.setNull (i, md.getParameterType (i)); 1026 } 1027 } 1028 1029 1030 /* 1031 * This class represents a Blob, used by the GdaBlobOp object 1032 * to transfer data from JDBC -> C 1033 */ 1034 class GdaJBlobOp { 1035 private static native void initIDs(); 1036 private Blob blob; 1037 1038 // Constructor 1039 public GdaJBlobOp (Blob blob) { 1040 this.blob = blob; 1041 } 1042 1043 // Get Blob's length 1044 public long length () throws Exception { 1045 return blob.length (); 1046 } 1047 1048 // Read data 1049 public byte[] read (long offset, int len) throws Exception { 1050 return blob.getBytes (offset + 1, len); 1051 } 1052 1053 // Write data 1054 public int write (long offset, byte[] data) throws Exception { 1055 int i; 1056 i = blob.setBytes (offset, data); 1057 if (i != data.length) { 1058 throw new Exception ("Could not write the complete BLOB"); 1059 } 1060 return i; 1061 } 1062 1063 // class initializer 1064 static { 1065 initIDs (); 1066 } 1067 } 1068 1069 /* 1070 * an InputStream which reads from a GdaBlob, for 1071 * data transfer C -> JDBC 1072 * 1073 * Note: the @size attribute is not used here since the PreparedStatement.setBinaryStream() already 1074 * contains the blob's size and won't try to get more. If this InputStream were to be used 1075 * somewhere else, then @size would have to be handled correctly. 1076 */ 1077 class GdaInputStream extends InputStream { 1078 static int chunk_size = 65536; // 64kb chunks 1079 1080 private static native void initIDs(); 1081 private native byte[] readByteData (long gda_blob_pointer, long offset, long size); 1082 public long size; 1083 private long current_pos; 1084 private long gda_blob_pointer; 1085 1086 private InputStream ist = null; // delegate 1087 1088 // Constructor 1089 public GdaInputStream (long gda_blob_pointer, long size) { 1090 current_pos = 0; 1091 this.size = size; 1092 this.gda_blob_pointer = gda_blob_pointer; 1093 } 1094 1095 // Constructor 1096 public GdaInputStream (byte[] data) { 1097 this.gda_blob_pointer = 0; 1098 ist = new ByteArrayInputStream (data); 1099 } 1100 1101 // abstract class implementation 1102 public int read() throws IOException { 1103 int i = -1; 1104 if (ist != null) 1105 i = ist.read (); 1106 1107 if ((i == -1) && (gda_blob_pointer != 0)) { 1108 byte[] data; 1109 data = readByteData (gda_blob_pointer, current_pos, chunk_size); 1110 current_pos += data.length; 1111 ist = new ByteArrayInputStream (data); 1112 i = ist.read (); 1113 } 1114 return i; 1115 } 1116 1117 // class initializer 1118 static { 1119 initIDs (); 1120 } 1121 } 1122