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