001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.oozie.util.db; 019 020 import java.io.BufferedInputStream; 021 import java.io.BufferedOutputStream; 022 import java.io.ByteArrayOutputStream; 023 import java.io.IOException; 024 import java.sql.Blob; 025 import java.sql.Connection; 026 import java.sql.PreparedStatement; 027 import java.sql.ResultSet; 028 import java.sql.SQLException; 029 import java.sql.Timestamp; 030 import java.util.ArrayList; 031 import java.util.HashSet; 032 import java.util.List; 033 import java.util.Map; 034 import java.util.Set; 035 036 import org.apache.commons.logging.LogFactory; 037 import org.apache.oozie.util.XLog; 038 import org.apache.oozie.util.db.Schema.Column; 039 import org.apache.oozie.util.db.Schema.Table; 040 041 /** 042 * The <code>SqlStatement</code> is used to generate SQL Statements. Prepare the generated Statements and also to parse 043 * the resultSets 044 */ 045 public abstract class SqlStatement { 046 047 private static XLog log = new XLog(LogFactory.getLog(SqlStatement.class)); 048 protected boolean forUpdate = false; 049 050 /** 051 * <code>ResultSetReader</code> is used to parse the result set and gives methods for getting appropriate type of 052 * data given the column name 053 */ 054 public static class ResultSetReader { 055 final ResultSet rSet; 056 057 private ResultSetReader(ResultSet rSet) { 058 this.rSet = rSet; 059 } 060 061 /** 062 * Move the Result Set to next record 063 * 064 * @return true if there is a next record 065 * @throws SQLException 066 */ 067 public boolean next() throws SQLException { 068 return rSet.next(); 069 } 070 071 /** 072 * Close the Result Set 073 * 074 * @throws SQLException 075 */ 076 public void close() throws SQLException { 077 rSet.close(); 078 } 079 080 /** 081 * Get the Column data given its type and name 082 * 083 * @param <T> Type of the column 084 * @param clazz Class of the Type 085 * @param col Column name 086 * @return Column data 087 * @throws SQLException 088 */ 089 @SuppressWarnings("unchecked") 090 public <T> T get(Class<T> clazz, Column col) throws SQLException { 091 if (clazz.isAssignableFrom(col.getType())) { 092 return (T) rSet.getObject(col.asLabel()); 093 } 094 else { 095 if (String.class.equals(clazz)) { 096 return (T) ("" + rSet.getObject(col.asLabel())); 097 } 098 else { 099 throw new RuntimeException("Column Error : Actual Type [" + col.getType() + "]," + " Requested Type [" 100 + clazz + "] !!"); 101 } 102 } 103 } 104 105 /** 106 * Get the data for columns with blob type 107 * 108 * @param col Column name 109 * @return Column data 110 * @throws SQLException 111 */ 112 public byte[] getByteArray(Column col) throws SQLException { 113 byte[] bArray = null; 114 if (Blob.class.equals(col.getType())) { 115 BufferedInputStream bStream = new BufferedInputStream(rSet.getBinaryStream(col.asLabel())); 116 byte[] temp = new byte[1024]; 117 int num = 0; 118 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 119 BufferedOutputStream bOut = new BufferedOutputStream(baos); 120 try { 121 while ((num = bStream.read(temp)) != -1) { 122 bOut.write(temp, 0, num); 123 } 124 bOut.flush(); 125 bOut.close(); 126 } 127 catch (IOException e) { 128 throw new SQLException(e); 129 } 130 bArray = baos.toByteArray(); 131 } 132 else { 133 throw new RuntimeException("Column Error : Actual Type [" + col.getType() + "]," + " Requested Type [" 134 + Blob.class + "] !!"); 135 } 136 return bArray; 137 } 138 139 /** 140 * Get a String Column 141 * 142 * @param col Column Name 143 * @return Column data 144 * @throws SQLException 145 */ 146 public String getString(Column col) throws SQLException { 147 return get(String.class, col); 148 } 149 150 /** 151 * Get the Timestamp Column 152 * 153 * @param col Column name 154 * @return Column data 155 * @throws SQLException 156 */ 157 public Timestamp getTimestamp(Column col) throws SQLException { 158 return get(Timestamp.class, col); 159 } 160 161 /** 162 * Get the Boolean Column 163 * 164 * @param col Column name 165 * @return Column data 166 * @throws SQLException 167 */ 168 public Boolean getBoolean(Column col) throws SQLException { 169 return get(Boolean.class, col); 170 } 171 172 /** 173 * Get the Numeric data 174 * 175 * @param col Column name 176 * @return Column data 177 * @throws SQLException 178 */ 179 public Long getLong(Column col) throws SQLException { 180 return get(Long.class, col); 181 } 182 183 } 184 185 /** 186 * Construct the condition statement that will be used in the where clause 187 */ 188 public static class Condition { 189 190 final Column column; 191 protected StringBuilder sb = new StringBuilder("( "); 192 protected List<Object> values = new ArrayList<Object>(); 193 194 private Condition(Column column) { 195 this.column = column; 196 if (column != null) { 197 sb.append(column); 198 } 199 } 200 201 /** 202 * Return the Condition string 203 */ 204 public String toString() { 205 return sb.toString(); 206 } 207 } 208 209 /** 210 * NULL/NOT NULL Condition Generator 211 */ 212 static class Null extends Condition { 213 Null(boolean isInvert, Column column) { 214 super(column); 215 sb.append(" IS"); 216 sb.append(isInvert ? " NOT" : ""); 217 sb.append(" NULL "); 218 sb.append(" )"); 219 } 220 } 221 222 /** 223 * Generate condition statement for IS NULL 224 * 225 * @param column column name 226 * @return IS NULL condition statement 227 */ 228 public static Condition isNull(Column column) { 229 return new Null(false, column); 230 } 231 232 /** 233 * Generate condition statement for IS NOT NULL 234 * 235 * @param column column name 236 * @return IS NOT NULL condition statement 237 */ 238 public static Condition isNotNull(Column column) { 239 return new Null(true, column); 240 } 241 242 /** 243 * LIKE/NOT LIKE Condition Generator 244 */ 245 static class Like extends Condition { 246 Like(boolean isInvert, Column column, String value) { 247 super(column); 248 sb.append(isInvert ? " NOT" : "").append(" LIKE ").append("?").append(" )"); 249 values.add(value); 250 } 251 } 252 253 /** 254 * Generate condition statement for IS LIKE 255 * 256 * @param column column name 257 * @param value value to be checked 258 * @return IS LIKE condition statement 259 */ 260 public static Condition isLike(Column column, String value) { 261 return new Like(false, column, value); 262 } 263 264 /** 265 * Generates condition statement for IS NOT LIKE 266 * 267 * @param column column name 268 * @param value value to be checked 269 * @return IS NOT LIKE condition statement 270 */ 271 public static Condition isNotLike(Column column, String value) { 272 return new Like(true, column, value); 273 } 274 275 /** 276 * Comparison condition statement generator 277 */ 278 static class Compare extends Condition { 279 Compare(String oper, Column column, Object value) { 280 super(column); 281 if (value instanceof Column) { 282 sb.append(oper).append(value).append(" )"); 283 } 284 else { 285 sb.append(oper).append("?").append(" )"); 286 values.add(value); 287 } 288 } 289 } 290 291 /** 292 * Generate Condition statement for equality check 293 * 294 * @param column 295 * @param value 296 * @return Equality Condition statement 297 */ 298 public static Condition isEqual(Column column, Object value) { 299 return new Compare(" = ", column, value); 300 } 301 302 /** 303 * Generate InEquality Condition statement 304 * 305 * @param column 306 * @param value 307 * @return Inequality Condition statement 308 */ 309 public static Condition isNotEqual(Column column, Object value) { 310 return new Compare(" <> ", column, value); 311 } 312 313 /** 314 * Generate Condition statement for LESS THAN condition checking 315 * 316 * @param column 317 * @param value 318 * @return less than condition statement 319 */ 320 public static Condition lessThan(Column column, Object value) { 321 return new Compare(" < ", column, value); 322 } 323 324 /** 325 * Generate Condition statement for GREATER THAN condition checking 326 * 327 * @param column 328 * @param value 329 * @return greater than condition statement 330 */ 331 public static Condition greaterThan(Column column, Object value) { 332 return new Compare(" > ", column, value); 333 } 334 335 /** 336 * Generate Condition statement for LESS THAN OR EQUAL condition checking 337 * 338 * @param column 339 * @param value 340 * @return less than or equal condition statement 341 */ 342 public static Condition lessThanOrEqual(Column column, Object value) { 343 return new Compare(" <= ", column, value); 344 } 345 346 /** 347 * Generate Condition statement for GREATER THAN OR EQUAL condition checking 348 * 349 * @param column 350 * @param value 351 * @return greater than or equal condition statement 352 */ 353 public static Condition greaterThanOrEqual(Column column, Object value) { 354 return new Compare(" >= ", column, value); 355 } 356 357 /** 358 * IN/NOT IN condition statement generator for checking multiple values and for sub queries 359 */ 360 static class In extends Condition { 361 In(boolean isInvert, Column column, Object... values) { 362 super(column); 363 sb.append(isInvert ? " NOT" : "").append(" IN ("); 364 for (Object value : values) { 365 sb.append(" ? ").append(","); 366 this.values.add(value); 367 } 368 // remove last comma 369 sb.setLength(sb.length() - 1); 370 sb.append(") )"); 371 } 372 373 In(boolean isInvert, Column column, Select select) { 374 super(column); 375 sb.append(isInvert ? " NOT" : "").append(" IN ("); 376 for (Object value : select.values) { 377 this.values.add(value); 378 } 379 sb.append(select.toString()); 380 sb.append(") )"); 381 } 382 } 383 384 /** 385 * IN Condition for checking multiple values 386 * 387 * @param column 388 * @param values 389 * @return In condition statement 390 */ 391 public static Condition in(Column column, Object... values) { 392 return new In(false, column, values); 393 } 394 395 /** 396 * NOT IN Condition for checking multiple values 397 * 398 * @param column 399 * @param values 400 * @return not in condition statement 401 */ 402 public static Condition notIn(Column column, Object... values) { 403 return new In(true, column, values); 404 } 405 406 /** 407 * Sub query with IN condition 408 * 409 * @param column 410 * @param select 411 * @return Sub query using in 412 */ 413 public static Condition in(Column column, Select select) { 414 return new In(false, column, select); 415 } 416 417 /** 418 * Sub query with NOT IN condition 419 * 420 * @param column 421 * @param select 422 * @return sub query using not in 423 */ 424 public static Condition notIn(Column column, Select select) { 425 return new In(true, column, select); 426 } 427 428 /** 429 * Generate the Range checking statements 430 */ 431 static class Between extends Condition { 432 Between(boolean isInvert, Column column, Object lVal, Object rVal) { 433 super(column); 434 sb.append(isInvert ? " NOT" : "").append(" BETWEEN "); 435 sb.append(" ? "); 436 values.add(lVal); 437 sb.append(" AND "); 438 sb.append(" ? ").append(" )"); 439 values.add(rVal); 440 } 441 } 442 443 /** 444 * BETWEEN range checking statement 445 * 446 * @param column 447 * @param lVal min value for range checking 448 * @param rVal max value for range checking 449 * @return between condition statement 450 */ 451 public static Condition between(Column column, Object lVal, Object rVal) { 452 return new Between(false, column, lVal, rVal); 453 } 454 455 /** 456 * NOT BETWEEN range checking statement 457 * 458 * @param column 459 * @param lVal min value for range checking 460 * @param rVal max value for range checking 461 * @return not between condition statement 462 */ 463 public static Condition notBetween(Column column, Object lVal, Object rVal) { 464 return new Between(true, column, lVal, rVal); 465 } 466 467 /** 468 * Logical AND condition Generator 469 * 470 * @param conds list of conditions for AND 471 * @return AND statement 472 */ 473 public static Condition and(Condition... conds) { 474 Condition retVal = new Condition(null); 475 if (conds.length >= 2) { 476 for (int i = 0; i < conds.length; i++) { 477 if (i > 0) { 478 retVal.sb.append(" AND "); 479 } 480 retVal.sb.append(conds[i].sb); 481 retVal.values.addAll(conds[i].values); 482 } 483 } 484 else { 485 if (conds.length == 1) { 486 return conds[0]; 487 } 488 } 489 retVal.sb.append(" )"); 490 return retVal; 491 } 492 493 /** 494 * Logical OR condition generator 495 * 496 * @param conds list of conditions for OR 497 * @return OR statement 498 */ 499 public static Condition or(Condition... conds) { 500 Condition retVal = new Condition(null); 501 if (conds.length >= 2) { 502 for (int i = 0; i < conds.length; i++) { 503 if (i > 0) { 504 retVal.sb.append(" OR "); 505 } 506 retVal.sb.append(conds[i].sb); 507 retVal.values.addAll(conds[i].values); 508 } 509 } 510 else { 511 if (conds.length == 1) { 512 return conds[0]; 513 } 514 } 515 retVal.sb.append(" )"); 516 return retVal; 517 } 518 519 protected StringBuilder sb = new StringBuilder(""); 520 protected List<Object> values = new ArrayList<Object>(); 521 522 /** 523 * Select Statement generator. Generate the SQL Statement for select statements. Provide methods to add WHERE 524 * clause, ORDER BY clause, FOR UPDATE clause. 525 */ 526 public static class Select extends SqlStatement { 527 private Condition condition; 528 private boolean isOdered = false; 529 private Column[] orderby = null; 530 private boolean[] isAscending = null; 531 private boolean isLimitSet = false; 532 533 private Select(Select other) { 534 this.condition = other.condition; 535 this.sb.append(other.sb); 536 this.values.addAll(other.values); 537 this.isOdered = other.isOdered; 538 this.isLimitSet = other.isLimitSet; 539 this.orderby = other.orderby; 540 this.isAscending = other.isAscending; 541 this.forUpdate = other.forUpdate; 542 } 543 544 Select(boolean count, Table... tables) { 545 String temp = count ? "COUNT(*)" : "*"; 546 this.sb.append("SELECT " + temp + " FROM"); 547 if ((tables != null) && (tables.length > 0)) { 548 for (Table table : tables) { 549 this.sb.append(" " + table + " ,"); 550 } 551 // remove comma 552 this.sb.setLength(sb.length() - 1); 553 } 554 else { 555 throw new RuntimeException("Need atleast 1 Table !!"); 556 } 557 } 558 559 Select(Column... columns) { 560 this.sb.append("SELECT"); 561 if ((columns != null) && (columns.length > 0)) { 562 Set<Table> tables = new HashSet<Table>(); 563 for (Column column : columns) { 564 tables.add(column.table()); 565 this.sb.append(" " + column + " AS " + column.asLabel() + " ,"); 566 } 567 // remove comma 568 this.sb.setLength(sb.length() - 1); 569 this.sb.append(" FROM"); 570 for (Table table : tables) { 571 this.sb.append(" " + table + " ,"); 572 } 573 // remove comma 574 this.sb.setLength(sb.length() - 1); 575 } 576 else { 577 throw new RuntimeException("Need atleast 1 Column !!"); 578 } 579 } 580 581 /** 582 * Set the condition for where clause 583 * 584 * @param condition condition for where clause 585 * @return <code>Select</code> for cascading 586 */ 587 public Select where(Condition condition) { 588 Select retVal = new Select(this); 589 retVal.condition = condition; 590 retVal.values.addAll(condition.values); 591 return retVal; 592 } 593 594 /** 595 * Sets the column to sort and the order of sort 596 * 597 * @param column column to sort 598 * @param order true = ascending 599 * @return <code>Select</code> for cascading 600 */ 601 public Select orderBy(Column column, boolean order) { 602 if (!isOdered) { 603 Select retVal = new Select(this); 604 retVal.orderby = new Column[]{column}; 605 retVal.isAscending = new boolean[]{order}; 606 retVal.isOdered = true; 607 return retVal; 608 } 609 return this; 610 } 611 612 /** 613 * To sort 2 columns 614 * 615 * @param column0 First column to be sorted 616 * @param order0 true = ascending 617 * @param column1 Second column to be sorted 618 * @param order1 true = ascending 619 * @return <code>Select</code> for cascading 620 */ 621 public Select orderBy(Column column0, boolean order0, Column column1, boolean order1) { 622 if (!isOdered) { 623 Select retVal = new Select(this); 624 retVal.orderby = new Column[]{column0, column1}; 625 retVal.isAscending = new boolean[]{order0, order1}; 626 retVal.isOdered = true; 627 return retVal; 628 } 629 return this; 630 } 631 632 /** 633 * Setting the offset and limit for LIMIT clause 634 * 635 * @param offset 636 * @param limit 637 * @return <code>Select</code> for cascading 638 */ 639 public Select limit(int offset, int limit) { 640 if (isOdered) { 641 Select retVal = new Select(this); 642 retVal.values.add(limit); 643 retVal.values.add(offset); 644 retVal.isLimitSet = true; 645 return retVal; 646 } 647 return this; 648 } 649 650 /** 651 * Set the "for update" flag to lock the rows for updating 652 * 653 * @return <code>Select</code> for cascading 654 */ 655 // TODO Not working for hsql 656 public Select forUpdate() { 657 Select retVal = new Select(this); 658 retVal.forUpdate = true; 659 return retVal; 660 } 661 662 /** 663 * Generate the SQL Select Statement with conditions and other clauses that were set 664 */ 665 public String toString() { 666 String oBy = ""; 667 if ((orderby != null) && (isAscending != null) && (orderby.length == isAscending.length)) { 668 StringBuffer osb = new StringBuffer(" ORDER BY "); 669 int i = 0; 670 for (Column column : orderby) { 671 osb.append(column.asLabel()).append(isAscending[i] ? " ASC ," : " DESC ,"); 672 } 673 osb.setLength(osb.length() - 1); 674 if (isLimitSet) { 675 osb.append("LIMIT ").append("?").append(" OFFSET ").append("?").append(" "); 676 } 677 oBy = osb.toString(); 678 } 679 return sb.toString() + ((condition != null) ? "WHERE " + condition.toString() : "") + oBy; 680 } 681 } 682 683 /** 684 * SQL Statement generator for DELETE Statements 685 */ 686 public static class Delete extends SqlStatement { 687 Condition condition; 688 final Table table; 689 690 Delete(Table table) { 691 this.table = table; 692 this.sb.append("DELETE FROM " + table + " "); 693 } 694 695 private Delete(Delete other) { 696 this.table = other.table; 697 this.condition = other.condition; 698 this.sb.append(other.sb); 699 this.values.addAll(other.values); 700 } 701 702 /** 703 * Set the where clause for DELETE 704 * 705 * @param condition condition for where clause 706 * @return <code>Delete</code> for cascading 707 */ 708 public Delete where(Condition condition) { 709 Delete retVal = new Delete(this); 710 retVal.condition = condition; 711 retVal.values.addAll(condition.values); 712 return retVal; 713 } 714 715 /** 716 * Return the DELETE Statement 717 */ 718 public String toString() { 719 return sb.toString() + ((condition != null) ? "WHERE " + condition.toString() : ""); 720 } 721 } 722 723 /** 724 * UPDATE SQL Statement generator 725 */ 726 public static class Update extends SqlStatement { 727 Condition condition; 728 final Table table; 729 730 Update(Table table) { 731 this.table = table; 732 this.sb.append("UPDATE " + table + " SET "); 733 } 734 735 private Update(Update other) { 736 this.table = other.table; 737 this.condition = other.condition; 738 this.sb.append(other.sb); 739 this.values.addAll(other.values); 740 } 741 742 /** 743 * SET clause for update statement 744 * 745 * @param column column name 746 * @param value A temporary place holder which can be replaced while preparing 747 * @return <code>Update</code> for cascading 748 */ 749 public Update set(Column column, Object value) { 750 Update retVal = new Update(this); 751 retVal.sb.append((values.isEmpty() ? "" : ", ") + column + " = ? "); 752 retVal.values.add(value); 753 return retVal; 754 } 755 756 /** 757 * Set condition for updating 758 * 759 * @param condition condition for where clause 760 * @return <code>Update</code> for cascading 761 */ 762 public Update where(Condition condition) { 763 Update retVal = new Update(this); 764 retVal.condition = condition; 765 retVal.values.addAll(condition.values); 766 return retVal; 767 } 768 769 /** 770 * Return the UPDATE statement 771 */ 772 public String toString() { 773 return sb.toString() + ((condition != null) ? " WHERE " + condition.toString() : ""); 774 } 775 } 776 777 /** 778 * INSERT Statement generator 779 */ 780 public static class Insert extends SqlStatement { 781 StringBuilder sbCol = new StringBuilder(""); 782 StringBuilder sbVal = new StringBuilder(""); 783 boolean isFirst = true; 784 final Table table; 785 786 Insert(Table table) { 787 this.table = table; 788 this.sbCol.append("INSERT INTO " + table + " ( )"); 789 this.sbVal.append("VALUES ( )"); 790 } 791 792 private Insert(Insert other) { 793 this.table = other.table; 794 this.sbCol.append(other.sbCol); 795 this.sbVal.append(other.sbVal); 796 this.values.addAll(other.values); 797 if (other.isFirst) { 798 this.isFirst = false; 799 } 800 } 801 802 /** 803 * Set the VALUES that are to be inserted 804 * 805 * @param column 806 * @param value A temporary place holder which will be replaced while preparing 807 * @return 808 */ 809 public Insert value(Column column, Object value) { 810 Insert retVal = new Insert(this); 811 retVal.sbCol.setLength(retVal.sbCol.length() - 1); 812 retVal.sbVal.setLength(retVal.sbVal.length() - 1); 813 retVal.values.add(value); 814 retVal.sbCol.append(((isFirst) ? "" : ", ") + column + " )"); 815 retVal.sbVal.append(((isFirst) ? "" : ", ") + "? )"); 816 retVal.isFirst = false; 817 return retVal; 818 } 819 820 /** 821 * Return the INSERT Statement 822 */ 823 public String toString() { 824 return sbCol.toString() + " " + sbVal.toString(); 825 } 826 } 827 828 /** 829 * Prepare the SQL Statement that is generated and assign the values to prepared statement. setValues should be 830 * called to set the Real Values for place holders 831 * 832 * @param conn Connection 833 * @return Prepared SQL Statement 834 * @throws SQLException 835 */ 836 public PreparedStatement prepareAndSetValues(Connection conn) throws SQLException { 837 String stmt = toString(); 838 if (forUpdate && !Schema.isHsqlConnection(conn)) { 839 stmt += " FOR UPDATE"; 840 } 841 PreparedStatement pStmt = conn.prepareStatement(stmt); 842 int i = 1; 843 for (Object value : this.values) { 844 pStmt.setObject(i, value); 845 i++; 846 } 847 log.trace(XLog.Info.get().createPrefix() + " Preparing : " + stmt); 848 log.trace(XLog.Info.get().createPrefix() + " Values : " + values); 849 return pStmt; 850 } 851 852 /** 853 * Assign the values to Prepared Statement. setValues should be called to set the Real Values for place holders 854 * 855 * @param pStmt Prepared Statement 856 * @return PreparedStatement with values set 857 * @throws SQLException 858 */ 859 public PreparedStatement prepare(PreparedStatement pStmt) throws SQLException { 860 int i = 1; 861 pStmt.clearParameters(); 862 for (Object value : this.values) { 863 pStmt.setObject(i, value); 864 i++; 865 } 866 return pStmt; 867 } 868 869 /** 870 * Prepare the SQL Statement. Doesn't set the values. 871 * 872 * @param conn Connection 873 * @return PreparedStatement 874 * @throws SQLException 875 */ 876 public PreparedStatement prepare(Connection conn) throws SQLException { 877 String stmt = toString(); 878 if (forUpdate && !Schema.isHsqlConnection(conn)) { 879 stmt += " FOR UPDATE"; 880 } 881 return conn.prepareStatement(stmt); 882 } 883 884 /** 885 * Preparing Multiple statements for batch execution. 886 * 887 * @param conn Connection 888 * @param values A list of maps that contains the actual values 889 * @return Prepared Statement 890 * @throws SQLException 891 */ 892 public PreparedStatement prepareForBatch(Connection conn, List<? extends Map<Object, Object>> values, 893 PreparedStatement pStmt) throws SQLException { 894 String stmt = toString(); 895 if (forUpdate && !Schema.isHsqlConnection(conn)) { 896 stmt += " FOR UPDATE"; 897 } 898 // PreparedStatement pStmt = conn.prepareStatement(stmt); 899 for (Map<Object, Object> map : values) { 900 getNewStatementWithValues(map).prepare(pStmt); 901 pStmt.addBatch(); 902 } 903 return pStmt; 904 } 905 906 /** 907 * Replace the place holders with actual values in the sql statement 908 * 909 * @param oldVal Place holder 910 * @param newVal Actual Value 911 * @return SQL Statement with oldVal(place holder) replaced with newVal(actual value) 912 */ 913 public SqlStatement setValue(Object oldVal, Object newVal) { 914 ArrayList<Object> temp = new ArrayList<Object>(values); 915 if (values.contains(oldVal)) { 916 int i = temp.indexOf(oldVal); 917 temp.set(i, newVal); 918 } 919 SqlStatement retVal = create(temp); 920 return retVal; 921 } 922 923 /** 924 * Replace the keys(newValues) which are place holders in the sql statements with the corresponding new values. And 925 * Gives back a new SQL Statement so that the actual statement can be re-used 926 * 927 * @param newValues 928 * @return A New SQL Statement object with actual values set in its member 929 */ 930 public SqlStatement getNewStatementWithValues(Map<Object, Object> newValues) { 931 ArrayList<Object> temp = new ArrayList<Object>(); 932 for (Object value : values) { 933 if (newValues.containsKey(value)) { 934 temp.add(newValues.get(value)); 935 } 936 else { 937 temp.add(value); 938 } 939 } 940 SqlStatement retVal = create(temp); 941 return retVal; 942 } 943 944 /** 945 * Create the Appropriate SQL Statement with the given values 946 * 947 * @param temp 948 * @return 949 */ 950 private SqlStatement create(ArrayList<Object> temp) { 951 SqlStatement retVal = null; 952 if (this instanceof Select) { 953 retVal = new Select((Select) this); 954 } 955 else { 956 if (this instanceof Insert) { 957 retVal = new Insert((Insert) this); 958 } 959 else { 960 if (this instanceof Update) { 961 retVal = new Update((Update) this); 962 } 963 else { 964 if (this instanceof Delete) { 965 retVal = new Delete((Delete) this); 966 } 967 } 968 } 969 } 970 retVal.values.clear(); 971 retVal.values.addAll(temp); 972 return retVal; 973 } 974 975 /** 976 * Create the <code>ResultSetReader</code> object that has the methods to access the data from the result set 977 * 978 * @param rSet Result Set 979 * @return ResultSet Reader 980 */ 981 public static ResultSetReader parse(ResultSet rSet) { 982 return new ResultSetReader(rSet); 983 } 984 985 /** 986 * Return a new Insert Statement 987 * 988 * @param table 989 * @return Insert statement 990 */ 991 public static Insert insertInto(Table table) { 992 return new Insert(table); 993 } 994 995 /** 996 * Return a new Update Statement 997 * 998 * @param table 999 * @return Update statement 1000 */ 1001 public static Update update(Table table) { 1002 return new Update(table); 1003 } 1004 1005 /** 1006 * Return a new Delete Statement 1007 * 1008 * @param table 1009 * @return Delete Statement 1010 */ 1011 public static Delete deleteFrom(Table table) { 1012 return new Delete(table); 1013 } 1014 1015 /** 1016 * Return a Select All Statement 1017 * 1018 * @param tables 1019 * @return Select * statement 1020 */ 1021 public static Select selectAllFrom(Table... tables) { 1022 return new Select(false, tables); 1023 } 1024 1025 /** 1026 * Return a Select Statement 1027 * 1028 * @param columns columns to select 1029 * @return select statement 1030 */ 1031 public static Select selectColumns(Column... columns) { 1032 return new Select(columns); 1033 } 1034 1035 /** 1036 * Select count(*) Statement generator. 1037 * 1038 * @param tables 1039 * @return "select count(*) from tables" statement 1040 */ 1041 public static Select getCount(Table... tables) { 1042 return new Select(true, tables); 1043 } 1044 }