001package bradleyross.library.database; 002import java.sql.PreparedStatement; 003import java.sql.SQLException; 004import java.sql.Driver; 005import java.sql.DriverManager; 006import java.sql.ResultSet; 007import java.sql.Statement; 008import java.sql.ResultSetMetaData; 009import java.io.PrintWriter; 010import java.io.PrintStream; 011import java.sql.Types; 012import java.util.regex.Pattern; 013import java.util.regex.Matcher; 014import bradleyross.library.NotSupportedException; 015import bradleyross.library.database.DatabaseExtras; 016import bradleyross.library.helpers.GenericPrinter; 017/** 018 * Supports usage of databases via JDBC (Java DataBase Connection) 019 * protocol. 020 *<p>This is an abstract class and can't be used directly in the 021 * creation of objects. This means that subclasses must be 022 * created.</p> 023 * <p>When creating subclasses, many fields will have to be set, 024 * including 025 * <code><a href="#handlerClass">handlerClass</a></code>, 026 * <code><a href="#accountName">accountName</a></code>, 027 * <code><a href="#connectionString">connectionString</a></code>, and 028 * <code><a href="#password">password</a></code>.</p> 029 *<p>By including the objects for the JDBC connection and statement, it 030 * is possible to encapsulate a large amount of the code for 031 * the database connectivity.</p> 032 *<p>Please note that the methods in this class do not include one 033 * for obtaining the password used in connecting to the database. 034 * If required, this method can be added in the subclass. 035 * Eliminating this method adds to the security of the system. 036 * By encapsulating the password in a field in this class for 037 * use by the connect method, there is no need for other classes 038 * to have access to the information.</p> 039 * <p>SQL Server notes</p> 040 * <ul> 041 * <li><p>Wants the string <code>dbo.</code> in front of table names.</p></li> 042 * <li><p>Specify the default database as part of the user configuration rather 043 * than including it in the connection string.</p></li> 044 * </ul> 045 * <p>Oracle notes</p> 046 * <ul> 047 * <li><p>Will not accept semicolons at the end of SQL statements.</p></li> 048 * </ul> 049 * <p>MySQL notes</p> 050 * @author Bradley Ross 051 */ 052public abstract class DatabaseProperties 053{ 054 protected Driver driver = null; 055 /** 056 * Constructor using a default system and account name. 057 */ 058 public DatabaseProperties() 059 { 060 invalidParameters = false; 061 clearTableNamePrefixes(); 062 setDatabaseInstance(); 063 } 064 /** 065 * Constructor specifying identifier for system and using 066 * a default account name. 067 * @param value Identifier code for system 068 */ 069 public DatabaseProperties(String value) 070 { 071 invalidParameters = false; 072 clearTableNamePrefixes(); 073 setDatabaseInstance(value); 074 } 075 /** 076 * Constructor specifying system and account name. 077 * @param systemName Identifier code for system 078 * @param accountName Account name to be used 079 */ 080 public DatabaseProperties (String systemName, String accountName) 081 { 082 invalidParameters = false; 083 clearTableNamePrefixes(); 084 setDatabaseInstance(systemName, accountName); 085 } 086 /** 087 * Internal program for setting up connection using default 088 * database and account. 089 * @see #setDatabaseInstance(String, String) 090 */ 091 public abstract void setDatabaseInstance(); 092 /** 093 * Internal program for setting up connection using specified 094 * database with a default account for the database. 095 * @param system Identifying code for database 096 */ 097 public abstract void setDatabaseInstance(String system); 098 /** 099 * Internal program for setting up connection with a specified 100 * database and account name. 101 * @param system Identifier code for database 102 * @param user Account name to be used 103 */ 104 public abstract void setDatabaseInstance(String system, String user); 105 /** 106 * Amount of diagnostic messages. 107 *<p>A value of zero indicates that no diagnostic messages 108 * should be displayed. The higher the value, the more 109 * diagnostic messages will be generated.</p> 110 */ 111 protected int debugLevel = 0; 112 /** 113 * Used to represent associated DatabaseExtras object. 114 */ 115 protected DatabaseExtras extras = null; 116 /** 117 * Set value of extras. 118 * @param value Object to be used for DatabaseExtras object. 119 * @see #extras 120 */ 121 public void setDatabaseExtras(DatabaseExtras value) 122 { 123 extras = value; 124 } 125 /** 126 * Get value of extras. 127 * @return DatabaseExtras object being used. 128 * @throws NotSupportedException if not supported for database 129 * @see #extras 130 */ 131 public DatabaseExtras getDatabaseExtras() throws NotSupportedException 132 { 133 if (extras == null) 134 { 135 throw new NotSupportedException("Database Extras is not supported"); 136 } 137 else 138 { 139 return extras; 140 } 141 } 142 /** 143 * Set of prefixes for table names 144 */ 145 protected String tableNamePrefixes[] = new String[10]; 146 /** Get the value of the default table name prefix (item 0) 147 * @return Default table name prefix 148 */ 149 public String getTableNamePrefixes() 150 { return tableNamePrefixes[0]; } 151 /** 152 * Get the value of a table name prefix 153 * @param i Location of table name prefix in list 154 * @return Value of table name prefix 155 */ 156 public String getTableNamePrefixes(int i) 157 { return tableNamePrefixes[i]; } 158 /** 159 * True indicates that autoCommit is set for this database connection when 160 * the connection is opened. 161 */ 162 protected boolean autoCommit = true; 163 /** 164 * Optional field containing a human readable description of the 165 * database. This string will have to be escaped before it is safe 166 * for use in HTML code and SQL queries. 167 */ 168 protected String systemDescription = null; 169 /** 170 * Getter for systemDescription 171 * @return Description of system 172 * @see #systemDescription 173 */ 174 public String getSystemDescription() 175 { 176 return systemDescription; 177 } 178 /** 179 * This is the name of the system identifier to identify 180 * the database in database systems that can support multiple 181 * databases. 182 */ 183 protected String systemName = null; 184 /** 185 * Name of the handler class for the database. 186 * <table> 187 * <caption>Database driver classes</caption> 188 * <tr><td>Product</td><td>Handler Class</td><td>Default<br>Port</td></tr> 189 * <tr><td>MySQL</td><td><code>com.mysql.jdbc.Driver</code></td><td>3306</td></tr> 190 * <tr><td>Oracle</td><td><code>oracle.jdbc.driver.OracleDriver</code></td><td>1521</td></tr> 191 * <tr><td>SQL Server</td><td><code>com.microsoft.sqlserver.jdbc.SQLServerDriver</code></td><td>1433</td></tr> 192 * </table> 193 * <p>It may be necessary to use the name of the handlerClass in 194 * generating the SQL statements, since the syntax for different 195 * databases such as MySQL, Oracle, DB2, Postgres, etc. differ for 196 * many of the built in functions.</p> 197 * <p>Although there is no <i>get</i> method for this field, one can 198 * be added when creating subclasses.</p> 199 */ 200 protected String handlerClass = null; 201 /** 202 * Port number of the database connection. 203 * <p>The default port number is shown in the discussion of the 204 * <a href="#handlerClass">handler class names</a>. If a port 205 * number other than the default is used, it is included as 206 * part of the <a href="#domainName">domain name</a> and 207 * <a href="#connectionString">connection string</a>.</p> 208 */ 209 protected int portNumber = 0; 210 /** 211 * The connection string to be used to connect to the database using 212 * JDBC (Java DataBase Connectivity) 213 * <p>The connection string is composed as a series of tokens 214 * separated by colons. The first token is always 215 * <code>jdbc</code> while the second is the name 216 * of the database manager product. The remaining 217 * tokens are dependent on the DBMS package used.</p> 218 * <p>The following are examples of connection strings.</p> 219 * <table> 220 * <caption>Formats for database connection strings</caption> 221 * <tr><td>MySQL</td> 222 * <td><code>jdbc:mysql://server.foo.com/alpha</code></td> 223 * <td>alpha is default database</td> 224 * </tr> 225 * <tr><td>Oracle</td> 226 * <td><code>jdbc:oracle:thin:@//server.foo.com/weather<br> 227 * jdbc:oracle:oci:</code></td> 228 * <td>Connects to weather service<br> 229 * The options thin and oci refer to the two types of JDBC connections. The 230 * OCI method requires the installation of additional pieces of software 231 * and uses SQL*Net to connect to the database.</td> 232 * </tr> 233 * <tr><td>SQL Server</td> 234 * <td><code>jdbc:sqlserver://server.foo.com</code></td> 235 * <td>SQL Server allows you to specify a default database as part of the 236 * user configuration.</td> 237 * </tr> 238 * </table> 239 */ 240 protected String connectionString = null; 241 /** 242 * Domain name for the system containing the database. 243 * <p>The domain name is included as part of the 244 * <a href="#connectionString">connection string</a>.</p> 245 */ 246 protected String domainName = null; 247 /** 248 * The account name to be used on the database server. 249 */ 250 protected String accountName = null; 251 /** 252 * The password to be used for accessing the database server. 253 * <p>It should be noted that there is no <i>get</i> method for 254 * the field. This improves security for the package. If necessary, 255 * a <i>get</i> method can be added in a subclass.</p> 256 */ 257 protected String password = null; 258 /** 259 * When creating MySQL tables, this field can be 260 * used by the getEngineClause to add the ENGINE 261 * statement to CREATE TABLE statements. 262 * @see #getEngineClause() 263 */ 264 protected String defaultEngine = null; 265 /** 266 * Default catalog for methods allowing the use 267 * of a default value. 268 * @see #getDefaultCatalog() 269 * @see #setDefaultCatalog(String) 270 */ 271 protected String defaultCatalog = null; 272 /** 273 * Get the value of defaultCatalog. 274 * @return Value of defaultCatalog 275 * @see #defaultCatalog 276 */ 277 public String getDefaultCatalog() 278 { 279 return defaultCatalog; 280 } 281 /** 282 * Sets value of defaultCatalog. 283 * @param value Value to be used for defaultCatalog 284 * @see #defaultCatalog 285 */ 286 public void setDefaultCatalog(String value) 287 { 288 defaultCatalog = value; 289 } 290 /** 291 * Default schema for methods allowing the use 292 * of a default value. 293 * @see #getDefaultSchema() 294 * @see #setDefaultSchema(String) 295 */ 296 protected String defaultSchema = null; 297 /** 298 * Gets value of defaultSchema 299 * @return Value of defaultSchema 300 * @see #defaultSchema 301 */ 302 public String getDefaultSchema() 303 { 304 return defaultSchema; 305 } 306 /** 307 * Sets value of defaultSchema. 308 * @param value Value to be used for defaultSchema 309 * @see #defaultSchema 310 */ 311 public void setDefaultSchema(String value) 312 { 313 defaultSchema = value; 314 } 315 /** 316 * The object representing the connection to the database. 317 * @see #getConnection() 318 */ 319 protected java.sql.Connection connection = null; 320 /** 321 * Flag indicating whether database has been connected. 322 */ 323 protected boolean isConnected = false; 324 /** 325 * Set the amount of diagnostic messages. 326 * @param level Amount of diagnostic messages. 327 */ 328 public void setDebugLevel(int level) 329 { debugLevel = level; } 330 /** 331 * Gets the amount of diagnostic messages to be printed. 332 * 333 * @return Level of diagnostic messages to be printed. 334 */ 335 public int getDebugLevel() 336 { return debugLevel; } 337 /** 338 * If the parameters supplied for instantiating the object are 339 * invalid, this field should be set to true. 340 * 341 * @see #setInvalidParameters(boolean) 342 * @see #hasInvalidParameters() 343 */ 344 protected boolean invalidParameters = false; 345 /** 346 * Returns the instance of the JDBC driver used to connect 347 * to the database. 348 * @return JDBC driver 349 */ 350 public Driver getDriver() { 351 return driver; 352 } 353 /** 354 * Return the system identifier used for the database connection. 355 * @return System identifier 356 */ 357 public String getSystem() 358 { return systemName; } 359 /** 360 * Get name of database management system 361 * <p>The database name is extracted from the 362 * <a href="#connectionString">connection string</a> 363 * as the second token of the string.</p> 364 * @return DBMS descriptor 365 */ 366 public String getDbms() 367 { 368 String working = connectionString.substring(connectionString.indexOf(":")+1); 369 working = working.substring(0, working.indexOf(":")); 370 return working.toLowerCase(); 371 } 372 /** 373 * Return the account name used for the database connection. 374 * @return Account name for database. 375 */ 376 public String getAccountName() 377 { return accountName; } 378 /** 379 * Create optional ENGINE clause 380 * @see #defaultEngine 381 * @return ENGINE clause for CREATE TABLE SQL statement 382 */ 383 public String getEngineClause() 384 { 385 if (defaultEngine == null) 386 { 387 return " "; 388 } 389 else if (getDbms().equalsIgnoreCase("mysql")) 390 { 391 return " ENGINE " + defaultEngine + " "; 392 } 393 else return " "; 394 } 395 /** 396 * Open the database connection. 397 * @throws SQLException exception encountered while connecting 398 */ 399 public void connect() throws java.sql.SQLException 400 { 401 if (invalidParameters) 402 { 403 throw new SQLException("Parameters for system and account name are not valid : " + 404 showAttributes()); 405 } 406 try 407 { 408 driver = (Driver) Class.forName(handlerClass).newInstance(); 409 } 410 catch (InstantiationException e) 411 { 412 System.out.println("*** Error in establishing instance of handler"); 413 System.out.println("*** Instantiation Exception"); 414 System.out.println(e.getMessage()); 415 e.printStackTrace(System.out); 416 } 417 catch (IllegalAccessException e ) 418 { 419 System.out.println("*** Error in establishing instance of handler"); 420 System.out.println("*** Illegal Access Exception"); 421 System.out.println(e.getMessage()); 422 e.printStackTrace(System.out); 423 } 424 catch (ClassNotFoundException e) 425 { 426 System.out.println("*** Error in establishing instance of handler"); 427 System.out.println("*** Class Not Found Exception"); 428 System.out.println(e.getMessage()); 429 e.printStackTrace(System.out); 430 } 431 try 432 { 433 connection = DriverManager.getConnection(connectionString, accountName, 434 password); 435 connection.setAutoCommit(autoCommit); 436 } 437 catch (SQLException e) 438 { 439 System.out.println("SQL Exception"); 440 System.out.println(e.getMessage()); 441 e.printStackTrace(System.out); 442 throw e; 443 } 444 isConnected = true; 445 if (debugLevel > 1) 446 { 447 System.out.println("Database connected"); 448 } 449 } 450 /** 451 * Close the database connection. 452 * @throws SQLException if database error 453 */ 454 public void close() throws SQLException 455 { 456 try 457 { 458 connection.close(); 459 } 460 catch (SQLException e) 461 { 462 e.printStackTrace(System.out); 463 throw e; 464 } 465 } 466 /** 467 * Obtain the connection object for the database connection. 468 * @return connection 469 */ 470 public java.sql.Connection getConnection() 471 { return connection;} 472 /** 473 * Execute SQL statement without returning results. 474 * <p>This method is usually used to make updates to the 475 * database.</p> 476 * @param sqlCode SQL code to be executed. 477 * @return record count 478 * @throws SQLException exceptions encountered while running update 479 */ 480 public int executeUpdate(String sqlCode) throws SQLException 481 { 482 java.sql.Statement stmt = null; 483 int recordCount = -1; 484 try 485 { 486 if (debugLevel > 0) 487 { System.out.println("Starting executeUpdate"); } 488 if (connection == (java.sql.Connection) null) 489 { connect(); } 490 stmt = connection.createStatement(); 491 recordCount = stmt.executeUpdate(sqlCode); 492 if (debugLevel > 0) 493 { System.out.println("Statement executed: " + 494 Integer.toString(recordCount) + 495 " records updated"); } 496 stmt.close(); 497 } 498 catch (SQLException e) 499 { 500 if (debugLevel > 0 ) 501 { 502 System.out.println("SQLException in executeUpdate"); 503 System.out.println(e.getMessage()); 504 e.printStackTrace(System.out); 505 } 506 throw e; 507 } 508 catch (Exception ex) 509 { 510 System.out.println("Unknown Exception in executeUpdate"); 511 ex.printStackTrace(System.out); 512 throw new SQLException(ex.getClass().getName() + " : " + ex.getMessage() + 513 "Unknown Exception in executeUpdate"); 514 } 515 return recordCount; 516 } 517 /** 518 * This class reads the first field on the first record from 519 * an SQL Query. 520 * <p>Since only the first field is read, the statement is 521 * closed after reading the field. This eliminates the possibility 522 * of leaving a statement open if it returns multiple rows.</p> 523 * @param sqlCode SQL code to be executed. 524 * @return String object continuing result of SQL query 525 * @throws SQLException exceptions encountered while executing query 526 */ 527 public String executeSimpleQuery(String sqlCode) 528 throws SQLException 529 { 530 java.sql.Statement stmt = null; 531 java.sql.ResultSet rs = null; 532 java.lang.String result = null; 533 try 534 { 535 if (debugLevel > 0) 536 { System.out.println("Starting executeSimpleQuery"); } 537 if (connection == (java.sql.Connection) null) 538 { connect(); } 539 stmt = connection.createStatement(); 540 rs = stmt.executeQuery(sqlCode); 541 if (debugLevel > 0) 542 { System.out.println("Statement executed"); } 543 /* 544 * The first method is not supported for forward only 545 * result sets. It looks like forward only result 546 * sets are the default for SQL Server. 547 */ 548 rs.next(); 549 result = rs.getString(1); 550 stmt.close(); 551 } 552 catch (SQLException e) 553 { 554 if (debugLevel > 0) 555 { 556 System.out.println("SQLException in executeSimpleQuery"); 557 System.out.println(e.getMessage()); 558 e.printStackTrace(System.out); 559 } 560 throw e; 561 } 562 catch (Exception ex) 563 { 564 System.out.println("Unknown Exception in executeSimpleQuery"); 565 ex.printStackTrace(System.out); 566 } 567 return result; 568 } 569 /** 570 * This class executes an SQL query and returns a 571 * ResultSet. 572 * @param sqlCode SQL code to be executed. 573 * @return ResultSet 574 * @throws SQLException exceptions encountered while executing query 575 */ 576 public java.sql.ResultSet executeQuery(String sqlCode) 577 throws java.sql.SQLException 578 { 579 java.sql.Statement stmt = null; 580 java.sql.ResultSet rs = null; 581 if (!isConnected) 582 { 583 System.out.println(" Error in executeQuery - database is not connected"); 584 throw new SQLException("Database not connected"); 585 } 586 try 587 { 588 if (debugLevel > 0) 589 { System.out.println("Starting executeQuery for " + sqlCode); } 590 if (connection == (java.sql.Connection) null) 591 { 592 if (debugLevel > 1) 593 { 594 System.out.println("Creating connection"); 595 } 596 connect(); 597 } 598 stmt = connection.createStatement(); 599 if (debugLevel > 1) 600 { 601 System.out.println("Statement created"); 602 } 603 rs = stmt.executeQuery(sqlCode); 604 if (debugLevel > 0) 605 { System.out.println("Statement executed"); } 606 } 607 catch (SQLException e) 608 { 609 System.out.println("SQLException in executeQuery"); 610 System.out.println(e.getMessage()); 611 e.printStackTrace(System.out); 612 throw e; 613 } 614 catch (Exception ex) 615 { 616 System.out.println("Unknown Exception in executeQuery"); 617 System.out.println(ex.getClass().getName() + " " + ex.getMessage()); 618 ex.printStackTrace(System.out); 619 } 620 return rs; 621 } 622 /** 623 * Execute a commit statement for the SQL connection. 624 */ 625 public void commit() 626 { 627 try 628 { connection.commit(); } 629 catch (SQLException e) 630 { 631 System.out.println("SQLException during commit"); 632 e.printStackTrace(System.out); 633 } 634 catch (Exception e) 635 { 636 System.out.println("Unknown exception during commit"); 637 e.printStackTrace(System.out); 638 } 639 } 640 /** 641 * Execute a rollback statement for the SQL connection. 642 */ 643 public void rollback() 644 { 645 try 646 { connection.rollback(); } 647 catch (SQLException e) 648 { 649 System.out.println("SQLException during rollback"); 650 e.printStackTrace(System.out); 651 } 652 catch (Exception e) 653 { 654 System.out.println("Unknown exception during rollback"); 655 e.printStackTrace(System.out); 656 } 657 } 658 /** 659 * Set autoCommit flag 660 * @param value Value to be used for setting autoCommit flag 661 */ 662 public void setAutoCommit(boolean value) 663 { 664 try 665 { connection.setAutoCommit(value); } 666 catch (SQLException e) 667 { 668 System.out.println("SQLException while setting autoCommit to " + 669 Boolean.toString(value)); 670 e.printStackTrace(System.out); 671 } 672 } 673 /** 674 * Return attributes of the connection properties 675 * 676 * @return String containing connection information 677 */ 678 public java.lang.String showAttributes() 679 { 680 return ("systemName:" + systemName + 681 "\naccountName:" + accountName + 682 "\ndomainName:" + domainName + 683 "\nhandlerClass:" + handlerClass); 684 } 685 /** 686 * Setter for accountName. 687 * 688 * <p>Must be used before database connection is made.</p> 689 * @param value Value for accountName 690 * 691 */ 692 693 public void setAccountName(String value) 694 { 695 if (isConnected) { return; } 696 accountName = value; 697 setDatabaseInstance(systemName, accountName); 698 } 699 /** 700 * Specify the connection string to be used. 701 * 702 * <p>Do not specify the account name or password as 703 * part of the connection string.</p> 704 * 705 * @param value Connection string to be used 706 * @see #connectionString 707 */ 708 public void setConnectionString(String value) 709 { 710 if (isConnected) { return; } 711 connectionString = value; 712 } 713 /** 714 * Setter for domainName 715 * <p>Does not include port number</p> 716 * @see #domainName 717 * @param value Value to be used for domain name 718 */ 719 public void setDomainName(String value) 720 { 721 if (isConnected) { return; } 722 domainName = value; 723 } 724 /** 725 * Set the class name to be used for the handler class. 726 * @param value Name of handler class 727 * @see #handlerClass 728 */ 729 public void setHandlerClass(String value) 730 { 731 if (isConnected) { return; } 732 handlerClass = value; 733 } 734 /** 735 * Sets the password to be used for the connection 736 * when it is desired to avoid placing the value in 737 * the program. 738 * 739 * @param value Value to be used for the password 740 */ 741 public void setPassword(String value) 742 { 743 if (isConnected) { return; } 744 password = value; 745 } 746 /** 747 * Setter for port number 748 * @param value port number to be used for connection 749 * @see #portNumber 750 */ 751 public void setPortNumber(int value) { 752 portNumber = value; 753 } 754 /** 755 * Setter for systemName. 756 * 757 * @see #systemName 758 * @param value Value to be used for system name 759 * 760 */ 761 public void setSystemName(String value) 762 { 763 if (isConnected) { return; } 764 systemName = value; 765 } 766 /** 767 * Clears the list of table name prefix values. 768 */ 769 public void clearTableNamePrefixes() 770 { 771 for (int i=0; i<tableNamePrefixes.length; i++) 772 { tableNamePrefixes[i] = null; } 773 } 774 /** 775 * Prefixes a table name with a value that was set as part of the 776 * database connection. 777 * 778 * @param type Location of the desired prefix in the tableNamePrefixes list 779 * @param value Table name to be prefixed 780 * @return Prefixed table name 781 */ 782 public java.lang.String prefixTableName(int type, String value) 783 { 784 if (type < 0 || type > 9) 785 { return " " + value + " "; } 786 if (tableNamePrefixes[type] == null) 787 { return " " + value + " "; } 788 if (tableNamePrefixes[type].length() <= 0) 789 { return value; } 790 return (" " + new String(tableNamePrefixes[type] + value) + " "); 791 } 792 /** 793 * Prefixes a table name with a value that was set as part of the database 794 * connection. 795 * 796 * <p>This version of the method uses the first entry in the tableNamePrefixes 797 * array. (index=0)</p> 798 * 799 * @param value Table name to be prefixed 800 * @return Prefixed table name 801 */ 802 public java.lang.String prefixTableName(java.lang.String value) 803 { return prefixTableName(0, value); } 804 /** 805 * Generate a prepared statement for this database. 806 * @param query SQL Query to be used in statement 807 * @return PreparedStatement object 808 * @throws java.sql.SQLException if database errors 809 */ 810 public java.sql.PreparedStatement prepareStatement(String query) 811 throws java.sql.SQLException 812 { 813 if (connection == null) 814 { 815 throw new SQLException("The value of the connection field is null"); 816 } 817 return connection.prepareStatement(query); 818 } 819 /** 820 * Returns the parameter as a DDL comment 821 * if the database is of a type that allows comments in 822 * DDL statements. 823 * 824 * <p>SQL Server does not allow comments in DDL statements.</p> 825 * 826 * @param text Text to be used in comment 827 * @return Formatted material for comment in CREATE TABLE statement 828 */ 829 public String comment(String text) 830 { 831 if (text == null) { return " "; } 832 if (!getDbms().equalsIgnoreCase("sqlserver")) 833 { 834 Pattern pattern = Pattern.compile("\'"); 835 Matcher matcher = pattern.matcher(text); 836 String temp = matcher.replaceAll("\'\'"); 837 return (" COMMENT \'" + temp + "\' "); 838 } 839 else 840 { 841 return (" "); 842 } 843 } 844 /** 845 * Return the data type used for large BLOBS 846 * (Binary Large Objects). 847 * @return Name of data type. 848 */ 849 public String getLongblobTerm() 850 { 851 if (getDbms().equalsIgnoreCase("sqlserver")) 852 { 853 return " VARBINARY(MAX) "; 854 } 855 else if (getDbms().equalsIgnoreCase("mysql")) 856 { 857 return " LONGBLOB "; 858 } 859 else 860 { 861 return " LONGBLOB "; 862 } 863 } 864 /** 865 * Return the expression used in SQL statements to 866 * obtain the current time. 867 * @return SQL clause. 868 */ 869 public String getNowTerm() 870 { 871 if (getDbms().equalsIgnoreCase("sqlserver")) 872 { 873 return " GETDATE() "; 874 } 875 else if (getDbms().equalsIgnoreCase("mysql")) 876 { 877 return " NOW() "; 878 } 879 else if (getDbms().equalsIgnoreCase("oracle")) 880 { 881 return " SYSDATE "; 882 } 883 else 884 { 885 return " NOW() "; 886 } 887 } 888 /** 889 * Return the expression used in SQL statements to 890 * represent a data type for holding a date. 891 * 892 * <p>SQL Server 2000 and 2005 do not have a DATE data type, 893 * and SMALLDATETIME should be used instead.</p> 894 * 895 * @return SQL clause. 896 */ 897 public String getDateTerm() 898 { 899 if (getDbms().equalsIgnoreCase("sqlserver")) 900 { 901 return " SMALLDATETIME "; 902 } 903 else if (getDbms().equalsIgnoreCase("mysql")) 904 { 905 return " DATE "; 906 } 907 else if (getDbms().equalsIgnoreCase("oracle")) 908 { 909 return " DATE "; 910 } 911 else 912 { 913 return " DATE "; 914 } 915 } 916 /** 917 * Return the expression used in SQL statements to 918 * represent a data type for holding a date and time. 919 * 920 * <p>It appears that Oracle refers to this data type 921 * as TIMESTAMP.</p> 922 * 923 * @return SQL clause. 924 */ 925 public String getDatetimeTerm() 926 { 927 if (getDbms().equalsIgnoreCase("sqlserver")) 928 { 929 return " DATETIME "; 930 } 931 else if (getDbms().equalsIgnoreCase("mysql")) 932 { 933 return " DATETIME "; 934 } 935 else if (getDbms().equalsIgnoreCase("oracle")) 936 { 937 return " TIMESTAMP "; 938 } 939 else 940 { 941 return " DATETIME "; 942 } 943 } 944 /** 945 * Decode the values of constants in java.sql.TYPES to 946 * String values. 947 * @param value Value of constant 948 * @return Corresponding string describing constant 949 * @see Types 950 */ 951 public static String decodeSqlType(int value) 952 { 953 if (value == Types.ARRAY) 954 { 955 return "ARRAY"; 956 } 957 else if (value == Types.BIGINT) 958 { 959 return "BIGINT"; 960 } 961 else if (value == Types.BINARY) 962 { 963 return "BINARY"; 964 } 965 else if (value == Types.BIT) 966 { 967 return "BIT"; 968 } 969 else if (value == Types.BLOB) 970 { 971 return "BLOB"; 972 } 973 else if (value == Types.BOOLEAN) 974 { 975 return "BOOLEAN"; 976 } 977 else if (value == Types.CHAR) 978 { 979 return "CHAR"; 980 } 981 else if (value == Types.CLOB) 982 { 983 return "CLOB"; 984 } 985 else if (value == Types.DOUBLE) 986 { 987 return "DOUBLE"; 988 } 989 else if (value == Types.FLOAT) 990 { 991 return "FLOAT"; 992 } 993 else if (value == Types.INTEGER) 994 { 995 return "INTEGER"; 996 } 997 else if (value == Types.JAVA_OBJECT) 998 { 999 return "JAVA_OBJECT"; 1000 } 1001 else if (value == Types.LONGVARBINARY) 1002 { 1003 return "LONGVARBINARY"; 1004 } 1005 else if (value == Types.LONGVARCHAR) 1006 { 1007 return "LONGVARCHAR"; 1008 } 1009 else if (value == Types.REAL) 1010 { 1011 return "REAL"; 1012 } 1013 else if (value == Types.SMALLINT) 1014 { 1015 return "SMALLINT"; 1016 } 1017 else if (value == Types.TINYINT) 1018 { 1019 return "TINYINT"; 1020 } 1021 else if (value == Types.VARCHAR) 1022 { 1023 return "VARCHAR"; 1024 } 1025 else if (value == Types.VARBINARY) 1026 { 1027 return "VARBINARY"; 1028 } 1029 else if (value == Types.DATE) 1030 { 1031 return "DATE"; 1032 } 1033 else if (value == Types.TIME) 1034 { 1035 return "TIME"; 1036 } 1037 else if (value == Types.TIMESTAMP) 1038 { 1039 return "TIMESTAMP"; 1040 } 1041 else 1042 { 1043 return "Unrecognized value"; 1044 } 1045 } 1046 1047 /** 1048 * Set value of invalidParameters to indicate that constructor is not valid. 1049 * @param value Value to be used for notSupported 1050 */ 1051 protected void setInvalidParameters(boolean value) 1052 { 1053 invalidParameters = value; 1054 } 1055 /** 1056 * Determine whether parameters for constructor were valid. 1057 * @return True if combination of system and account is not supported 1058 */ 1059 public boolean hasInvalidParameters() 1060 { 1061 return invalidParameters; 1062 } 1063 /** 1064 * Dump contents of database table to PrintWriter object. 1065 * 1066 * @param table Name of table to be dumped 1067 * @param output Destination PrintWriter 1068 */ 1069 public void dumpTable(String table, PrintWriter output) 1070 { 1071 dumpTable(table, table, output, (PrintStream) null); 1072 } 1073 /** 1074 * Dump contents of database to PrintStream object 1075 * @param table Name of table to be dumped 1076 * @param output Destination PrintStream 1077 */ 1078 public void dumpTable(String table, PrintStream output) 1079 { 1080 dumpTable(table, table, (PrintWriter) null, output); 1081 } 1082 /** 1083 * Dumps the contents of a table as a series of SQL statements. 1084 * <p>An OutputStreamWriter can be created from an OutputStream using the 1085 * constructor <code>OutputStreamWriter(OutputStream out)</code>.</p> 1086 * <p>The objects <code>System.out</code> and <code>System.err</code> are 1087 * PrintStream objects. A PrintStream object can be created from an 1088 * OutputStream object using the constructor 1089 * <code>PrintStream(OutputStream out)</code>.</p> 1090 * <p>A PrintStream object can be created from a File object using the 1091 * constructor 1092 * <code>PrintStream (File out)</code>.</p> 1093 * 1094 * @param sourceTableName Table to be dumped 1095 * @param targetTableName Table name to be used in SELECT statement 1096 * @param outputWriter PrintWriter object to which information is to be passed 1097 * @param outputStream PrintStream object to which information is to be passed 1098 */ 1099 protected void dumpTable(String sourceTableName, String targetTableName, PrintWriter outputWriter, 1100 PrintStream outputStream) 1101 { 1102 System.out.println("Starting table dumper for " + sourceTableName); 1103 setAutoCommit(false); 1104 String tableName = prefixTableName(sourceTableName); 1105 String sqlQuery = "SELECT * FROM " + tableName ; 1106 if (debugLevel > 1) 1107 { 1108 System.out.println("Query is " + sqlQuery); 1109 } 1110 Statement stmt = null; 1111 ResultSet rs = null; 1112 try 1113 { 1114 boolean test; 1115 stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 1116 /* 1117 * This is apparently a fix for large result sets specific to MySQL. 1118 * There was also a comment to try 1119 * ((com.mysql.jdbc.Statement) stmt).enableStreamingResults(); 1120 */ 1121 if (getDbms().equalsIgnoreCase("mysql")) 1122 { 1123 if (debugLevel > 1) 1124 { 1125 System.out.println("Special case for MySQL large result sets"); 1126 } 1127 stmt.setFetchSize(Integer.MIN_VALUE); 1128 } 1129 else if (getDbms().equalsIgnoreCase("sqlserver")) 1130 stmt.setFetchSize(20); 1131 if (debugLevel > 1) 1132 { 1133 int sample = stmt.getResultSetType(); 1134 if (sample == ResultSet.TYPE_FORWARD_ONLY) 1135 { 1136 System.out.println("Result set is TYPE_FORWARD_ONLY"); 1137 } 1138 else if (sample == ResultSet.TYPE_SCROLL_INSENSITIVE) 1139 { 1140 System.out.println("Result set is TYPE_SCROLL_INSENSITIVE"); 1141 } 1142 else if (sample == ResultSet.TYPE_SCROLL_SENSITIVE) 1143 { 1144 System.out.println("Result set is TYPE_SCROLL_SENSITIVE"); 1145 } 1146 else 1147 { 1148 System.out.println("Result set is of unknown type"); 1149 } 1150 } 1151 test = stmt.execute(sqlQuery); 1152 if (!test) 1153 { 1154 System.out.println("Problem in executing " + sqlQuery); 1155 return; 1156 } 1157 rs = stmt.getResultSet(); 1158 if (rs == null) 1159 { 1160 System.out.println("Result set was null"); 1161 } 1162 else 1163 { 1164 System.out.println("Result set generated"); 1165 } 1166 } 1167 catch (java.sql.SQLException e) 1168 { 1169 System.out.println("SQL Exception encountered: " + e.getMessage()); 1170 e.printStackTrace(System.out); 1171 } 1172 catch (Exception e) 1173 { 1174 System.out.println("Unexpected exception in table dumper"); 1175 System.out.println(e.getClass().getName() + " " + e.getMessage()); 1176 e.printStackTrace(System.out); 1177 } 1178 } 1179 public void dumpTable(String sourceTableName, String targetTableName, 1180 GenericPrinter output) 1181 { 1182 System.out.println("dumpTable: Starting table dumper for " + sourceTableName); 1183 setAutoCommit(false); 1184 String tableName = prefixTableName(sourceTableName); 1185 String sqlQuery = "SELECT * FROM " + tableName ; 1186 if (debugLevel > 1) 1187 { 1188 System.out.println("dumpTable: Query is " + sqlQuery); 1189 } 1190 Statement stmt = null; 1191 ResultSet rs = null; 1192 try 1193 { 1194 boolean test; 1195 stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 1196 /* 1197 * This is apparently a fix for large result sets specific to MySQL. 1198 * There was also a comment to try 1199 * ((com.mysql.jdbc.Statement) stmt).enableStreamingResults(); 1200 */ 1201 if (getDbms().equalsIgnoreCase("mysql")) 1202 { 1203 if (debugLevel > 1) 1204 { 1205 System.out.println("Special case for MySQL large result sets"); 1206 } 1207 stmt.setFetchSize(Integer.MIN_VALUE); 1208 } 1209 else if (getDbms().equalsIgnoreCase("sqlserver")) 1210 stmt.setFetchSize(20); 1211 if (debugLevel > 1) 1212 { 1213 int sample = stmt.getResultSetType(); 1214 if (sample == ResultSet.TYPE_FORWARD_ONLY) 1215 { 1216 System.out.println("Result set is TYPE_FORWARD_ONLY"); 1217 } 1218 else if (sample == ResultSet.TYPE_SCROLL_INSENSITIVE) 1219 { 1220 System.out.println("Result set is TYPE_SCROLL_INSENSITIVE"); 1221 } 1222 else if (sample == ResultSet.TYPE_SCROLL_SENSITIVE) 1223 { 1224 System.out.println("Result set is TYPE_SCROLL_SENSITIVE"); 1225 } 1226 else 1227 { 1228 System.out.println("Result set is of unknown type"); 1229 } 1230 } 1231 test = stmt.execute(sqlQuery); 1232 if (!test) 1233 { 1234 System.out.println("Problem in executing " + sqlQuery); 1235 return; 1236 } 1237 rs = stmt.getResultSet(); 1238 if (rs == null) 1239 { 1240 System.out.println("dumpTable: Result set was null"); 1241 } 1242 else 1243 { 1244 System.out.println("dumpTable: Result set generated"); 1245 dumpResultSet(rs, targetTableName, output); 1246 } 1247 } 1248 catch (java.sql.SQLException e) 1249 { 1250 System.out.println("SQL Exception encountered: " + e.getMessage()); 1251 e.printStackTrace(System.out); 1252 } 1253 catch (Exception e) 1254 { 1255 System.out.println("Unexpected exception in table dumper"); 1256 System.out.println(e.getClass().getName() + " " + e.getMessage()); 1257 e.printStackTrace(System.out); 1258 } 1259 } 1260 1261 /** 1262 * Dumps a result set to a PrintWriter object 1263 * @param rs Result Set 1264 * @param targetTableName Table name to be used in INSERT statement 1265 * @param outputWriter Destination PrintWriter object 1266 */ 1267 public void dumpResultSet(ResultSet rs, String targetTableName, PrintWriter outputWriter) 1268 { 1269 GenericPrinter out = new GenericPrinter(outputWriter); 1270 dumpResultSet(rs, targetTableName, out); 1271 } 1272 /** 1273 * Dumps a result set to a PrintStream object 1274 * @param rs Result set 1275 * @param targetTableName Table name to be used in INSERT statement 1276 * @param outputStream Destination PrintStream object 1277 */ 1278 public void dumpResultSet(ResultSet rs, String targetTableName, PrintStream outputStream) 1279 { 1280 GenericPrinter out = new GenericPrinter(outputStream); 1281 dumpResultSet(rs, targetTableName, out); 1282 } 1283 /** 1284 * Dumps a result set as a set of INSERT SQL statements. 1285 * 1286 * @param rs Result set to be dumped 1287 * @param targetTableName Table name to be used in INSERT statements 1288 * @param output GenericPrinter object to which information is passed 1289 * 1290 */ 1291 public void dumpResultSet(ResultSet rs, String targetTableName, GenericPrinter output) 1292 { 1293 ResultSetMetaData meta = null; 1294 int columnCount = 0; 1295 String columnNames[]; 1296 int columnTypes[]; 1297 int rowCounter = 0; 1298 try 1299 { 1300 rowCounter = 0; 1301 meta = rs.getMetaData(); 1302 columnCount = meta.getColumnCount(); 1303 if (debugLevel > 0) 1304 { 1305 System.out.println("Query executed, " + Integer.toString(columnCount) + " columns"); 1306 } 1307 columnNames = new String[columnCount]; 1308 columnTypes = new int[columnCount]; 1309 for (int i = 0; i < columnCount; i++) 1310 { 1311 columnNames[i] = meta.getColumnName(i+1); 1312 columnTypes[i] = meta.getColumnType(i+1); 1313 } 1314 /* Get result set */ 1315 while (rs.next()) 1316 { 1317 boolean nullValue[] = new boolean[columnCount]; 1318 String columnValue[] = new String[columnCount]; 1319 for (int i = 0; i < columnCount; i++) 1320 { 1321 nullValue[i] = false; 1322 columnValue[i] = null; 1323 } 1324 rowCounter++; 1325 if (rowCounter % 500 == 49) 1326 { 1327 output.flush(); 1328 } 1329 StringBuffer working; 1330 /* Read values for SQL statement */ 1331 for (int i = 0; i < columnCount; i++) 1332 { 1333 1334 int temp = columnTypes[i]; 1335 if (temp == Types.TIMESTAMP) 1336 { 1337 java.sql.Timestamp date = rs.getTimestamp(i+1); 1338 if (rs.wasNull()) 1339 { 1340 nullValue[i] = true; 1341 columnValue[i] = "dummy"; 1342 } 1343 else 1344 { 1345 columnValue[i] ="\'" + date.toString() + "\'"; 1346 } 1347 } 1348 else if (temp == Types.VARCHAR || temp == Types.LONGVARCHAR || 1349 temp == Types.CHAR) 1350 { 1351 String value = rs.getString(i+1); 1352 if (rs.wasNull()) 1353 { 1354 nullValue[i] = true; 1355 1356 } 1357 else 1358 { 1359 1360 columnValue[i] = "\'" + value + "\'"; 1361 } 1362 } 1363 else if (temp == Types.FLOAT || temp == Types.DOUBLE || temp == Types.DECIMAL || 1364 temp == Types.NUMERIC || temp == Types.REAL) 1365 { 1366 float value = 0.0f; 1367 value = rs.getFloat(i+1); 1368 if (rs.wasNull()) 1369 { 1370 nullValue[i] = true; 1371 1372 } 1373 else 1374 { 1375 1376 columnValue[i] = Float.toString(value); 1377 } 1378 } 1379 else if (temp == Types.TINYINT || temp == Types.SMALLINT || 1380 temp == Types.INTEGER) 1381 { 1382 int value = rs.getInt(i+1); 1383 if (rs.wasNull()) 1384 { 1385 nullValue[i] = true; 1386 1387 } 1388 else 1389 { 1390 1391 columnValue[i] = Integer.toString(value); 1392 } 1393 } 1394 } 1395 /* 1396 * Write SQL statement 1397 */ 1398 working = new StringBuffer(); 1399 boolean firstItemProcessed = false; 1400 working.append("INSERT INTO " + targetTableName + "("); 1401 for (int i = 0; i < columnCount; i++) 1402 { 1403 if (nullValue[i]) 1404 { 1405 continue; 1406 } 1407 if (firstItemProcessed) 1408 { 1409 working.append(", " + columnNames[i]); 1410 } 1411 else 1412 { 1413 working.append(columnNames[i]); 1414 firstItemProcessed = true; 1415 } 1416 } 1417 working.append(") VALUES("); 1418 firstItemProcessed = false; 1419 for (int i = 0; i < columnCount; i++) 1420 { 1421 if (nullValue[i]) 1422 { 1423 continue; 1424 } 1425 if (firstItemProcessed) 1426 { 1427 working.append(", " + columnValue[i]); 1428 } 1429 else 1430 { 1431 working.append(columnValue[i]); 1432 firstItemProcessed = true; 1433 } 1434 } 1435 working.append(");"); 1436 output.println(new String(working)); 1437 } 1438 if (debugLevel > 0) 1439 { 1440 System.out.println(Integer.toString(rowCounter) + " rows were processed"); 1441 } 1442 rs.close(); 1443 } 1444 catch (java.sql.SQLException e) 1445 { 1446 System.out.println("SQL Exception encountered: "); 1447 System.out.println(e.getClass().getName()+ e.getMessage()); 1448 e.printStackTrace(System.out); 1449 } 1450 catch (Exception e) 1451 { 1452 System.out.println("Unexpected exception in table dumper"); 1453 System.out.println(e.getClass().getName() + " " + e.getMessage()); 1454 e.printStackTrace(System.out); 1455 } 1456 } 1457 /** 1458 * Insert rows in a table where there is only one column in 1459 * the primary key. 1460 * 1461 * <p>The primary key should be the first column in the list.</p> 1462 * 1463 * @param tableName Name of the table 1464 * @param columnNames Array containing column names in the database 1465 * table for the columns to be populated with data. 1466 * @param value Values to be inserted in the columns 1467 * @throws SQLException if database errors 1468 * @deprecated 1469 */ 1470 public void insertRow (String tableName, 1471 String columnNames[], Object... value) throws SQLException 1472 { 1473 insertRowWithKeys (tableName, columnNames, 1, value); 1474 } 1475 /** 1476 * Insert rows in a table where there is more than one column in 1477 * the primary key. 1478 * 1479 * @param tableName Name of the table 1480 * @param columnNames Array containing column names in the database 1481 * table. 1482 * @param columnCount Number of columns in primary key. These are the first 1483 * columns in the list. 1484 * @param value Values to be inserted in the columns 1485 * @throws SQLException if database errors 1486 */ 1487 public void insertRowWithKeys (String tableName, 1488 String columnNames[], int columnCount, Object... value) throws SQLException 1489 { 1490 if (debugLevel > 1 || columnNames.length != value.length) 1491 { 1492 System.out.println("Starting insertRow"); 1493 1494 for (int i = 0; i < columnNames.length; i++) 1495 { 1496 System.out.print(columnNames[i] + " "); 1497 } 1498 System.out.println(); 1499 for (int i = 0; i < value.length; i ++) 1500 { 1501 System.out.print(value[i] + " "); 1502 } 1503 System.out.println(); 1504 } 1505 StringBuffer queryBuffer = new StringBuffer(); 1506 queryBuffer.append("SELECT COUNT(*) AS COUNTER FROM " + 1507 prefixTableName(tableName) + 1508 " WHERE "); 1509 1510 for (int i = 0; i < columnCount; i++) 1511 { 1512 if (i > 0) { queryBuffer.append(" AND "); } 1513 queryBuffer.append(columnNames[i] + "=? "); 1514 1515 } 1516 PreparedStatement stmt = prepareStatement(new String(queryBuffer)); 1517 if (debugLevel > 0) 1518 { 1519 System.out.println(new String(queryBuffer)); 1520 System.out.print(" "); 1521 for (int i = 0; i < columnCount; i++) 1522 { 1523 if (i > 0) System.out.print(" "); 1524 System.out.print(value[i].toString()); 1525 } 1526 System.out.println(); 1527 } 1528 for (int i = 0; i < columnCount; i++) 1529 { 1530 stmt.setObject(i + 1, value[i]); 1531 } 1532 ResultSet rs = stmt.executeQuery(); 1533 queryBuffer = new StringBuffer(); 1534 rs.next(); 1535 int rowCount = rs.getInt("COUNTER"); 1536 if (rowCount == 0) 1537 { 1538 boolean firstItem = true; 1539 if (debugLevel > 1) 1540 { 1541 System.out.println("Inserting record"); 1542 } 1543 queryBuffer.append("INSERT INTO " + prefixTableName(tableName) + " ( "); 1544 for (int i = 0; i < columnNames.length; i++) 1545 { 1546 if (value[i] == null) { continue; } 1547 if (!firstItem) { queryBuffer.append(", "); } 1548 queryBuffer.append(columnNames[i]); 1549 firstItem = false; 1550 } 1551 firstItem = true; 1552 queryBuffer.append(" ) VALUES ( "); 1553 for (int i = 0; i < columnNames.length; i++) 1554 { 1555 if (value[i] == null) { continue; } 1556 if (!firstItem) { queryBuffer.append(", "); } 1557 if (Number.class.isAssignableFrom(value[i].getClass())) 1558 { 1559 queryBuffer.append(value[i].toString()); 1560 } 1561 else if (String.class.isAssignableFrom(value[i].getClass())) 1562 { 1563 queryBuffer.append("\'" + value[i].toString() + "\'"); 1564 } 1565 firstItem = false; 1566 } 1567 queryBuffer.append(" )"); 1568 } 1569 else 1570 { 1571 boolean firstItem = true; 1572 if (debugLevel > 1) 1573 { 1574 System.out.println("Updating row"); 1575 } 1576 if (columnNames.length == 1) 1577 { 1578 return; 1579 } 1580 if (value[0] == null) 1581 { 1582 throw new SQLException("Primary key value may not be null"); 1583 } 1584 queryBuffer.append("UPDATE " + prefixTableName(tableName) + " SET "); 1585 for (int i = columnCount; i < columnNames.length; i++) 1586 { 1587 if (value[i] == null) { continue; } 1588 if (!firstItem) 1589 { 1590 queryBuffer.append(", "); 1591 } 1592 queryBuffer.append(" " + columnNames[i] + "="); 1593 if (Number.class.isAssignableFrom(value[i].getClass())) 1594 { 1595 queryBuffer.append(value[i].toString()); 1596 } 1597 else if (String.class.isAssignableFrom(value[i].getClass())) 1598 { 1599 queryBuffer.append("\'" + value[i].toString() + "\'"); 1600 } 1601 firstItem = false; 1602 } 1603 queryBuffer.append(" WHERE "); 1604 firstItem = true; 1605 for (int i = 0; i < columnCount; i++) 1606 { 1607 if (!firstItem) 1608 { 1609 queryBuffer.append(" AND "); 1610 } 1611 queryBuffer.append(columnNames[i] + "="); 1612 if (Number.class.isAssignableFrom(value[i].getClass())) 1613 { 1614 queryBuffer.append(value[i].toString()); 1615 } 1616 else if (String.class.isAssignableFrom(value[i].getClass())) 1617 { 1618 queryBuffer.append("\'" + value[i].toString() + "\'"); 1619 } 1620 firstItem = false; 1621 } 1622 } 1623 if (debugLevel > 0) 1624 { 1625 System.out.println(new String(queryBuffer)); 1626 } 1627 executeUpdate(new String(queryBuffer)); 1628 } 1629}