001    package hep.aida.ref.sql;
002    
003    // FreeHEP
004    import hep.aida.ref.tuple.AbstractTuple;
005    import hep.aida.ref.tuple.TupleColumn;
006    import hep.aida.ref.tuple.FTupleColumn;
007    import hep.aida.ref.tuple.FTupleCursor;
008    import org.freehep.util.Value;
009    
010    // Log4J
011    import org.apache.log4j.Logger;
012    
013    // AIDA
014    import hep.aida.ITuple;
015    import hep.aida.IBaseTupleColumn;
016    import hep.aida.ICloud1D;
017    import hep.aida.ICloud2D;
018    import hep.aida.ICloud3D;
019    import hep.aida.IHistogram1D;
020    import hep.aida.IHistogram2D;
021    import hep.aida.IHistogram3D;
022    import hep.aida.IProfile1D;
023    import hep.aida.IProfile2D;
024    import hep.aida.IEvaluator;
025    import hep.aida.IFilter;
026    
027    // SQL
028    import java.sql.PreparedStatement;
029    import java.sql.ResultSet;
030    import java.sql.ResultSetMetaData;
031    import java.sql.SQLException;
032    
033    // Java
034    import java.util.Collection;
035    import java.util.ArrayList;
036    import java.lang.reflect.Constructor;
037    import java.lang.reflect.InvocationTargetException;
038    
039    /** <code>SQLTuple</code> is an extension of {@link ITuple}
040      * for SQL database.
041      * <br>
042      * <code>SQLTuple</code> contains several extensions to {@link ITuple}
043      * and {@link ITuple}:
044      * <ul>
045      * <li><code>void addIndex(String[] columnName);</code></li>
046      * <li><code>void addColumn(String columnName, Class columnType, IEvaluator evaluator);</code></li>
047      * <li><code>void start(IFilter filter);</code></li>
048      * <li><code>void start(String[] columns);</code></li>
049      * <li><code>void start(IFilter filter, String[] columns);</code></li>
050      * <li><code>void start(String stmtSrc);</code></li>
051      * <li><code>void start(IFilter filter, String stmtSrc);</code></li>
052      * <li><code>String[] getRowData();</code></li>
053      * <li><code>boolean getBoolean(String column);</code></li>
054      * <li><code>byte getByte(String column);</code></li>
055      * <li><code>char getChar(String column);</code></li>
056      * <li><code>short getShort(String column);</code></li>
057      * <li><code>int getInt(String column);</code></li>
058      * <li><code>long getLong(String column);</code></li>
059      * <li><code>float getFloat(String column);</code></li>
060      * <li><code>double getDouble(String column);</code></li>
061      * <li><code>String getString(String column);</code></li>
062      * <li><code>Object getObject(String column);</code></li>
063      * <li><code>ITuple getTuple(String column);</code></li>
064      * <li><code>void fill(String column, boolean value);</code></li>
065      * <li><code>void fill(String column, byte value);</code></li>
066      * <li><code>void fill(String column, char value);</code></li>
067      * <li><code>void fill(String column, short value);</code></li>
068      * <li><code>void fill(String column, int value);</code></li>
069      * <li><code>void fill(String column, long value);</code></li>
070      * <li><code>void fill(String column, float value);</code></li>
071      * <li><code>void fill(String column, double value);</code></li>
072      * <li><code>void fill(String column, String value);</code></li>
073      * <li><code>void fill(String column, Object value);</code></li>
074      * <li><code>void fill(String column, ITuple value);</code></li>
075      * <li><code>double groupValue(String operator, int column);</code></li>
076      * <li><code>String columnDefault(int param);</code></li>
077      * <li><code>String[] columnDefaults();</code></li>
078      * <li><code>Collection<String> getColumn(String cName);</code></li>
079      * <li><code>&lt;T&gt; Collection&lt;T&gt; getColumn(String cName, Class&lt;T&gt; cl);</code></li>
080      * <li><code>Collection<String> getColumn(String cName, IFilter filter);</code></li>
081      * <li><code>&lt;T&gt; Collection&lt;T&gt; getColumn(String cName, Class&lt;T&gt; cl, IFilter filter);</code></li>
082      * </ul>
083      * <p><font color="#880088">
084      * <pre>
085      * $Log: SQLTuple.java,v $
086      * Revision 1.82  2007/05/23 16:38:44  hrivnac
087      * logical connections for Plotter; better UML
088      *
089      * Revision 1.81  2006/12/15 00:16:13  hrivnac
090      * FORWARD_ONLY allows to plot big ntuples
091      *
092      * Revision 1.80  2006/12/12 15:21:42  hrivnac
093      * McKoi replaced with Derby; uppercase-only dbs handled better; moving to JAS 0.8.3
094      *
095      * Revision 1.79  2006/11/22 23:55:36  hrivnac
096      * fixed non-double values, added intr database
097      *
098      * Revision 1.78  2006/11/20 16:56:08  hrivnac
099      * fixing input params for Plotter command line
100      *
101      * Revision 1.77  2006/11/17 17:11:34  hrivnac
102      * chooser.jsp closes tree too
103      *
104      * Revision 1.76  2006/11/15 16:16:01  hrivnac
105      * Oracle work fine in CERN, cache enabled
106      *
107      * Revision 1.75  2006/11/14 16:06:18  hrivnac
108      * improving Web Service
109      *
110      * Revision 1.74  2006/10/12 15:02:58  hrivnac
111      * bug fixes
112      *
113      * Revision 1.73  2005/09/28 18:22:42  hrivnac
114      * javadoc fixed
115      *
116      * Revision 1.72  2005/09/28 16:21:06  hrivnac
117      * code cleaning
118      *
119      * Revision 1.71  2005/09/21 23:00:38  hrivnac
120      * readonly tuples can be read
121      *
122      * Revision 1.70  2005/09/21 14:49:49  hrivnac
123      * better support for Oracle types
124      *
125      * Revision 1.69  2005/09/19 14:30:12  hrivnac
126      * projection bugs fixed
127      *
128      * Revision 1.68  2005/09/02 14:10:31  hrivnac
129      * moved to JAS3 0.8.2
130      *
131      * Revision 1.67  2005/06/15 15:26:04  hrivnac
132      * ITuple._rows only evaluated when requested
133      *
134      * Revision 1.66  2005/03/18 12:12:11  hrivnac
135      * ITuple.start() resets ITuple to its original shape even after customised ITuple.start(...) calls
136      *
137      * Revision 1.65  2005/03/09 15:25:52  hrivnac
138      * ITuple.rows() improved
139      *
140      * Revision 1.64  2005/03/08 17:05:51  hrivnac
141      * ...
142      *
143      * Revision 1.63  2005/02/10 20:07:51  hrivnac
144      * bug fixes to support new ColMan
145      *
146      * Revision 1.62  2005/01/27 17:30:41  hrivnac
147      * PreparedStatement with default values
148      *
149      * Revision 1.61  2005/01/25 16:45:03  hrivnac
150      * Adding rows uses PreparedStatement
151      *
152      * Revision 1.60  2004/12/01 16:07:15  hrivnac
153      * better support for ColMan JAS3 plugin
154      *
155      * Revision 1.59  2004/11/30 14:06:04  hrivnac
156      * SQLTuple.rows() fix
157      *
158      * Revision 1.58  2004/10/29 22:27:25  hrivnac
159      * imports corrected
160      *
161      * Revision 1.57  2004/10/21 15:46:49  hrivnac
162      * doc improved
163      *
164      * Revision 1.56  2004/10/20 23:02:29  hrivnac
165      * Types mapping simplified
166      *
167      * Revision 1.55  2004/10/13 12:25:39  hrivnac
168      * defaults work fine
169      *
170      * Revision 1.54  2004/10/13 09:21:21  hrivnac
171      * defaults used
172      *
173      * Revision 1.53  2004/10/12 13:25:40  hrivnac
174      * small improvements
175      *
176      * Revision 1.52  2004/10/08 15:22:33  hrivnac
177      * JAS3 plugin works
178      *
179      * Revision 1.51  2004/07/06 14:24:50  hrivnac
180      * support for Oracle
181      *
182      * Revision 1.50  2004/06/30 13:01:05  hrivnac
183      * oracle sceleton
184      *
185      * Revision 1.49  2004/06/23 08:04:53  hrivnac
186      * documentation fixes
187      *
188      * Revision 1.48  2004/06/18 09:17:31  hrivnac
189      * StmtSrc can be accessed directkly
190      *
191      * Revision 1.47  2004/06/16 21:56:43  hrivnac
192      * StringBuffer in SQLTuple.addRow() -> speed
193      *
194      * Revision 1.46  2004/05/22 15:12:59  hrivnac
195      * class id reformated
196      *
197      * Revision 1.45  2004/05/04 08:50:33  hrivnac
198      * can run with JAS3
199      *
200      * Revision 1.44  2004/05/03 19:22:30  hrivnac
201      * basic support for JAS3
202      *
203      * Revision 1.43  2004/04/21 13:41:32  hrivnac
204      * explicit dependency on MySQL removed
205      *
206      * Revision 1.42  2004/04/21 08:24:50  hrivnac
207      * some explicit MySQL dependencies removed
208      *
209      * Revision 1.41  2004/04/20 12:46:49  hrivnac
210      * tuples use always primitive types
211      *
212      * Revision 1.40  2004/04/15 08:49:01  hrivnac
213      * ColMan fixes
214      *
215      * Revision 1.39  2004/04/14 13:54:41  hrivnac
216      * potential bugs fixed
217      *
218      * Revision 1.38  2004/04/14 13:39:47  hrivnac
219      * 1.5 warnings fixed
220      *
221      * Revision 1.37  2004/04/13 15:45:54  hrivnac
222      * AIDA URL introduced
223      *
224      * Revision 1.36  2004/02/10 14:50:58  hrivnac
225      * JavaDoc tags completed
226      *
227      * Revision 1.35  2004/02/04 13:30:39  hrivnac
228      * - improvement of Enums internal mapping
229      * - general cleaning
230      *
231      * Revision 1.34  2003/11/24 15:13:22  hrivnac
232      * Logging improved.
233      *
234      * Revision 1.33  2003/11/20 17:21:58  hrivnac
235      * Java 1.5 natively supported, Log4J reporting improved.
236      *
237      * Revision 1.32  2003/11/17 15:01:12  hrivnac
238      * More BM results.
239      *
240      * Revision 1.31  2003/11/17 10:18:29  hrivnac
241      * Cleaning.
242      *
243      * Revision 1.30  2003/11/13 18:19:38  hrivnac
244      * BenchMarks running for all DBs, Reporting class added.
245      *
246      * Revision 1.29  2003/11/13 15:43:08  hrivnac
247      * BenchMarking introduced.
248      *
249      * Revision 1.28  2003/11/13 11:07:31  hrivnac
250      * EventSelector prototype added.
251      *
252      * Revision 1.27  2003/11/05 19:46:22  hrivnac
253      * - FreeHEP 1.2.1
254      * - JAIDA 3.2.1
255      *
256      * Revision 1.18  2003/10/30 11:42:40  hrivnac
257      * ArrayList -> Collection
258      *
259      * Revision 1.15  2003/10/22 17:59:39  hrivnac
260      * Refactored.
261      *
262      * Revision 1.13  2003/10/21 13:56:00  hrivnac
263      * Default values supported.
264      *
265      * Revision 1.12  2003/10/21 13:24:52  hrivnac
266      * Constructor from columnString implemented.
267      *
268      * Revision 1.11  2003/10/10 10:12:21  hrivnac
269      * All three testing pgms work.
270      *
271      * Revision 1.8  2003/10/07 10:15:57  hrivnac
272      * SQL extensions to ITuple added.
273      *
274      * Revision 1.5  2003/10/03 16:02:21  hrivnac
275      * Better handling of multiple technologies.
276      *
277      * Revision 1.3  2003/10/02 14:24:01  hrivnac
278      * Cleaning.
279      *
280      * Revision 1.7  2003/09/30 20:30:47  hrivnac
281      * special Pool functions
282      *
283      * Revision 1.6  2003/09/30 16:46:02  hrivnac
284      * - Writing test in TestWrite
285      * - SQLTuple projections supported
286      *
287      * Revision 1.5  2003/09/30 14:11:48  hrivnac
288      * Can created SQLTuples.
289      *
290      * Revision 1.4  2003/09/30 12:29:19  hrivnac
291      * Tuples can be written.
292      *
293      * Revision 1.3  2003/09/29 16:15:54  hrivnac
294      * More complete.
295      *
296      * Revision 1.2  2003/09/29 14:36:40  hrivnac
297      * Works per attribute.
298      *
299      * </pre>
300      * </font></p>
301      * @opt attributes
302      * @opt operations
303      * @opt types
304      * @opt visibility
305      * @version $Id: SQLTuple.java,v 1.82 2007/05/23 16:38:44 hrivnac Exp $
306      * @author <a href="mailto:Julius.Hrivnac@cern.ch">J.Hrivnac</a> */
307    public class SQLTuple extends AbstractTuple {
308    
309      /** Just call superclass constructor.
310        * @param name       The name of the ITuple.
311        * @param title      The title of the ITuple.
312        * @param columnName The names of columns.
313        * @param columnType The types of columns. 
314        * @param options    The options to be used to create the ITuple. */
315      public SQLTuple(String name,
316                      String title,
317                      String[] columnName,
318                      Class[] columnType,
319                      String options) {
320        super(name, title, options);
321        initSQLTuple(name, title, columnName, columnType, options);
322        }
323    
324      /** Just calls superclass constructor.
325        * @param name          The name of the ITuple.
326        * @param title         The title of the ITuple.
327        * @param columnsString The columns definition.
328        * @param options       The options to be used to create the ITuple. */
329      public SQLTuple(String name,
330                      String title,
331                      String columnsString,
332                      String options) {
333        super(name, title, options);
334        initSQLTuple(name, title, super.columnNames(), super.columnTypes(), options);
335        }
336    
337      /** Initialise internal variables. Is called from the constructor.
338        * @param name          The name of the ITuple.
339        * @param title         The title of the ITuple.
340        * @param columnName    The names of columns.
341        * @param columnType    The types of columns.
342        * @param options       The options to be used to create the ITuple.
343        * @throws IllegalArgumentException if the ITuple can't be created. */
344      protected void initSQLTuple(String name,
345                                  String title,
346                                  String[] columnName,
347                                  Class[] columnType,
348                                  String options) throws IllegalArgumentException {
349        try {
350          setOptions(options);
351          _names = columnName;
352          _types = columnType;
353          _defaults       = new String[ _names.length];
354          _defaultObjects = new Object[ _names.length];
355          _filled         = new boolean[_names.length];
356          int eq;
357          for (int i = 0; i < _names.length; i++) {
358            _defaults[i] = null;
359            eq = columnName[i].indexOf("=");
360            if (eq > -1) {
361              _defaults[i]       = _names[i].substring(eq + 1    ).trim();
362              _names[i]          = _names[i].substring(0     , eq).trim();
363              _defaultObjects[i] = type2Object(_defaults[i], _types[i]);
364              }
365            }
366          _namesOrig          = _names;
367          _typesOrig          = _types;
368          _defaultsOrig       = _defaults;
369          _defaultObjectsOrig = _defaultObjects;
370          _stmtSrc = new StmtSrc(_accessor, title);
371          prepare();
372          _rows = -1;
373          }
374        catch (SQLTupleException e) {
375          throw new IllegalArgumentException("Can't initialise SQLTuple " + name + " / " + title, e);
376          }
377    
378        }
379    
380      /** <code>SQLTuple</code> extension: add indexes into SQL table.
381        * @param columnName The array of column names to be indexed. */
382      public void addIndex(String[] columnName) {
383        for (String name : columnName) {
384          String[] args = {"index_" + title() + "_" + name, name};
385          update("addIndex", args);
386          }
387        }
388    
389      /** <code>SQLTuple</code> extension: add column into SQL table.
390        * @param columnName The name of column to be added.
391        * @param columnType The type of column to be added.
392        * @param evaluator  The evaluator to be used to compute new column values. */
393      public void addColumn(String columnName,
394                            Class columnType,
395                            IEvaluator evaluator) {
396        // Check whether it is a new column
397        for (int i = 0; i < columns(); i++) {
398          if (columnName.equals(_names[i])) {
399            log.warn("Column " + columnName + " already exists");
400            return;
401            }
402          }
403        // Add column into table
404        String[] args1 = {columnName, _accessor.sqlName(columnType)};
405        update("addColumnAlter", args1);
406        // Fill table with values
407        String[] args2 = {columnName, evaluator.expression()};
408        update("addColumnUpdate", args2);
409        // Update internal variables
410        String[] names0          = new String[columns() + 1];
411        String[] defaults0       = new String[columns() + 1];
412        Object[] defaultObjects0 = new Object[columns() + 1];
413        Class[]  types0          = new Class[ columns() + 1];
414        _filled = new boolean[columns() + 1];
415        for (int i = 0; i < columns(); i++) {
416          names0[   i]       = _names[         i];
417          defaults0[i]       = _defaults[      i];
418          defaultObjects0[i] = _defaultObjects[i];
419          types0[   i]       = _types[         i];
420          }
421        names0[   columns()]       = columnName;
422        defaults0[columns()]       = null;
423        defaultObjects0[columns()] = type2Object(null, columnType);
424        types0[   columns()]       = columnType;
425        _names          = names0;
426        _defaults       = defaults0;
427        _defaultObjects = defaultObjects0;
428        _types          = types0;
429        for (int i = 0; i < columns(); i++) {
430          _filled[i] = false;;
431          }
432        }
433    
434      /** <code>SQLTuple</code> is never in memory => false.
435        * @return <code>false</code>. */
436      public boolean isInMemory() {
437        return false;
438        }
439    
440      /** Use SQL <code>min<code> function.
441        * @param column The column to get the minimum of.
442        * @return       The found minimum. */
443      public double columnMin(int column) {
444        return groupValue("min", column);
445        }
446    
447      /** Use SQL <code>max<code> function.
448        * @param column The column to get the maximum of.
449        * @return       The found maximum. */
450      public double columnMax(int column) {
451        return groupValue("max", column);
452        }
453    
454      /** Use SQL <code>avg<code> function.
455        * @param column The column to get the average of.
456        * @return       The found average. */
457      public double columnMean(int column) {
458        return groupValue("avg", column);
459        }
460    
461      /** Use SQL <code>std<code> function.
462        * @param column The column to get the std of.
463        * @return       The found std. */
464      public double columnRms(int column) {
465        return groupValue("std", column);
466        }
467    
468      /** Apply an operator to a column.
469        * @param operator The operator to be applied..
470        * @param column   The column to be evalated.
471        * @return         The found result of the operator applied on the column.
472        * @throws IllegalArgumentException if the operator can't be applied on the column. */
473      private double groupValue(String operator, int column) {
474        String[] args = {operator, columnName(column)};
475        ResultSet rs = query("groupValue", args);
476        try {
477          rs.next();
478          }
479        catch (SQLException e) {
480          log.error(Util.report("Can't perform operation " + operator + " on column " + column, e), e);
481          throw new IllegalArgumentException("Couldn't perform operation " + operator + " on column " + column, e);
482          }
483        return getDouble(rs, 1);
484        }
485    
486      /** Apply an operator to a column.
487        * @param operator The operator to be applied..
488        * @param column   The column formula to be evalated.
489        * @return         The found result of the operator applied on the column.
490        * @throws IllegalArgumentException if the operator can't be applied on the column. */
491      public double groupValue(String operator, String column) {
492        String[] args = {operator, column};
493        ResultSet rs = query("groupValue", args);
494        try {
495          rs.next();
496          }
497        catch (SQLException e) {
498          log.error(Util.report("Can't perform operation " + operator + " on formula " + column, e), e);
499          throw new IllegalArgumentException("Couldn't perform operation " + operator + " on formula " + column, e);
500          }
501        return getDouble(rs, 1);
502        }
503    
504      /** Find column number from the column name.
505        * @param name The name of the column.
506        * @return     The number of the specified column.
507        * @throws IllegalArgumentException if no column of that name exists. */
508      public int findColumn(String name) throws IllegalArgumentException {
509        if (_accessor.supportsOnlyUpperCase()) {
510          name = name.toUpperCase();
511          }
512        for (int i = 0; i < _names.length; i++) {
513          if (_names[i].equals(name)) {
514            return i;
515            }
516          }
517        throw new IllegalArgumentException("There is no column " + name);
518        }
519    
520      /** Get boolean value of a column.
521        * @param  column The column name.
522        * @return        The value of the current row. */
523      public boolean getBoolean(String column) {
524        return getBoolean(findColumn(column));
525        }
526    
527      /** Get boolean value of a column.
528        * @param  column The column number.
529        * @return        The value of the current row. */
530      public boolean getBoolean(int column) {
531        try {
532          return _rs.getBoolean(column+1);
533                }
534              catch (SQLException e) {
535          log.error(Util.report("Can't get boolean of column " + column + ", return default", e), e);
536          }
537        return Boolean.parseBoolean(_defaults[column]);
538        }
539    
540      /** Get byte value of a column.
541        * @param  column The column name.
542        * @return        The value of the current row. */
543      public byte getByte(String column) {
544        return getByte(findColumn(column));
545        }
546    
547      /** Get byte value of a column.
548        * @param  column The column number.
549        * @return        The value of the current row. */
550      public byte getByte(int column) {
551        try {
552          return _rs.getByte(column+1);
553                }
554              catch (SQLException e) {
555          log.error(Util.report("Can't get byte of column " + column + ", return default", e), e);
556          }
557        return Byte.parseByte(_defaults[column]);
558        }
559    
560      /** Get char value of a column.
561        * @param  column The column name.
562        * @return        The value of the current row. */
563      public char getChar(String column) {
564        return getChar(findColumn(column));
565        }
566    
567      /** Get char value of a column.
568        * @param  column The column number.
569        * @return        The value of the current row. */
570      public char getChar(int column) {
571        try {
572          return _rs.getString(column+1).charAt(0);
573                }
574              catch (SQLException e) {
575          log.error(Util.report("Can't get char of column " + column + ", return default", e), e);
576          }
577        return _defaults[column].toCharArray()[0];
578        }
579    
580      /** Get double value of a column.
581        * @param  column The column name.
582        * @return        The value of the current row. */
583      public double getDouble(String column) {
584        return getDouble(findColumn(column));
585        }
586    
587      /** Get double value of a column.
588        * @param  column The column number.
589        * @return        The value of the current row. */
590      public double getDouble(int column) {
591        try {
592          return _rs.getDouble(column+1);
593                }
594              catch (SQLException e) {
595          log.error(Util.report("Can't get double of column " + column + ", return default", e), e);
596          }
597        return Double.parseDouble(_defaults[column]);
598        }
599    
600      /** Get float value of a column.
601        * @param  column The column name.
602        * @return        The value of the current row. */
603      public float getFloat(String column) {
604        return getFloat(findColumn(column));
605        }
606    
607      /** Get float value of a column.
608        * @param  column The column number.
609        * @return        The value of the current row. */
610      public float getFloat(int column) {
611        try {
612          return _rs.getFloat(column+1);
613                }
614              catch (SQLException e) {
615          log.error(Util.report("Can't get double of column " + column + ", return default", e), e);
616          }
617        return Float.parseFloat(_defaults[column]);
618        }
619    
620      /** Get int value of a column.
621        * @param  column The column name.
622        * @return        The value of the current row. */
623      public int getInt(String column) {
624        return getInt(findColumn(column));
625        }
626    
627      /** Get int value of a column.
628        * @param  column The column number.
629        * @return        The value of the current row. */
630      public int getInt(int column) {
631        try {
632          return _rs.getInt(column+1);
633                }
634              catch (SQLException e) {
635          log.error(Util.report("Can't get int of column " + column + ", return default", e), e);
636          }
637        return Integer.parseInt(_defaults[column]);
638        }
639    
640      /** Get long value of a column.
641        * @param  column The column name.
642        * @return        The value of the current row. */
643      public long getLong(String column) {
644        return getLong(findColumn(column));
645        }
646    
647      /** Get long value of a column.
648        * @param  column The column number.
649        * @return        The value of the current row. */
650      public long getLong(int column) {
651        try {
652          return _rs.getLong(column+1);
653                }
654              catch (SQLException e) {
655          log.error(Util.report("Can't get long of column " + column + ", return default", e), e);
656          }
657        return Long.parseLong(_defaults[column]);
658        }
659    
660      /** Get Object value of a column.
661        * @param  column The column name.
662        * @return        The value of the current row. */
663      public Object getObject(String column) {
664        return getObject(findColumn(column));
665        }
666    
667      /** Get Object value of a column.
668        * @param  column The column number.
669        * @return        The value of the current row. */
670      public Object getObject(int column) {
671        try {
672          return _rs.getObject(column+1);
673                }
674              catch (SQLException e) {
675          log.error(Util.report("Can't get Object of column " + column + ", return default String", e), e);
676          }
677        return _defaults[column];
678        }
679    
680      /** Get short value of a column.
681        * @param  column The column name.
682        * @return        The value of the current row. */
683      public short getShort(String column) {
684        return getShort(findColumn(column));
685        }
686    
687      /** Get short value of a column.
688        * @param  column The column number.
689        * @return        The value of the current row. */
690      public short getShort(int column) {
691        try {
692          return _rs.getShort(column+1);
693                }
694              catch (SQLException e) {
695          log.error(Util.report("Can't get short of column " + column + ", return default", e), e);
696          }
697        return Short.parseShort(_defaults[column]);
698        }
699    
700      /** Get String value of a column.
701        * @param  column The column name.
702        * @return        The value of the current row. */
703      public String getString(String column) {
704        return getString(findColumn(column));
705        }
706    
707      /** Get String value of a column.
708        * @param  column The column number.
709        * @return        The value of the current row. */
710      public String getString(int column) {
711        try {
712          return _rs.getString(column+1);
713                }
714              catch (SQLException e) {
715          log.error(Util.report("Can't get String of column " + column + ", return default", e), e);
716          }
717        return _defaults[column];
718        }
719    
720      /** Get ITuple value of a column.
721        * @param  column The column name.
722        * @return        The value of the current row. */
723      public ITuple getTuple(String column) {
724        return getTuple(findColumn(column));
725        }
726    
727      /** Fill {@link Value} in a column.
728        * @param column The column name. 
729        * @param value  The {@link Value} to be filled in the current row. 
730        * @throws IllegalArgumentException if {@link Value} can't be filled. */
731      public void fill(int column, Value value) throws IllegalArgumentException {
732        if (_readOnly) {
733          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
734          }
735        try {
736          _statement.setString(column+1, value.getString());
737          }
738        catch (SQLException e) {
739          log.error(Util.report("Can't set column " + column + " to value " + value, e), e);
740          throw new IllegalArgumentException("Couldn't column " + column + " to value " + value, e);
741          }
742        _filled[column] = true;
743        }
744    
745      /** Fill int value in a column.
746        * @param column The column name. 
747        * @param value  The value to be filled in the current row. 
748        * @throws IllegalArgumentException if value can't be filled. */
749      public void fill(String column, int value) throws IllegalArgumentException {
750        fill(findColumn(column), value);
751        }
752    
753      /** Fill int value in a column.
754        * @param column The column number. 
755        * @param value  The value to be filled in the current row.
756        * @throws IllegalArgumentException if value can't be filled. */
757      public void fill(int column, int value) throws IllegalArgumentException {
758        if (_readOnly) {
759          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
760          }
761        try {
762          _statement.setInt(column+1, value);
763          }
764        catch (SQLException e) {
765          log.error(Util.report("Can't set column " + column + " to int value " + value, e), e);
766          throw new IllegalArgumentException("Couldn't column " + column + " to int value " + value, e);
767          }
768        _filled[column] = true;
769        }
770    
771      /** Fill short value in a column.
772        * @param column The column name.
773        * @param value  The value to be filled in the current row.
774        * @throws IllegalArgumentException if value can't be filled. */
775      public void fill(String column, short value) throws IllegalArgumentException {
776        fill(findColumn(column), value);
777        }
778    
779      /** Fill short value in a column.
780        * @param column The column number.
781        * @param value  The value to be filled in the current row.
782        * @throws IllegalArgumentException if value can't be filled. */
783      public void fill(int column, short value) throws IllegalArgumentException {
784        if (_readOnly) {
785          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
786          }
787        try {
788          _statement.setShort(column+1, value);
789          }
790        catch (SQLException e) {
791          log.error(Util.report("Can't set column " + column + " to short value " + value, e), e);
792          throw new IllegalArgumentException("Couldn't column " + column + " to short value " + value, e);
793          }
794        _filled[column] = true;
795        }
796    
797      /** Fill long value in a column.
798        * @param column The column name.
799        * @param value  The value to be filled in the current row.
800        * @throws IllegalArgumentException if value can't be filled. */
801      public void fill(String column, long value) throws IllegalArgumentException {
802        fill(findColumn(column), value);
803        }
804    
805      /** Fill long value in a column.
806        * @param column The column number.
807        * @param value  The value to be filled in the current row.
808        * @throws IllegalArgumentException if value can't be filled. */
809      public void fill(int column, long value) throws IllegalArgumentException {
810        if (_readOnly) {
811          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
812          }
813        try {
814          _statement.setLong(column+1, value);
815          }
816        catch (SQLException e) {
817          log.error(Util.report("Can't set column " + column + " to long value " + value, e), e);
818          throw new IllegalArgumentException("Couldn't column " + column + " to long value " + value, e);
819          }
820        _filled[column] = true;
821        }
822    
823      /** Fill double value in a column.
824        * @param column The column name.
825        * @param value  The value to be filled in the current row.
826        * @throws IllegalArgumentException if value can't be filled. */
827      public void fill(String column, double value) throws IllegalArgumentException {
828        fill(findColumn(column), value);
829        }
830    
831      /** Fill double value in a column.
832        * @param column The column number.
833        * @param value  The value to be filled in the current row.
834        * @throws IllegalArgumentException if value can't be filled. */
835      public void fill(int column, double value) throws IllegalArgumentException {
836        if (_readOnly) {
837          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
838          }
839        try {
840          _statement.setDouble(column+1, value);
841          }
842        catch (SQLException e) {
843          log.error(Util.report("Can't set column " + column + " to double value " + value, e), e);
844          throw new IllegalArgumentException("Couldn't column " + column + " to double value " + value, e);
845          }
846        _filled[column] = true;
847        }
848    
849      /** Fill float value in a column.
850        * @param column The column name.
851        * @param value  The value to be filled in the current row.
852        * @throws IllegalArgumentException if value can't be filled. */
853      public void fill(String column, float value) throws IllegalArgumentException {
854        fill(findColumn(column), value);
855        }
856    
857      /** Fill float value in a column.
858        * @param column The column number.
859        * @param value  The value to be filled in the current row.
860        * @throws IllegalArgumentException if value can't be filled. */
861      public void fill(int column, float value) throws IllegalArgumentException {
862        if (_readOnly) {
863          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
864          }
865        try {
866          _statement.setFloat(column+1, value);
867          }
868        catch (SQLException e) {
869          log.error(Util.report("Can't set column " + column + " to float value " + value, e), e);
870          throw new IllegalArgumentException("Couldn't column " + column + " to float value " + value, e);
871          }
872        _filled[column] = true;
873        }
874    
875      /** Fill boolean value in a column.
876        * @param column The column name.
877        * @param value  The value to be filled in the current row.
878        * @throws IllegalArgumentException if value can't be filled. */
879      public void fill(String column, boolean value) throws IllegalArgumentException {
880        fill(findColumn(column), value);
881        }
882    
883      /** Fill boolean value in a column.
884        * @param column The column number
885        * @param value  The value to be filled in the current row.
886        * @throws IllegalArgumentException if value can't be filled. */
887      public void fill(int column, boolean value) throws IllegalArgumentException {
888        if (_readOnly) {
889          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
890          }
891        try {
892          _statement.setBoolean(column+1, value);
893          }
894        catch (SQLException e) {
895          log.error(Util.report("Can't set column " + column + " to boolean value " + value, e), e);
896          throw new IllegalArgumentException("Couldn't column " + column + " to boolean value " + value, e);
897          }
898        _filled[column] = true;
899        }
900    
901      /** Fill byte value in a column.
902        * @param column The column name
903        * @param value  The value to be filled in the current row.
904        * @throws IllegalArgumentException if value can't be filled. */
905      public void fill(String column, byte value) throws IllegalArgumentException {
906        fill(findColumn(column), value);
907        }
908    
909      /** Fill byte value in a column.
910        * @param column The column number.
911        * @param value  The value to be filled in the current row.
912        * @throws IllegalArgumentException if value can't be filled. */
913      public void fill(int column, byte value) throws IllegalArgumentException {
914        if (_readOnly) {
915          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
916          }
917        try {
918          _statement.setByte(column+1, value);
919          }
920        catch (SQLException e) {
921          log.error(Util.report("Can't set column " + column + " to byte value " + value, e), e);
922          throw new IllegalArgumentException("Couldn't column " + column + " to byte value " + value, e);
923          }
924        _filled[column] = true;
925        }
926    
927      /** Fill char value in a column.
928        * @param column The column name.
929        * @param value  The value to be filled in the current row.
930        * @throws IllegalArgumentException if value can't be filled. */
931      public void fill(String column, char value) throws IllegalArgumentException {
932        fill(findColumn(column), value);
933        }
934    
935      /** Fill char value in a column.
936        * @param column The column number.
937        * @param value  The value to be filled in the current row.
938        * @throws IllegalArgumentException if value can't be filled. */
939      public void fill(int column, char value) throws IllegalArgumentException {
940        if (_readOnly) {
941          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
942          }
943        try {
944          _statement.setString(column+1, Character.toString(value));
945          }
946        catch (SQLException e) {
947          log.error(Util.report("Can't set column " + column + " to char value " + value, e), e);
948          throw new IllegalArgumentException("Couldn't column " + column + " to char value " + value, e);
949          }
950        _filled[column] = true;
951        }
952    
953      /** Fill String value in a column.
954        * @param column The column name.
955        * @param value  The value to be filled in the current row.
956        * @throws IllegalArgumentException if value can't be filled. */
957      public void fill(String column, String value) throws IllegalArgumentException {
958        fill(findColumn(column), value);
959        }
960    
961      /** Fill String value in a column.
962        * @param column The column number.
963        * @param value  The value to be filled in the current row.
964        * @throws IllegalArgumentException if value can't be filled. */
965      public void fill(int column, String value) throws IllegalArgumentException {
966        if (_readOnly) {
967          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
968          }
969        try {
970          _statement.setString(column+1, value);
971          }
972        catch (SQLException e) {
973          log.error(Util.report("Can't set column " + column + " to String value " + value, e), e);
974          throw new IllegalArgumentException("Couldn't column " + column + " to String value " + value, e);
975          }
976        _filled[column] = true;
977        }
978    
979      /** Fill Object value in a column.
980        * @param column The column name.
981        * @param value  The value to be filled in the current row.
982        * @throws IllegalArgumentException if value can't be filled. */
983      public void fill(String column, Object value) throws IllegalArgumentException {
984        fill(findColumn(column), value);
985        }
986    
987      /** Fill Object value in a column.
988        * @param column The column number.
989        * @param value  The value to be filled in the current row.
990        * @throws IllegalArgumentException if value can't be filled. */
991      public void fill(int column, Object value) throws IllegalArgumentException {
992        if (_readOnly) {
993          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
994          }
995        try {
996          _statement.setObject(column+1, value);
997          }
998        catch (SQLException e) {
999          log.error(Util.report("Can't set column " + column + " to Object value " + value, e), e);
1000          throw new IllegalArgumentException("Couldn't column " + column + " to Object value " + value, e);
1001          }
1002        _filled[column] = true;
1003        }
1004    
1005      /** Fill float values into current row.
1006        * @param values The values to be filled in the current row.
1007        * @throws IllegalArgumentException if value can't be filled. */
1008      public void fill(float[] values) throws IllegalArgumentException {
1009        if (_readOnly) {
1010          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
1011          }
1012        for (int i = 0; i < columns(); i++) {
1013          try {
1014            _statement.setFloat(i+1, values[i]);
1015          }
1016          catch (SQLException e) {
1017            log.error(Util.report("Can't set column " + i + " to float value " + values[i], e), e);
1018            throw new IllegalArgumentException("Couldn't column " + i + " to float value " + values[i], e);
1019            }
1020          _filled[i] = true;
1021          }
1022        }
1023    
1024      /** Fill double values into current row.
1025        * @param values The values to be filled in the current row.
1026        * @throws IllegalArgumentException if value can't be filled. */
1027      public void fill(double[] values) throws IllegalArgumentException {
1028        if (_readOnly) {
1029          throw new IllegalArgumentException("SQLTuple is readonly, can't be filled");
1030          }
1031        for (int i = 0; i < columns(); i++) {
1032          try {
1033            _statement.setDouble(i+1, values[i]);
1034          }
1035          catch (SQLException e) {
1036            log.error(Util.report("Can't set column " + i + " to double value " + values[i], e), e);
1037            throw new IllegalArgumentException("Couldn't column " + i + " to double value " + values[i], e);
1038            }
1039          _filled[i] = true;
1040          }
1041        }
1042    
1043      /** Get the number of the current row.
1044        * @return The current row number. */
1045      public int row() {
1046        return getRow();
1047        }
1048    
1049      /** Get the number of the current row.
1050        * @return The current row number. */
1051      public int getRow() {
1052        try {
1053          return _rs.getRow();
1054          }
1055        catch (SQLException e) {
1056          log.error(Util.report("Can't get row, returned 0", e), e);
1057          }
1058        return 0;
1059        }
1060    
1061      /** Go to the row with specified number.
1062        * @param row The number of row to go to.
1063        * @throws IllegalArgumentException if can't go to specified row.*/
1064      public void setRow(int row) throws IllegalArgumentException {
1065        try {
1066          _rs.absolute(row);
1067          }
1068        catch (SQLException e) {
1069          log.error(Util.report("Can't set row to " + row, e), e);
1070          throw new IllegalArgumentException("Couldn't set row to " + row, e);
1071          }
1072        }
1073    
1074      /** Start looping, positions in the first row. */
1075      public void start() {
1076        if (_names != _namesOrig) {
1077          _names          = _namesOrig;
1078          _types          = _typesOrig;
1079          _defaults       = _defaultsOrig;
1080          _defaultObjects = _defaultObjectsOrig;
1081          }
1082        String[] args = {title()};
1083        _rs = query("start", args);
1084        }
1085    
1086      /** <code>SQLTuple</code> extension: get subNTuple (subset of rows)
1087        * and positions in the first row. Use {@link IFilter}.
1088        * @param filter The IFilter to be used to select rows.
1089        * @throws SQLTupleException if can't get subNTuple.*/
1090      public void start(IFilter filter) throws SQLTupleException {
1091        String[] args = {filter.expression()};
1092        _rs = query("startFilter", args);
1093        }
1094    
1095      /** <code>SQLTuple</code> extension: get subNTuple (subset of columns)
1096        * and positions in the first row. Use SQL command from {@link StmtSrc}.
1097        * @param stmtSrc The SQL Stmt String to be used to select rows.
1098        * @throws SQLTupleException if can't get subNTuple.*/
1099      public void start(String stmtSrc) throws SQLTupleException {
1100        String[] args = {};
1101        _rs = query(stmtSrc, args);
1102        try {
1103          ResultSetMetaData rsmd = _rs.getMetaData();
1104          int cols = rsmd.getColumnCount();
1105          _names   = new String[cols];
1106          _types   = new Class[cols];
1107          for (int i = 0; i < cols; i++) {
1108            _names[i] = rsmd.getColumnName(i+1);
1109            for (int j = 0; j < _namesOrig.length; j++) {
1110              if (_names[i].equals(_namesOrig[j])) {
1111                _types[i] = _typesOrig[j];
1112                break;
1113                }
1114              }
1115            }
1116          }
1117        catch (SQLException e) {
1118          throw new SQLTupleException("Can't start using Statement " + stmtSrc, e);
1119          }
1120        }
1121    
1122      /** <code>SQLTuple</code> extension: get subNTuple (subset of rows and columns)
1123        * and positions in the first row. Use {@link IFilter} and
1124        * SQL command from {@link StmtSrc}.
1125        * @param filter  The IFilter to be used to select rows.
1126        * @param stmtSrc The SQL Stmt String to be used to select rows.
1127        * @throws SQLTupleException if can't get subNTuple.*/
1128      public void start(IFilter filter, 
1129                        String stmtSrc) throws SQLTupleException {
1130        String[] args = {filter.expression()};
1131        _rs = query(stmtSrc, args);
1132        try {
1133          ResultSetMetaData rsmd = _rs.getMetaData();
1134          int cols = rsmd.getColumnCount();
1135          _names   = new String[cols];
1136          _types   = new Class[cols];
1137          for (int i = 0; i < cols; i++) {
1138            _names[i] = rsmd.getColumnName(i+1);
1139            for (int j = 0; j < _namesOrig.length; j++) {
1140              if (_names[i].equals(_namesOrig[j])) {
1141                _types[i] = _typesOrig[j];
1142                break;
1143                }
1144              }
1145            }
1146          }
1147        catch (SQLException e) {
1148          throw new SQLTupleException("Can't start using Statement " + stmtSrc, e);
1149          }
1150        }
1151    
1152      /** <code>SQLTuple</code> extension: get subNTuple (subset of columns)
1153        * and positions in the first row.
1154        * @param columns The names of column to be extracted.
1155        * @throws SQLTupleException if can't get subNTuple.*/
1156      public void start(String[] columns) throws SQLTupleException {
1157        String[] args = new String[1];
1158        args[0] = "";
1159        for (int i = 0; i < columns.length; i++) {
1160          args[0] += columns[i];
1161          if (i < columns.length - 1) {
1162            args[0] += ",";
1163            }
1164          }
1165        _rs = query("getColumn", args);
1166        try {
1167          ResultSetMetaData rsmd = _rs.getMetaData();
1168          int cols = rsmd.getColumnCount();
1169          _names   = new String[cols];
1170          _types   = new Class[cols];
1171          for (int i = 0; i < cols; i++) {
1172            _names[i] = rsmd.getColumnName(i+1);
1173            for (int j = 0; j < _namesOrig.length; j++) {
1174              if (_names[i].equals(_namesOrig[j])) {
1175                _types[i] = _typesOrig[j];
1176                break;
1177                }
1178              }
1179            }
1180          }
1181        catch (SQLException e) {
1182          throw new SQLTupleException("Can't start using Statement getColumnFilter", e);
1183          }
1184        }
1185    
1186      /** <code>SQLTuple</code> extension: get subNTuple (subset of rows and columns) 
1187        * and positions in the first row. Uses {@link IFilter} and
1188        * SQL command from {@link StmtSrc}.
1189        * @param filter  The IFilter to be used to select rows.
1190        * @param columns The names of column to be extracted.
1191        * @throws SQLTupleException if can't get subNTuple.*/
1192      public void start(IFilter filter, String[] columns) throws SQLTupleException {
1193        String[] args = new String[2];
1194        args[0] = "";
1195        for (int i = 0; i < columns.length; i++) {
1196          args[0] += columns[i];
1197          if (i < columns.length - 1) {
1198            args[0] += ",";
1199            }
1200          }
1201        args[1] = filter.expression();
1202        _rs = query("getColumnFilter", args);
1203        try {
1204          ResultSetMetaData rsmd = _rs.getMetaData();
1205          int cols = rsmd.getColumnCount();
1206          _names   = new String[cols];
1207          _types   = new Class[cols];
1208          for (int i = 0; i < cols; i++) {
1209            _names[i] = rsmd.getColumnName(i+1);
1210            for (int j = 0; j < _namesOrig.length; j++) {
1211              if (_names[i].equals(_namesOrig[j])) {
1212                _types[i] = _typesOrig[j];
1213                break;
1214                }
1215              }
1216            }
1217          }
1218        catch (SQLException e) {
1219          throw new SQLTupleException("Can't start using Statement getColumnFilter", e);
1220          }
1221        }
1222    
1223      /** Skip rows.
1224        * @param rows The number of rows to skip. */
1225      public void skip(int rows) {
1226        try {
1227          _rs.relative(rows);
1228                }
1229              catch (SQLException e) {
1230          log.error(Util.report("Can't skip " + rows + " rows", e), e);
1231          throw new IllegalArgumentException("Couldn't skip " + rows + "  rows", e);
1232          }
1233        }
1234    
1235      /** Go into the next row.
1236        * @return true if success. */
1237      public boolean next() {
1238        try {
1239          if (_rs == null) {
1240            throw new SQLException("ResultSet not available");
1241            }
1242          return _rs.next();
1243                }
1244              catch (SQLException e) {
1245          log.error(Util.report("Can't go to next row", e), e);
1246          }
1247        return false;
1248        }
1249    
1250      /** <code>SQLTuple</code> extension: return current Row Data.
1251        * @return The array of Strings representing the current row. */
1252      public String[] getRowData() {
1253        String[] values = new String[_names.length];
1254        try {
1255          for (int i = 0; i < values.length; i++) {
1256            values[i] = _rs.getString(i+1);
1257            }
1258          }
1259        catch (SQLException e) {
1260          log.error(Util.report("Can't get Row Data", e), e);
1261          }
1262        return values;
1263        }
1264    
1265      /** Add the current row into NTuple and reset. 
1266        * Not set columns are set to their default values. */
1267      public void addRow() {
1268        for (int i = 0; i < columns(); i++) {
1269          if (!_filled[i]) {
1270            log.debug("Value of column " + i + " not set, using default value: " + _types[i] + " " + _names[i] + " = " + _defaults[i]);
1271            fill(i, _defaultObjects[i]);
1272            }
1273          }
1274        try {
1275          if (_rows == -1) {
1276            rows();
1277            }
1278          _rows += updatePrepared(_statement);
1279          }
1280              catch (SQLTupleException e) {
1281          log.error(Util.report("Can't execute PreparedStatement", e), e);
1282          }
1283        finally {
1284          resetRow();
1285          }
1286        }
1287    
1288      /** Prepare statement for adding row. */
1289      public void prepare(){
1290        StringBuffer values = new StringBuffer();
1291        for (int i = 0; i < _names.length; i++) {
1292          _filled[i] = false;
1293          values.append("?");
1294          if (i < _names.length - 1) {
1295            values.append(", ");
1296            }
1297          }
1298        String[] args = {values.toString()};
1299        try {
1300          _statement = _stmtSrc.prepare("addRow", args);
1301          }
1302        catch (SQLTupleException e) {
1303          log.warn("Can't prepare statement addRow");
1304          _readOnly = true;
1305          }
1306        }
1307    
1308      /** Gets the name of the column number <code>param</code>.
1309        * @param param The number of column.
1310        * @return      The name of the column. */
1311      public String columnName(int param) {
1312        return _names[param];
1313        }
1314    
1315      /** Gets the number of the column name <code>name</code>.
1316        * @param name The number of column.
1317        * @return     The number of the column. 
1318        * @throws IllegalArgumentException if no column with that name exists. */
1319      public int columnNumber(String name) throws IllegalArgumentException {
1320        if (_names != null) {
1321          for (int i = 0; i < _names.length; i++) {
1322            if (_names[i].equals(name)) {
1323              return i;
1324              }
1325            }
1326          }
1327        throw new IllegalArgumentException("There is no column " + name);
1328        }
1329    
1330      /** Get all column names. 
1331        * @return The array of Strings with all column names. */
1332      public String[] columnNames() {
1333        return _names;
1334        }
1335    
1336      /** Get the type of the column number <code>param</code>.
1337        * @param param The number of column.
1338        * @return      The type of the column. */
1339      public Class columnType(int param) {
1340        return _types[param];
1341        }
1342    
1343      /** Get all column types.
1344        * @return The array of Classes with all column types. */
1345      public Class[] columnTypes() {
1346        return _types;
1347        }
1348    
1349      /** <code>SQLTuple</code> extension:
1350        * Get the default value of the column number <code>param</code>.
1351        * @param param The number of column.
1352        * @return      The default value of the column. */
1353      public String columnDefault(int param) {
1354        return _defaults[param];
1355        }
1356        
1357      /** Give the default as a String.
1358        * @param  column The number of column.
1359        * @return        The String representation of the default. */
1360      public String columnDefaultString(int column) {
1361        return _defaults[column];
1362        }
1363    
1364      /** <code>SQLTuple</code> extension:
1365        * Get all column default values.
1366        * @return The array of Strings with all column default values. */
1367      public String[] columnDefaults() {
1368        return _defaults;
1369        }
1370    
1371      /** Gets the number of columns. 
1372        * @return The number of columns. */ 
1373      public int columns() {
1374        return _names.length;
1375        }
1376    
1377      /** Reset the NTuple/table, close it. */
1378      public void reset() {
1379        try {
1380          _rs.close();
1381          }
1382        catch (SQLException e) {
1383          log.error(Util.report("Can't reset", e), e);
1384          }
1385        _rs = null;
1386        }
1387    
1388      /** Reset the current row. */
1389      public void resetRow() throws IllegalArgumentException {
1390        try {
1391          _statement.clearParameters();
1392          for (int i = 0; i < columns(); i++) {
1393            _filled[i] = false;
1394            }
1395          }
1396              catch (SQLException e) {
1397          log.error(Util.report("Can't reset row", e), e);
1398          throw new IllegalArgumentException("Couldn't reset row", e);
1399          }
1400        }
1401    
1402      /** Get the number of rows.
1403        * @return The number of rows. */
1404      public int rows() throws IllegalArgumentException {
1405        if (_rows == -1) {
1406          try {
1407            ResultSet rs = query("rows", null);
1408            rs.next();
1409            _rows = rs.getInt(1);
1410            rs.close();
1411            }
1412          catch (SQLException e) {
1413            log.error(Util.report("Can't get rows", e), e);
1414            throw new IllegalArgumentException("Couldn't get rows", e);
1415            }
1416          }
1417        return _rows;
1418        }
1419    
1420      /** Get column.
1421        * @param index The column number.
1422        * @return      The requested {@link TupleColumn} */
1423      public IBaseTupleColumn column(int index) {
1424        return new SQLTupleColumn(this, index);
1425        }
1426    
1427      /** Get column.
1428        * @param name The column name.
1429        * @return     The requested {@link TupleColumn} */
1430      public FTupleColumn columnByName(String name) {
1431        return new SQLTupleColumn(this, findColumn(name));
1432        }
1433    
1434      /** Give nested {@link ITuple}. It is not supported.
1435        * @param index The column's index of the Folder.
1436        * @return The nested {@link ITuple}.
1437        * @throws UnsupportedOperationException always, because opereation is not supported. */
1438      public ITuple findTuple(int index) throws UnsupportedOperationException {
1439        throw new UnsupportedOperationException("Operation not supported in SQLTuple");
1440        }
1441    
1442      /** Get {@link FTupleCursor}.
1443        * @return The requested {@link FTupleCursor} */
1444      public FTupleCursor cursor() throws IllegalStateException {
1445        return new SQLTupleCursor(this);
1446        }
1447    
1448      /** Get {@link Value} of column at {@link FTupleCursor}.
1449        * @param column The column, value of which is requested.
1450        * @param value  The {@link Value} to be filled. */
1451      public void columnValue(int column, Value value) {
1452        Class cl = columnType(column);
1453             if (cl == Byte.TYPE)      value.set(getByte(column));
1454        else if (cl == Boolean.TYPE)   value.set(getBoolean(column));
1455        else if (cl == Character.TYPE) value.set(getChar(column));
1456        else if (cl == Short.TYPE)     value.set(getShort(column));
1457        else if (cl == Integer.TYPE)   value.set(getInt(column));
1458        else if (cl == Long.TYPE)      value.set(getLong(column));
1459        else if (cl == Float.TYPE)     value.set(getFloat(column));
1460        else if (cl == Double.TYPE)    value.set(getDouble(column));
1461        else if (cl == String.class)   value.set(getString(column));
1462        else                           value.set(getString(column));
1463        }
1464    
1465      /** Get {@link Value} of column at {@link FTupleCursor}.
1466        * @param column The column, value of which is requested.
1467        * @param cursor The {@link FTupleCursor} pointing to requested row.
1468        * @param value  The {@link Value} to be filled. */
1469      public void columnValue(int column, FTupleCursor cursor, Value value) {
1470        columnValue(column, value);
1471        }
1472    
1473      /** Get double value from the {@link ResultSet}. If direct <code>rs.getDouble(...)</code>
1474        * fails, <code>rs.getString(...)</code> and conversion to String is tried.
1475        * @param rs The {@link ResultSet} to be used. The current row will be inspected.
1476        * @param i  The column to be used.
1477        * @return   The found double value. 
1478        * @throws IllegalArgumentException if double value can't be extracted, even via String value. */
1479      private double getDouble(ResultSet rs, int i) throws IllegalArgumentException {
1480        // Try as double
1481        try {
1482          return rs.getDouble(i);
1483          }
1484        // Double failed
1485              catch (SQLException e) {
1486          // Try as String, convert to double
1487          try {
1488            String s = rs.getString(i);
1489            log.debug("Can't make projection, can't convert " + s + " to double, going via String: " + e.toString());
1490            return new Double(s);
1491            }
1492          // String failed
1493          catch (SQLException ee) {
1494            log.error(Util.report("Can't make projection", ee), ee);
1495            throw new IllegalArgumentException("Couldn't make projection", ee);
1496            }
1497          }
1498        }    
1499    
1500      public void project(ICloud1D   cloud,
1501                          IEvaluator evaluatorX) throws IllegalArgumentException {
1502        String[] args = {evaluatorX.expression()};
1503        ResultSet rs = query("projectX", args);
1504        try {
1505          while (rs.next()) {
1506            cloud.fill(getDouble(rs, 1));
1507            }
1508          }
1509        catch (Exception e) {
1510          log.error(Util.report("Can't make projection", e), e);
1511          throw new IllegalArgumentException("Couldn't make projection", e);
1512          }
1513              }
1514     
1515      public void project(ICloud1D   cloud,
1516                          IEvaluator evaluatorX,
1517                          IEvaluator weight) throws IllegalArgumentException {
1518        String[] args = {evaluatorX.expression(),
1519                         weight.expression()};
1520        ResultSet rs = query("projectXW", args);
1521        try {
1522          while (rs.next()) {
1523            cloud.fill(getDouble(rs, 1), getDouble(rs, 2));
1524            }
1525                }
1526              catch (SQLException e) {
1527          log.error(Util.report("Can't make projection", e), e);
1528          throw new IllegalArgumentException("Couldn't make projection", e);
1529          }
1530        }
1531    
1532      public void project(ICloud1D   cloud,
1533                          IEvaluator evaluatorX,
1534                          IFilter    filter) throws IllegalArgumentException {
1535        String[] args = {evaluatorX.expression(),
1536                         filter.expression()};
1537        ResultSet rs = query("projectXF", args);
1538        try {
1539          while (rs.next()) {
1540            cloud.fill(getDouble(rs, 1));
1541            }
1542                }
1543              catch (SQLException e) {
1544          log.error(Util.report("Can't make projection", e), e);
1545          throw new IllegalArgumentException("Couldn't make projection", e);
1546          }
1547        }
1548    
1549      public void project(ICloud1D   cloud,
1550                          IEvaluator evaluatorX,
1551                          IFilter    filter,
1552                          IEvaluator weight) throws IllegalArgumentException {
1553        String[] args = {evaluatorX.expression(),
1554                         weight.expression(),
1555                         filter.expression()};
1556        ResultSet rs = query("projectXFW", args);
1557        try {
1558          while (rs.next()) {
1559            cloud.fill(getDouble(rs, 1), getDouble(rs, 2));
1560            }
1561                }
1562              catch (SQLException e) {
1563          log.error(Util.report("Can't make projection", e), e);
1564          throw new IllegalArgumentException("Couldn't make projection", e);
1565          }
1566        }
1567    
1568      public void project(ICloud2D   cloud,
1569                          IEvaluator evaluatorX,
1570                          IEvaluator evaluatorY) throws IllegalArgumentException {
1571        String[] args = {evaluatorX.expression(),
1572                         evaluatorY.expression()};
1573        ResultSet rs = query("projectXY", args);
1574        try {
1575          while (rs.next()) {
1576            cloud.fill(getDouble(rs, 1), getDouble(rs, 2));
1577            }
1578                }
1579              catch (SQLException e) {
1580          log.error(Util.report("Can't make projection", e), e);
1581          throw new IllegalArgumentException("Couldn't make projection", e);
1582          }
1583        }
1584    
1585      public void project(ICloud2D   cloud,
1586                          IEvaluator evaluatorX,
1587                          IEvaluator evaluatorY,
1588                          IEvaluator weight) throws IllegalArgumentException {
1589        String[] args = {evaluatorX.expression(),
1590                         evaluatorY.expression(),
1591                         weight.expression()};
1592        ResultSet rs = query("projectXYW", args);
1593        try {
1594          while (rs.next()) {
1595            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1596            }
1597                }
1598              catch (SQLException e) {
1599          log.error(Util.report("Can't make projection", e), e);
1600          throw new IllegalArgumentException("Couldn't make projection", e);
1601          }
1602        }
1603    
1604      public void project(ICloud2D   cloud,
1605                          IEvaluator evaluatorX,
1606                          IEvaluator evaluatorY,
1607                          IFilter    filter) throws IllegalArgumentException {
1608        String[] args = {evaluatorX.expression(),
1609                         evaluatorY.expression(),
1610                         filter.expression()};
1611        ResultSet rs = query("projectXYF", args);
1612        try {
1613          while (rs.next()) {
1614            cloud.fill(getDouble(rs, 1), getDouble(rs, 2));
1615            }
1616                }
1617              catch (SQLException e) {
1618          log.error(Util.report("Can't make projection", e), e);
1619          throw new IllegalArgumentException("Couldn't make projection", e);
1620          }
1621        }
1622    
1623      public void project(ICloud2D   cloud,
1624                          IEvaluator evaluatorX,
1625                          IEvaluator evaluatorY,
1626                          IFilter    filter,
1627                          IEvaluator weight) throws IllegalArgumentException {
1628        String[] args = {evaluatorX.expression(),
1629                         evaluatorY.expression(),
1630                         weight.expression(),
1631                         filter.expression()};
1632        ResultSet rs = query("projectXYFW", args);
1633        try {
1634          while (rs.next()) {
1635            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1636            }
1637                }
1638              catch (SQLException e) {
1639          log.error(Util.report("Can't make projection", e), e);
1640          throw new IllegalArgumentException("Couldn't make projection", e);
1641          }
1642        }
1643    
1644      public void project(ICloud3D   cloud,
1645                          IEvaluator evaluatorX,
1646                          IEvaluator evaluatorY,
1647                          IEvaluator evaluatorZ) throws IllegalArgumentException {
1648        String[] args = {evaluatorX.expression(),
1649                         evaluatorY.expression(),
1650                         evaluatorZ.expression()};
1651        ResultSet rs = query("projectXYZ", args);
1652        try {
1653          while (rs.next()) {
1654            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1655            }
1656                }
1657              catch (SQLException e) {
1658          log.error(Util.report("Can't make projection", e), e);
1659          throw new IllegalArgumentException("Couldn't make projection", e);
1660          }
1661        }
1662    
1663      public void project(ICloud3D   cloud,
1664                          IEvaluator evaluatorX,
1665                          IEvaluator evaluatorY,
1666                          IEvaluator evaluatorZ,
1667                          IEvaluator weight) throws IllegalArgumentException {
1668        String[] args = {evaluatorX.expression(),
1669                         evaluatorY.expression(),
1670                         evaluatorZ.expression(),
1671                         weight.expression()};
1672        ResultSet rs = query("projectXYZW", args);
1673        try {
1674          while (rs.next()) {
1675            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1676            }
1677                }
1678              catch (SQLException e) {
1679          log.error(Util.report("Can't make projection", e), e);
1680          throw new IllegalArgumentException("Couldn't make projection", e);
1681          }
1682        }
1683    
1684      public void project(ICloud3D   cloud,
1685                          IEvaluator evaluatorX,
1686                          IEvaluator evaluatorY,
1687                          IEvaluator evaluatorZ,
1688                          IFilter    filter) throws IllegalArgumentException {
1689        String[] args = {evaluatorX.expression(),
1690                         evaluatorY.expression(),
1691                         evaluatorZ.expression(),
1692                         filter.expression()};
1693        ResultSet rs = query("projectXYZF", args);
1694        try {
1695          while (rs.next()) {
1696            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1697            }
1698                }
1699              catch (SQLException e) {
1700          log.error(Util.report("Can't make projection", e), e);
1701          throw new IllegalArgumentException("Couldn't make projection", e);
1702          }
1703        }
1704    
1705      public void project(ICloud3D   cloud,
1706                          IEvaluator evaluatorX,
1707                          IEvaluator evaluatorY,
1708                          IEvaluator evaluatorZ,
1709                          IFilter    filter,
1710                          IEvaluator weight) throws IllegalArgumentException {
1711        String[] args = {evaluatorX.expression(),
1712                         evaluatorY.expression(),
1713                         evaluatorZ.expression(),
1714                         weight.expression(),
1715                         filter.expression()};
1716        ResultSet rs = query("projectXYZFW", args);
1717        try {
1718          while (rs.next()) {
1719            cloud.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1720            }
1721                }
1722              catch (SQLException e) {
1723          log.error(Util.report("Can't make projection", e), e);
1724          throw new IllegalArgumentException("Couldn't make projection", e);
1725          }
1726        }
1727    
1728      public void project(IHistogram1D histogram,
1729                          IEvaluator evaluatorX) throws IllegalArgumentException {
1730        String[] args = {evaluatorX.expression()};
1731        ResultSet rs = query("projectX", args);
1732        try {
1733          while (rs.next()) {
1734            histogram.fill(getDouble(rs, 1));
1735            }
1736                }
1737              catch (SQLException e) {
1738          log.error(Util.report("Can't make projection", e), e);
1739          throw new IllegalArgumentException("Couldn't make projection", e);
1740          }
1741        }
1742    
1743      public void project(IHistogram1D histogram,
1744                          IEvaluator   evaluatorX,
1745                          IEvaluator   weight) throws IllegalArgumentException {
1746        String[] args = {evaluatorX.expression(),
1747                         weight.expression()};
1748        ResultSet rs = query("projectXW", args);
1749        try {
1750          while (rs.next()) {
1751            histogram.fill(getDouble(rs, 1), getDouble(rs, 2));
1752            }
1753                }
1754              catch (SQLException e) {
1755          log.error(Util.report("Can't make projection", e), e);
1756          throw new IllegalArgumentException("Couldn't make projection", e);
1757          }
1758        }
1759    
1760      public void project(IHistogram1D histogram,
1761                          IEvaluator   evaluatorX,
1762                          IFilter      filter) throws IllegalArgumentException {
1763        String[] args = {evaluatorX.expression(),
1764                         filter.expression()};
1765        ResultSet rs = query("projectXF", args);
1766        try {
1767          while (rs.next()) {
1768            histogram.fill(getDouble(rs, 1));
1769            }
1770                }
1771              catch (SQLException e) {
1772          log.error(Util.report("Can't make projection", e), e);
1773          throw new IllegalArgumentException("Couldn't make projection", e);
1774          }
1775        }
1776    
1777      public void project(IHistogram1D histogram,
1778                          IEvaluator   evaluatorX,
1779                          IFilter      filter,
1780                          IEvaluator   weight) throws IllegalArgumentException {
1781        String[] args = {evaluatorX.expression(),
1782                         weight.expression(),
1783                         filter.expression()};
1784        ResultSet rs = query("projectXFW", args);
1785        try {
1786          while (rs.next()) {
1787            histogram.fill(getDouble(rs, 1), getDouble(rs, 2));
1788            }
1789                }
1790              catch (SQLException e) {
1791          log.error(Util.report("Can't make projection", e), e);
1792          throw new IllegalArgumentException("Couldn't make projection", e);
1793          }
1794        }
1795    
1796      public void project(IHistogram2D histogram,
1797                          IEvaluator   evaluatorX,
1798                          IEvaluator   evaluatorY) throws IllegalArgumentException {
1799        String[] args = {evaluatorX.expression(),
1800                         evaluatorY.expression()};
1801        ResultSet rs = query("projectXY", args);
1802        try {
1803          while (rs.next()) {
1804            histogram.fill(getDouble(rs, 1), getDouble(rs, 2));
1805            }
1806                }
1807              catch (SQLException e) {
1808          log.error(Util.report("Can't make projection", e), e);
1809          throw new IllegalArgumentException("Couldn't make projection", e);
1810          }
1811        }
1812    
1813      public void project(IHistogram2D histogram,
1814                          IEvaluator   evaluatorX,
1815                          IEvaluator   evaluatorY,
1816                          IEvaluator   weight) throws IllegalArgumentException {
1817        String[] args = {evaluatorX.expression(),
1818                         evaluatorY.expression(),
1819                         weight.expression()};
1820        ResultSet rs = query("projectXYW", args);
1821        try {
1822          while (rs.next()) {
1823            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1824            }
1825                }
1826              catch (SQLException e) {
1827          log.error(Util.report("Can't make projection", e), e);
1828          throw new IllegalArgumentException("Couldn't make projection", e);
1829          }
1830        }
1831    
1832      public void project(IHistogram2D histogram,
1833                          IEvaluator   evaluatorX,
1834                          IEvaluator   evaluatorY,
1835                          IFilter      filter) throws IllegalArgumentException {
1836        String[] args = {evaluatorX.expression(),
1837                         evaluatorY.expression(),
1838                         filter.expression()};
1839        ResultSet rs = query("projectXYF", args);
1840        try {
1841          while (rs.next()) {
1842            histogram.fill(getDouble(rs, 1), getDouble(rs, 2));
1843            }
1844                }
1845              catch (SQLException e) {
1846          log.error(Util.report("Can't make projection", e), e);
1847          throw new IllegalArgumentException("Couldn't make projection", e);
1848          }
1849        }
1850    
1851      public void project(IHistogram2D histogram,
1852                          IEvaluator   evaluatorX,
1853                          IEvaluator   evaluatorY,
1854                          IFilter      filter,
1855                          IEvaluator   weight) throws IllegalArgumentException {
1856        String[] args = {evaluatorX.expression(),
1857                         evaluatorY.expression(),
1858                         weight.expression(),
1859                         filter.expression()};
1860        ResultSet rs = query("projectXYFW", args);
1861        try {
1862          while (rs.next()) {
1863            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1864            }
1865                }
1866              catch (SQLException e) {
1867          log.error(Util.report("Can't make projection", e), e);
1868          throw new IllegalArgumentException("Couldn't make projection", e);
1869          }
1870        }
1871    
1872      public void project(IHistogram3D histogram,
1873                          IEvaluator   evaluatorX,
1874                          IEvaluator   evaluatorY,
1875                          IEvaluator   evaluatorZ) throws IllegalArgumentException {
1876        String[] args = {evaluatorX.expression(),
1877                         evaluatorY.expression(),
1878                         evaluatorZ.expression()};
1879        ResultSet rs = query("projectXYZ", args);
1880        try {
1881          while (rs.next()) {
1882            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1883            }
1884                }
1885              catch (SQLException e) {
1886          log.error(Util.report("Can't make projection", e), e);
1887          throw new IllegalArgumentException("Couldn't make projection", e);
1888          }
1889        }
1890    
1891      public void project(IHistogram3D histogram,
1892                          IEvaluator   evaluatorX,
1893                          IEvaluator   evaluatorY,
1894                          IEvaluator   evaluatorZ,
1895                          IEvaluator   weight) throws IllegalArgumentException {
1896        String[] args = {evaluatorX.expression(),
1897                         evaluatorY.expression(),
1898                         evaluatorZ.expression(),
1899                         weight.expression()};
1900        ResultSet rs = query("projectXYZW", args);
1901        try {
1902          while (rs.next()) {
1903            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1904            }
1905                }
1906              catch (SQLException e) {
1907          log.error(Util.report("Can't make projection", e), e);
1908          throw new IllegalArgumentException("Couldn't make projection", e);
1909          }
1910        }
1911    
1912      public void project(IHistogram3D histogram,
1913                          IEvaluator   evaluatorX,
1914                          IEvaluator   evaluatorY,
1915                          IEvaluator   evaluatorZ,
1916                          IFilter      filter) throws IllegalArgumentException {
1917        String[] args = {evaluatorX.expression(),
1918                         evaluatorY.expression(),
1919                         evaluatorZ.expression(),
1920                         filter.expression()};
1921        ResultSet rs = query("projectXYZF", args);
1922        try {
1923          while (rs.next()) {
1924            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1925            }
1926                }
1927              catch (SQLException e) {
1928          log.error(Util.report("Can't make projection", e), e);
1929          throw new IllegalArgumentException("Couldn't make projection", e);
1930          }
1931        }
1932    
1933      public void project(IHistogram3D histogram,
1934                          IEvaluator   evaluatorX,
1935                          IEvaluator   evaluatorY,
1936                          IEvaluator   evaluatorZ,
1937                          IFilter      filter,
1938                          IEvaluator   weight) throws IllegalArgumentException {
1939        String[] args = {evaluatorX.expression(),
1940                         evaluatorY.expression(),
1941                         evaluatorZ.expression(),
1942                         weight.expression(),
1943                         filter.expression()};
1944        ResultSet rs = query("projectXYZFW", args);
1945       try {
1946          while (rs.next()) {
1947            histogram.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
1948            }
1949                }
1950              catch (SQLException e) {
1951          log.error(Util.report("Can't make projection", e), e);
1952          throw new IllegalArgumentException("Couldn't make projection", e);
1953          }
1954        }
1955    
1956      public void project(IProfile1D profile,
1957                          IEvaluator evaluatorX,
1958                          IEvaluator evaluatorY) throws IllegalArgumentException {
1959        String[] args = {evaluatorX.expression(),
1960                         evaluatorY.expression()};
1961        ResultSet rs = query("projectXY", args);
1962        try {
1963          while (rs.next()) {
1964            profile.fill(getDouble(rs, 1), getDouble(rs, 2));
1965            }
1966                }
1967              catch (SQLException e) {
1968           log.error(Util.report("Can't make projection", e), e);
1969          throw new IllegalArgumentException("Couldn't make projection", e);
1970         }
1971        }
1972    
1973      public void project(IProfile1D profile,
1974                          IEvaluator evaluatorX,
1975                          IEvaluator evaluatorY,
1976                          IEvaluator weight) throws IllegalArgumentException {
1977        String[] args = {evaluatorX.expression(),
1978                         evaluatorY.expression(),
1979                         weight.expression()};
1980        ResultSet rs = query("projectXYW", args);
1981        try {
1982          while (rs.next()) {
1983            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
1984            }
1985                }
1986              catch (SQLException e) {
1987          log.error(Util.report("Can't make projection", e), e);
1988          throw new IllegalArgumentException("Couldn't make projection", e);
1989          }
1990        }
1991    
1992      public void project(IProfile1D profile,
1993                          IEvaluator evaluatorX,
1994                          IEvaluator evaluatorY,
1995                          IFilter    filter) throws IllegalArgumentException {
1996        String[] args = {evaluatorX.expression(),
1997                         evaluatorY.expression(),
1998                         filter.expression()};
1999        ResultSet rs = query("projectXYF", args);
2000        try {
2001          while (rs.next()) {
2002            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
2003            }
2004                }
2005              catch (SQLException e) {
2006          log.error(Util.report("Can't make projection", e), e);
2007          throw new IllegalArgumentException("Couldn't make projection", e);
2008          }
2009        }
2010    
2011      public void project(IProfile1D profile,
2012                          IEvaluator evaluatorX,
2013                          IEvaluator evaluatorY,
2014                          IFilter    filter,
2015                          IEvaluator weight) throws IllegalArgumentException {
2016        String[] args = {evaluatorX.expression(),
2017                         evaluatorY.expression(),
2018                         weight.expression(),
2019                         filter.expression()};
2020        ResultSet rs = query("projectXYFW", args);
2021        try {
2022          while (rs.next()) {
2023            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
2024            }
2025                }
2026              catch (SQLException e) {
2027          log.error(Util.report("Can't make projection", e), e);
2028          throw new IllegalArgumentException("Couldn't make projection", e);
2029          }
2030        }
2031    
2032      public void project(IProfile2D profile,
2033                          IEvaluator evaluatorX,
2034                          IEvaluator evaluatorY,
2035                          IEvaluator evaluatorZ) throws IllegalArgumentException {
2036        String[] args = {evaluatorX.expression(),
2037                         evaluatorY.expression(),
2038                         evaluatorZ.expression()};
2039        ResultSet rs = query("projectXYZ", args);
2040        try {
2041          while (rs.next()) {
2042            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3));
2043            }
2044                }
2045              catch (SQLException e) {
2046          log.error(Util.report("Can't make projection", e), e);
2047          throw new IllegalArgumentException("Couldn't make projection", e);
2048          }
2049        }
2050    
2051      public void project(IProfile2D profile,
2052                          IEvaluator evaluatorX,
2053                          IEvaluator evaluatorY,
2054                          IEvaluator evaluatorZ,
2055                          IEvaluator weight) throws IllegalArgumentException {
2056        String[] args = {evaluatorX.expression(),
2057                         evaluatorY.expression(),
2058                         evaluatorZ.expression(),
2059                         weight.expression()};
2060        ResultSet rs = query("projectXYZW", args);
2061        try {
2062          while (rs.next()) {
2063            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
2064            }
2065                }
2066              catch (SQLException e) {
2067          log.error(Util.report("Can't make projection", e), e);
2068          throw new IllegalArgumentException("Couldn't make projection", e);
2069          }
2070        }
2071    
2072      public void project(IProfile2D profile,
2073                          IEvaluator evaluatorX,
2074                          IEvaluator evaluatorY,
2075                          IEvaluator evaluatorZ,
2076                          IFilter    filter) throws IllegalArgumentException {
2077        String[] args = {evaluatorX.expression(),
2078                         evaluatorY.expression(),
2079                         evaluatorZ.expression(),
2080                         filter.expression()};
2081        ResultSet rs = query("projectXYZF", args);
2082        try {
2083          while (rs.next()) {
2084            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
2085            }
2086                }
2087              catch (SQLException e) {
2088          log.error(Util.report("Can't make projection", e), e);
2089          throw new IllegalArgumentException("Couldn't make projection", e);
2090          }
2091        }
2092    
2093      public void project(IProfile2D profile,
2094                          IEvaluator evaluatorX,
2095                          IEvaluator evaluatorY,
2096                          IEvaluator evaluatorZ,
2097                          IFilter    filter,
2098                          IEvaluator weight) throws IllegalArgumentException {
2099        String[] args = {evaluatorX.expression(),
2100                         evaluatorY.expression(),
2101                         evaluatorZ.expression(),
2102                         weight.expression(),
2103                         filter.expression()};
2104        ResultSet rs = query("projectXYZFW", args);
2105        try {
2106          while (rs.next()) {
2107            profile.fill(getDouble(rs, 1), getDouble(rs, 2), getDouble(rs, 3), getDouble(rs, 4));
2108            }
2109                }
2110              catch (SQLException e) {
2111          log.error(Util.report("Can't make projection", e), e);
2112          throw new IllegalArgumentException("Couldn't make projection", e);
2113          }
2114        }
2115    
2116      /** <code>SQLTuple</code> extension: get the whole column as an array
2117        * of Strings.
2118        * @param  cName The name of the column.
2119        * @return       The {@link Collection} containing the whole column as Strings. */
2120      public Collection<String> getColumn(String cName) {
2121        return getColumn(cName, String.class);
2122        }
2123    
2124      /** <code>SQLTuple</code> extension: get the whole column as an array
2125        * of Objects of the specified Class (which has to have a String constructor).
2126        * @param  cName The name of the column.
2127        * @param  cl    The Class (with String constructor) to be used to create Objects for {@link Collection}.
2128        * @return       The {@link Collection} containing the whole column as Objects of specified Class. */
2129      public <T> Collection<T> getColumn(String cName,
2130                                         Class<T>  cl) {
2131        return getColumn(cName, cl, null);
2132        }
2133    
2134      /** <code>SQLTuple</code> extension: get the filtered column as an array
2135        * of Strings.  
2136        * @param  cName  The name of the column.
2137        * @param  filter The {@link IFilter} to be used to select rows.
2138        * @return        The [@link Collection} containing the whole column as Strings. */
2139      public Collection<String> getColumn(String  cName,
2140                                          IFilter filter) {
2141        return getColumn(cName, String.class, filter);
2142        }
2143    
2144      /** <code>SQLTuple</code> extension: get the filtered column as an array
2145        * of Objects of the specified Class (it has to have a String constructor).
2146        * @param  cName  The name of the column.
2147        * @param  cl     The Class (with String constructor) to be used to create Objects for {@link Collection}.
2148        * @param  filter The {@link IFilter} to be used to select rows.
2149        * @return        The {@link Collection} containing the whole column as Objects of specified Class. */
2150      public <T> Collection<T> getColumn(String cName,
2151                                         Class<T> cl,
2152                                         IFilter filter) {
2153        Collection<T> values = new ArrayList<T>();
2154        Class[] parameters = {String.class};
2155        Constructor<T> constructor = null;
2156        try {
2157          constructor = cl.getConstructor(parameters);
2158          }
2159        catch(NoSuchMethodException e) {
2160          log.error(Util.report("Can't find constructor " + cl + "(" + cName + "), return empty Collection", e), e);
2161          return values;
2162          }
2163        Object args[];
2164        T obj = null;
2165        ResultSet rs = null;
2166        if (filter == null) {
2167          String[] args0 = {cName};
2168          rs = query("getColumn", args0);
2169          }
2170        else {
2171          String[] args0 = {cName, filter.expression()};
2172          rs = query("getColumnFilter", args0);
2173          }
2174        try {
2175          while (rs.next()) {
2176            args = new Object[1];
2177            args[0] = rs.getString(1);
2178            try {
2179              obj = constructor.newInstance(args);
2180              values.add((T)obj);
2181              }
2182            catch(InstantiationException e) {
2183              log.error(Util.report("Can't construct " + cl + " from " + args[0] + ", return empty Collection", e), e);  
2184              }
2185            catch(IllegalAccessException e) {
2186              log.error(Util.report("Can't construct " + cl + " from " + args[0] + ", return empty Collection", e), e);  
2187              }
2188            catch(InvocationTargetException e) {
2189              log.error(Util.report("Can't construct " + cl + " from " + args[0] + ", return empty Collection", e), e);  
2190              }
2191            }
2192                }
2193              catch (SQLException e) {
2194          log.error(Util.report("Can't get column " + cName + " with filter " + filter.expression() + " as Collection<String>, return empty Collection", e), e);
2195          }
2196        return values;
2197        }
2198    
2199      /** Register options.
2200        * @param options The options string to be registered. 
2201        * @throws SQLTupleException if Accessor can't be created. */
2202      public void setOptions(String options) throws SQLTupleException {
2203        _accessor = Accessor.getAccessor(options);
2204        }
2205    
2206      /** Get attached {@link Accessor}.
2207        * @return The associated Accessor. */
2208      public Accessor accessor() {
2209        return _accessor;
2210        }
2211    
2212      /** Perform update operation via {@link StmtSrc}.
2213        * @param statementString The SQL statement to be used. 
2214        * @param args            The arguments to be filled into the SQL statement in place of X*.
2215        * @return                The number of added rows.
2216        * @throws IllegalArgumentException if the update can't be performed. */
2217      private int update(String statementString,
2218                         String[] args) throws IllegalArgumentException {
2219        try {
2220          return _stmtSrc.update(statementString, args);
2221          }
2222        catch(SQLTupleException e) {
2223          log.error(Util.report("Can't perform update " + statementString, e), e);
2224          throw new IllegalArgumentException("Couldn't perform update " + statementString, e);
2225          }
2226        }
2227    
2228      /** Perform update operation via {@link StmtSrc} using {@link PreparedStatement}.
2229        * @param statement The SQL {@link PreparedStatement} to be used. 
2230        * @return          The number of added rows.
2231        * @throws SQLTupleException if the update can't be performed. */
2232      private int updatePrepared(PreparedStatement statement) throws SQLTupleException {
2233        try {
2234          return _stmtSrc.updatePrepared(statement);
2235          }
2236        catch(SQLTupleException e) {
2237          log.error(Util.report("Can't perform update using Prepared Statement " + statement, e), e);
2238          throw new IllegalArgumentException("Couldn't perform update using Prepared Statement " + statement, e);
2239          }
2240        }
2241    
2242      /** Perform query operation via {@link StmtSrc}.
2243        * @param statementString The SQL statement to be used.
2244        * @param args            The arguments to be filled into the SQL statement in place of X*.
2245        * @return                The results of the SQL command.
2246        * @throws IllegalArgumentException if the update can't be performed. */
2247      private ResultSet query(String statementString,
2248                              String[] args) throws IllegalArgumentException {
2249        try {
2250          ResultSet rs = _stmtSrc.query(statementString, args);
2251          if (!_accessor.forwardOnly()) {
2252            rs.last();
2253            _rows = rs.getRow();
2254            rs.beforeFirst();
2255            }
2256          return rs;
2257          }
2258        catch(Exception e) {
2259          log.error(Util.report("Can't perform query " + statementString, e), e);
2260          throw new IllegalArgumentException("Couldn't perform query " + statementString, e);
2261          }
2262        }
2263    
2264      /** Give attached {@link StmtSrc}.
2265        * @return The attached {@link StmtSrc}. */
2266      public StmtSrc stmtSrc() {
2267        return _stmtSrc;
2268        }
2269    
2270      /** Attached {@link StmtSrc}.
2271        * @param url The {@link StmtSrc} to be attached. */
2272      public void setStmtSrc(String url) {
2273        String src = _accessor.src();
2274        _accessor.setSrc(url);
2275        try {  
2276          _stmtSrc = new StmtSrc(_accessor, title());
2277          }
2278        catch (SQLTupleException e) {
2279          log.error(Util.report("Can't (re)set StmtSrc to " + url, e), e);
2280          _accessor.setSrc(src);
2281          }
2282        }
2283    
2284      /** Create Object from String value.
2285        * @param value The value as {@link String}.
2286        * @param type  The type of the requested Object.
2287        * @return      The Object of the requested type with the requested value. */
2288      private Object type2Object(String value, Class type) {
2289        Object valueObject;
2290             if (type == Integer.TYPE  ) valueObject = ((value ==  null) ? (int   )0 : Integer.parseInt(  value));
2291        else if (type == Short.TYPE    ) valueObject = ((value ==  null) ? (short )0 : Short.parseShort(  value));
2292        else if (type == Long.TYPE     ) valueObject = ((value ==  null) ? (long  )0 : Long.parseLong(    value));
2293        else if (type == Float.TYPE    ) valueObject = ((value ==  null) ? (float )0 : Float.parseFloat(  value));
2294        else if (type == Double.TYPE   ) valueObject = ((value ==  null) ? (double)0 : Double.parseDouble(value));
2295        else if (type == Boolean.TYPE  ) valueObject = ((value ==  null) ? false     : Boolean.valueOf(   value).booleanValue());
2296        else if (type == Byte.TYPE     ) valueObject = ((value ==  null) ? (byte  )0 : Byte.parseByte(    value));
2297        else if (type == Character.TYPE) valueObject = ((value ==  null) ? (char  )0 :                    value.charAt(0));
2298        else                             valueObject = ((value ==  null) ? ""        :                    value);
2299        return valueObject;
2300        }
2301    
2302      private Accessor _accessor;
2303    
2304      private StmtSrc _stmtSrc;
2305    
2306      private PreparedStatement _statement;
2307    
2308      private ResultSet _rs;
2309    
2310      private String[] _names;
2311    
2312      private Class[] _types;
2313    
2314      private String[] _defaults;
2315      
2316      private Object[] _defaultObjects;
2317      
2318      private String[] _namesOrig;
2319    
2320      private Class[] _typesOrig;
2321    
2322      private String[] _defaultsOrig;
2323      
2324      private Object[] _defaultObjectsOrig;
2325    
2326      private boolean[] _filled;
2327        
2328      private int _rows;
2329      
2330      private boolean _readOnly = false;
2331    
2332      /** Logging . */
2333      private static Logger log = Logger.getLogger(SQLTuple.class);
2334    
2335      }