KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > Result


1 /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the Hypersonic SQL Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This software consists of voluntary contributions made by many individuals
31  * on behalf of the Hypersonic SQL Group.
32  *
33  *
34  * For work added by the HSQL Development Group:
35  *
36  * Copyright (c) 2001-2005, The HSQL Development Group
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions are met:
41  *
42  * Redistributions of source code must retain the above copyright notice, this
43  * list of conditions and the following disclaimer.
44  *
45  * Redistributions in binary form must reproduce the above copyright notice,
46  * this list of conditions and the following disclaimer in the documentation
47  * and/or other materials provided with the distribution.
48  *
49  * Neither the name of the HSQL Development Group nor the names of its
50  * contributors may be used to endorse or promote products derived from this
51  * software without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */

65
66
67 package org.hsqldb;
68
69 import java.io.DataInput JavaDoc;
70 import java.io.IOException JavaDoc;
71 import java.io.OutputStream JavaDoc;
72 import java.util.NoSuchElementException JavaDoc;
73
74 import org.hsqldb.lib.Iterator;
75 import org.hsqldb.rowio.RowInputBinary;
76 import org.hsqldb.rowio.RowOutputBinary;
77
78 // fredt@users 20020130 - patch 1.7.0 by fredt
79
// to ensure consistency of r.rTail r.iSize in all operations
80
// methods for set operations moved here from Select.java
81
// tony_lai@users 20020820 - patch 595073 - duplicated exception msg
82
// fredt@users 20030801 - patch 1.7.2 - separate metadata and polymophic serialisation
83
// boucherb@users 200307/8 - various, in support of fred's work over the same time period
84

85 /**
86  * The primary unit of comunication between Connection, Server and Session
87  * objects.
88  *
89  * An HSQLDB Result object encapsulates all requests (such as to alter or
90  * query session settings, to allocate and execute statements, etc.) and all
91  * responses (such as exception indications, update counts, result sets and
92  * result set metadata). It also implements the HSQL wire protocol for
93  * comunicating all such requests and responses across the network.
94  *
95  * Extensively rewritten and extended in successive versions of HSQLDB.
96  *
97  * @author Thomas Mueller (Hypersonic SQL Group)
98  * @version 1.8.0
99  * @since Hypersonic SQL
100  */

101 public class Result {
102
103     // record list
104
public Record rRoot;
105     private Record rTail;
106     private int size;
107
108     // transient - number of significant columns
109
private int significantColumns;
110
111     // type of result
112
public int mode;
113
114 // boolean isMulti;
115
// database ID
116
int databaseID;
117
118     // session ID
119
int sessionID;
120
121     // user / password or error strings
122
String JavaDoc mainString;
123     String JavaDoc subString;
124
125     // database name
126
String JavaDoc subSubString;
127
128     // the exception if this is an error
129
private Throwable JavaDoc exception;
130
131     // prepared statement id / error vendor code
132
int statementID;
133
134     // max rows (out) or update count (in)
135
int updateCount;
136     public ResultMetaData metaData;
137
138     /** A Result object's metadata */
139     public static class ResultMetaData {
140
141         // always resolved
142
public String JavaDoc[] colLabels;
143         public String JavaDoc[] tableNames;
144         public String JavaDoc[] colNames;
145         public boolean[] isLabelQuoted;
146         public int[] colTypes;
147         public int[] colSizes;
148         public int[] colScales;
149
150         // extra attrs, sometimes resolved
151
public String JavaDoc[] catalogNames;
152         public String JavaDoc[] schemaNames;
153         public int[] colNullable;
154         public boolean[] isIdentity;
155         public boolean[] isWritable;
156         public int[] paramMode;
157
158         // It's possible to do better than java.lang.Object
159
// for type OTHER if the expression generating the value
160
// is of type FUNCTION. This applies to result set columns
161
// whose value is the result of a SQL function call and
162
// especially to the arguments and return value of a CALL
163
public String JavaDoc[] classNames;
164         boolean isParameterDescription;
165
166         ResultMetaData() {}
167
168         ResultMetaData(int n) {
169             prepareData(n);
170         }
171
172         /**
173          * Method declaration
174          *
175          * @param columns
176          */

177         private void prepareData(int columns) {
178
179             colLabels = new String JavaDoc[columns];
180             tableNames = new String JavaDoc[columns];
181             colNames = new String JavaDoc[columns];
182             isLabelQuoted = new boolean[columns];
183             colTypes = new int[columns];
184             colSizes = new int[columns];
185             colScales = new int[columns];
186             catalogNames = new String JavaDoc[columns];
187             schemaNames = new String JavaDoc[columns];
188             colNullable = new int[columns];
189             isIdentity = new boolean[columns];
190             isWritable = new boolean[columns];
191             classNames = new String JavaDoc[columns];
192         }
193
194         public int[] getParameterTypes() {
195             return colTypes;
196         }
197
198         boolean isTableColumn(int i) {
199             return tableNames[i] != null && tableNames[i].length() > 0
200                    && colNames[i] != null && colNames[i].length() > 0;
201         }
202
203         private void decodeTableColumnAttrs(int in, int i) {
204
205             colNullable[i] = in & 0x0000000f;
206             isIdentity[i] = (in & 0x00000010) != 0;
207             isWritable[i] = (in & 0x00000020) != 0;
208         }
209
210         private void writeTableColumnAttrs(RowOutputBinary out,
211                                            int i)
212                                            throws IOException JavaDoc, HsqlException {
213
214             // HSQLDB also ignores precision and scale for all types except
215
// XXXCHAR, for which it may (or may not) perform some trimming/padding.
216
// All in all, it's currently meaningless (indeed misleading) to
217
// transmit and report the values, as the data typically will
218
// not be constrained accordingly.
219
// switch(colType[i]) {
220
// // As early as SQL 92, these are allowed to have a scale.
221
// // However, DatabaseCommandInterpreter.processCreateColumn
222
// // does not currently handle this correctly and will assign
223
// // a precision instead of a scale if TIME(s) or TIMESTAMP(s)
224
// // is specified
225
// case Types.TIME :
226
// case Types.TIMESTAMP :
227
// out.writeIntData(colScale[i]);
228
// break;
229
// case Types.DECIMAL :
230
// case Types.NUMERIC : {
231
// out.writeIntData(colScale[i]);
232
// } // fall through
233
// // Apparently, SQL 92 specifies that FLOAT can have
234
// // a declared precision, which is typically the number of
235
// // bits (not binary digits). In any case, this is somewhat
236
// // meaningless under HSQLDB/Java, in that we use java.lang.Double
237
// // to represent SQL FLOAT
238
// case Types.FLOAT :
239
// // It's legal to declare precision for these, although HSQLDB
240
// // currently does not use it to constrain values
241
// case Types.BINARY :
242
// case Types.VARBINARY :
243
// case Types.LONGVARBINARY :
244
// // possibly, but not universally acted upon (trimmming/padding)
245
// case Types.CHAR :
246
// case Types.VARCHAR :
247
// case Types.LONGVARCHAR : {
248
// out.writeIntData(colSize[i]);
249
// }
250
// }
251
out.writeIntData(encodeTableColumnAttrs(i));
252             out.writeString(catalogNames[i] == null ? ""
253                                                     : catalogNames[i]);
254             out.writeString(schemaNames[i] == null ? ""
255                                                    : schemaNames[i]);
256         }
257
258         private int encodeTableColumnAttrs(int i) {
259
260             int out = colNullable[i]; // always between 0x00 and 0x02
261

262             if (isIdentity[i]) {
263                 out |= 0x00000010;
264             }
265
266             if (isWritable[i]) {
267                 out |= 0x00000020;
268             }
269
270             return out;
271         }
272
273         private void readTableColumnAttrs(RowInputBinary in,
274                                           int i)
275                                           throws IOException JavaDoc, HsqlException {
276
277             decodeTableColumnAttrs(in.readIntData(), i);
278
279             catalogNames[i] = in.readString();
280             schemaNames[i] = in.readString();
281         }
282
283         ResultMetaData(RowInputBinary in,
284                        int mode) throws HsqlException, IOException JavaDoc {
285
286             int l = in.readIntData();
287
288             prepareData(l);
289
290             if (mode == ResultConstants.PARAM_META_DATA) {
291                 isParameterDescription = true;
292                 paramMode = new int[l];
293             }
294
295             for (int i = 0; i < l; i++) {
296                 colTypes[i] = in.readType();
297
298                 // fredt - 1.8.0 added
299
colSizes[i] = in.readIntData();
300                 colScales[i] = in.readIntData();
301                 colLabels[i] = in.readString();
302                 tableNames[i] = in.readString();
303                 colNames[i] = in.readString();
304                 classNames[i] = in.readString();
305
306                 if (isTableColumn(i)) {
307                     readTableColumnAttrs(in, i);
308                 }
309
310                 if (mode == ResultConstants.PARAM_META_DATA) {
311                     paramMode[i] = in.readIntData();
312                 }
313             }
314         }
315
316         void write(RowOutputBinary out,
317                    int colCount) throws HsqlException, IOException JavaDoc {
318
319             out.writeIntData(colCount);
320
321             for (int i = 0; i < colCount; i++) {
322                 out.writeType(colTypes[i]);
323
324                 // fredt - 1.8.0 added
325
out.writeIntData(colSizes[i]);
326                 out.writeIntData(colScales[i]);
327                 out.writeString(colLabels[i] == null ? ""
328                                                      : colLabels[i]);
329                 out.writeString(tableNames[i] == null ? ""
330                                                       : tableNames[i]);
331                 out.writeString(colNames[i] == null ? ""
332                                                     : colNames[i]);
333                 out.writeString(classNames[i] == null ? ""
334                                                       : classNames[i]);
335
336                 if (isTableColumn(i)) {
337                     writeTableColumnAttrs(out, i);
338                 }
339
340                 if (isParameterDescription) {
341                     out.writeIntData(paramMode[i]);
342                 }
343             }
344         }
345     }
346
347     /**
348      * General constructor
349      */

350     public Result(int type) {
351
352         mode = type;
353
354 /*
355         if (type == ResultConstants.MULTI) {
356             isMulti = true;
357         }
358 */

359         if (type == ResultConstants.DATA
360                 || type == ResultConstants.PARAM_META_DATA
361                 || type == ResultConstants.SQLEXECUTE
362                 || type == ResultConstants.SETSESSIONATTR) {
363             metaData = new ResultMetaData();
364         }
365     }
366
367     Result(ResultMetaData md) {
368
369         mode = ResultConstants.DATA;
370         significantColumns = md.colTypes.length;
371         metaData = md;
372     }
373
374 // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
375

376     /**
377      * Constructor for errors
378      *
379      * @param error error message
380      * @param state sql state
381      * @param code vendor code
382      */

383     Result(String JavaDoc error, String JavaDoc state, int code) {
384
385         mode = ResultConstants.ERROR;
386         mainString = error;
387         subString = state;
388         statementID = code;
389         subSubString = "";
390     }
391
392     /**
393      * Only used with DATA and PARAM_META_DATA results
394      *
395      * @param columns
396      */

397     Result(int type, int columns) {
398
399         metaData = new ResultMetaData();
400
401         metaData.prepareData(columns);
402
403         if (type == ResultConstants.PARAM_META_DATA) {
404             metaData.isParameterDescription = true;
405             metaData.paramMode = new int[columns];
406         }
407
408         mode = type;
409         significantColumns = columns;
410     }
411
412     /**
413      * For BATCHEXECUTE and BATCHEXECDIRECT
414      */

415     public Result(int type, int[] types, int id) {
416
417         mode = type;
418         metaData = new ResultMetaData();
419         metaData.colTypes = types;
420         significantColumns = types.length;
421         statementID = id;
422     }
423
424     /**
425      * Constructor declaration
426      *
427      * @param in
428      * @exception HsqlException Description of the Exception
429      */

430     Result(RowInputBinary in) throws HsqlException {
431
432         try {
433             mode = in.readIntData();
434
435             if (mode == ResultConstants.MULTI) {
436                 readMultiResult(in);
437
438                 return;
439             }
440
441             databaseID = in.readIntData();
442             sessionID = in.readIntData();
443
444             switch (mode) {
445
446                 case ResultConstants.GETSESSIONATTR :
447                 case ResultConstants.SQLDISCONNECT :
448                 case ResultConstants.SQLSTARTTRAN :
449                 case ResultConstants.HSQLRESETSESSION :
450                     break;
451
452                 case ResultConstants.SQLPREPARE :
453                     setStatementType(in.readIntData());
454
455                     mainString = in.readString();
456                     break;
457
458                 case ResultConstants.PREPARE_ACK :
459                 case ResultConstants.SQLFREESTMT :
460                     statementID = in.readIntData();
461                     break;
462
463                 case ResultConstants.SQLEXECDIRECT :
464                     updateCount = in.readIntData();
465                     statementID = in.readIntData();
466                     mainString = in.readString();
467                     break;
468
469                 case ResultConstants.ERROR :
470                 case ResultConstants.SQLCONNECT :
471                     mainString = in.readString();
472                     subString = in.readString();
473                     subSubString = in.readString();
474                     statementID = in.readIntData();
475
476 // throw Trace.getError(string, code);
477
break;
478
479                 case ResultConstants.UPDATECOUNT :
480                     updateCount = in.readIntData();
481                     break;
482
483                 case ResultConstants.SQLENDTRAN : {
484                     int type = in.readIntData();
485
486                     setEndTranType(type); // endtran type
487

488                     switch (type) {
489
490                         case ResultConstants.SAVEPOINT_NAME_RELEASE :
491                         case ResultConstants.SAVEPOINT_NAME_ROLLBACK :
492                             mainString = in.readString(); // savepoint name
493
}
494
495                     break;
496                 }
497                 case ResultConstants.BATCHEXECUTE :
498                 case ResultConstants.BATCHEXECDIRECT :
499                 case ResultConstants.SQLEXECUTE :
500                 case ResultConstants.SETSESSIONATTR : {
501                     updateCount = in.readIntData();
502                     statementID = in.readIntData();
503
504                     int l = in.readIntData();
505
506                     metaData = new ResultMetaData(l);
507                     significantColumns = l;
508
509                     for (int i = 0; i < l; i++) {
510                         metaData.colTypes[i] = in.readType();
511                     }
512
513                     int count = in.readIntData();
514
515                     while (count-- > 0) {
516                         add(in.readData(metaData.colTypes));
517                     }
518
519                     break;
520                 }
521                 case ResultConstants.DATA :
522                 case ResultConstants.PARAM_META_DATA : {
523                     metaData = new ResultMetaData(in, mode);
524                     significantColumns = metaData.colLabels.length;
525
526                     int count = in.readIntData();
527
528                     while (count-- > 0) {
529                         add(in.readData(metaData.colTypes));
530                     }
531
532                     break;
533                 }
534                 case ResultConstants.SQLSETCONNECTATTR : {
535                     int type = in.readIntData(); // attr type
536

537                     setConnectionAttrType(type);
538
539                     switch (type) {
540
541                         case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
542                             mainString = in.readString(); // savepoint name
543

544                         // case ResultConstants.SQL_ATTR_AUTO_IPD :
545
// - always true
546
// default: throw - case never happens
547
}
548
549                     break;
550                 }
551                 default :
552                     throw new HsqlException(
553                         Trace.getMessage(
554                             Trace.Result_Result, true, new Object JavaDoc[]{
555                                 new Integer JavaDoc(mode) }), null, 0);
556             }
557         } catch (IOException JavaDoc e) {
558             throw Trace.error(Trace.TRANSFER_CORRUPTED);
559         }
560     }
561
562     static Result newSingleColumnResult(String JavaDoc colName, int colType) {
563
564         Result result = new Result(ResultConstants.DATA, 1);
565
566         result.metaData.colNames[0] = colName;
567         result.metaData.colLabels[0] = colName;
568         result.metaData.tableNames[0] = "";
569         result.metaData.colTypes[0] = colType;
570
571         return result;
572     }
573
574     static Result newPrepareResponse(int csid, Result rsmd, Result pmd) {
575
576         Result out;
577         Result pack;
578
579         out = new Result(ResultConstants.MULTI);
580
581 // out.isMulti = true;
582
pack = new Result(ResultConstants.PREPARE_ACK);
583         pack.statementID = csid;
584
585         out.add(new Object JavaDoc[]{ pack });
586         out.add(new Object JavaDoc[]{ rsmd });
587         out.add(new Object JavaDoc[]{ pmd });
588
589         return out;
590     }
591
592     static Result newParameterDescriptionResult(int len) {
593
594         Result r = new Result(ResultConstants.PARAM_META_DATA, len);
595
596         r.metaData.isParameterDescription = true;
597         r.metaData.paramMode = new int[len];
598
599         return r;
600     }
601
602     public static Result newFreeStmtRequest(int statementID) {
603
604         Result r = new Result(ResultConstants.SQLFREESTMT);
605
606         r.statementID = statementID;
607
608         return r;
609     }
610
611     static Result newExecuteDirectRequest(String JavaDoc sql) {
612
613         Result out;
614
615         out = new Result(ResultConstants.SQLEXECDIRECT);
616
617         out.setMainString(sql);
618
619         return out;
620     }
621
622     public static Result newReleaseSavepointRequest(String JavaDoc name) {
623
624         Result out;
625
626         out = new Result(ResultConstants.SQLENDTRAN);
627
628         out.setMainString(name);
629         out.setEndTranType(ResultConstants.SAVEPOINT_NAME_RELEASE);
630
631         return out;
632     }
633
634     public static Result newRollbackToSavepointRequest(String JavaDoc name) {
635
636         Result out;
637
638         out = new Result(ResultConstants.SQLENDTRAN);
639
640         out.setMainString(name);
641         out.setEndTranType(ResultConstants.SAVEPOINT_NAME_ROLLBACK);
642
643         return out;
644     }
645
646     public static Result newSetSavepointRequest(String JavaDoc name) {
647
648         Result out;
649
650         out = new Result(ResultConstants.SQLSETCONNECTATTR);
651
652         out.setConnectionAttrType(ResultConstants.SQL_ATTR_SAVEPOINT_NAME);
653         out.setMainString(name);
654
655         return out;
656     }
657
658     /**
659      * Method declaration
660      *
661      * @return
662      */

663     public int getSize() {
664         return size;
665     }
666
667     /**
668      * Method declaration
669      *
670      * @param columns
671      */

672     void setColumnCount(int columns) {
673         significantColumns = columns;
674     }
675
676     /**
677      * Method declaration
678      *
679      * @return
680      */

681     public int getColumnCount() {
682         return significantColumns;
683     }
684
685     /**
686      * Append Result argument to this.
687      *
688      * @param a
689      */

690     void append(Result a) {
691
692         if (a.rRoot == null) {
693             return;
694         }
695
696         if (rRoot == null) {
697             rRoot = a.rRoot;
698         } else {
699             rTail.next = a.rRoot;
700         }
701
702         rTail = a.rTail;
703         size += a.size;
704     }
705
706     void addAll(Result r) {
707
708         if (r == null) {
709             return;
710         }
711
712         Record from = r.rRoot;
713
714         while (from != null) {
715             add(from.data);
716
717             from = from.next;
718         }
719     }
720
721     public void clear() {
722
723         rRoot = null;
724         rTail = null;
725         size = 0;
726     }
727
728     public boolean isEmpty() {
729         return rRoot == null;
730     }
731
732     /**
733      * Method declaration
734      *
735      * @param a
736      */

737     void setRows(Result a) {
738
739         if (a == null) {
740             rRoot = null;
741             rTail = null;
742             size = 0;
743         } else {
744             rRoot = a.rRoot;
745             rTail = a.rTail;
746             size = a.size;
747         }
748     }
749
750     /**
751      * Method declaration
752      *
753      * @param d
754      */

755     public void add(Object JavaDoc[] d) {
756
757         Record r = new Record();
758
759         r.data = d;
760
761         if (rRoot == null) {
762             rRoot = r;
763         } else {
764             rTail.next = r;
765         }
766
767         rTail = r;
768
769         size++;
770     }
771
772     /**
773      * Method declaration
774      *
775      * @param limitstart number of records to discard at the head
776      * @param limitcount number of records to keep, all the rest if 0
777      */

778
779 // fredt@users 20020130 - patch 1.7.0 by fredt
780
// rewritten and moved from Select.java
781
void trimResult(int limitstart, int limitcount) {
782
783         Record n = rRoot;
784
785         if (n == null) {
786             return;
787         }
788
789         if (limitstart >= size) {
790             size = 0;
791             rRoot = rTail = null;
792
793             return;
794         }
795
796         size -= limitstart;
797
798         for (int i = 0; i < limitstart; i++) {
799             n = n.next;
800
801             if (n == null) {
802
803                 // if iSize is consistent this block will never be reached
804
size = 0;
805                 rRoot = rTail = n;
806
807                 return;
808             }
809         }
810
811         rRoot = n;
812
813         if (limitcount == 0 || limitcount >= size) {
814             return;
815         }
816
817         for (int i = 1; i < limitcount; i++) {
818             n = n.next;
819
820             if (n == null) {
821
822                 // if iSize is consistent this block will never be reached
823
return;
824             }
825         }
826
827         size = limitcount;
828         n.next = null;
829         rTail = n;
830     }
831
832     /**
833      * Removes duplicate rows on the basis of comparing the singificant
834      * columns of the rows in the result.
835      *
836      * @throws HsqlException
837      */

838     void removeDuplicates(Session session) throws HsqlException {
839         removeDuplicates(session, significantColumns);
840     }
841
842     /**
843      * Removes duplicate rows on the basis of comparing the first columnCount
844      * columns of rows in the result.
845      *
846      * @throws HsqlException
847      */

848
849 // fredt@users 20020130 - patch 1.7.0 by fredt
850
// to ensure consistency of r.rTail r.iSize in all set operations
851
void removeDuplicates(Session session,
852                           int columnCount) throws HsqlException {
853
854         if (rRoot == null) {
855             return;
856         }
857
858         int[] order = new int[columnCount];
859         int[] way = new int[columnCount];
860
861         for (int i = 0; i < columnCount; i++) {
862             order[i] = i;
863             way[i] = 1;
864         }
865
866         sortResult(session, order, way);
867
868         Record n = rRoot;
869
870         for (;;) {
871             Record next = n.next;
872
873             if (next == null) {
874                 break;
875             }
876
877             if (compareRecord(session, n.data, next.data, columnCount) == 0) {
878                 n.next = next.next;
879
880                 size--;
881             } else {
882                 n = next;
883             }
884         }
885
886         rTail = n;
887     }
888
889     /**
890      * Removes duplicates then removes the contents of the second result
891      * from this one base on first columnCount of the rows in each result.
892      *
893      * @param minus
894      * @throws HsqlException
895      */

896     void removeSecond(Session session, Result minus,
897                       int columnCount) throws HsqlException {
898
899         removeDuplicates(session, columnCount);
900         minus.removeDuplicates(session, columnCount);
901
902         Record n = rRoot;
903         Record last = rRoot;
904         boolean rootr = true; // checking rootrecord
905
Record n2 = minus.rRoot;
906         int i = 0;
907
908         while (n != null && n2 != null) {
909             i = compareRecord(session, n.data, n2.data, columnCount);
910
911             if (i == 0) {
912                 if (rootr) {
913                     rRoot = last = n.next;
914                 } else {
915                     last.next = n.next;
916                 }
917
918                 n = n.next;
919
920                 size--;
921             } else if (i > 0) { // r > minus
922
n2 = n2.next;
923             } else { // r < minus
924
last = n;
925                 rootr = false;
926                 n = n.next;
927             }
928         }
929
930         for (; n != null; ) {
931             last = n;
932             n = n.next;
933         }
934
935         rTail = last;
936     }
937
938     /**
939      * Removes all duplicate rows then removes all rows that are not shared
940      * between this and the other result, based on comparing the first
941      * columnCount columns of each result.
942      *
943      * @param r2
944      * @throws HsqlException
945      */

946     void removeDifferent(Session session, Result r2,
947                          int columnCount) throws HsqlException {
948
949         removeDuplicates(session, columnCount);
950         r2.removeDuplicates(session, columnCount);
951
952         Record n = rRoot;
953         Record last = rRoot;
954         boolean rootr = true; // checking rootrecord
955
Record n2 = r2.rRoot;
956         int i = 0;
957
958         size = 0;
959
960         while (n != null && n2 != null) {
961             i = compareRecord(session, n.data, n2.data, columnCount);
962
963             if (i == 0) { // same rows
964
if (rootr) {
965                     rRoot = n; // make this the first record
966
} else {
967                     last.next = n; // this is next record in resultset
968
}
969
970                 rootr = false;
971                 last = n; // this is last record in resultset
972
n = n.next;
973                 n2 = n2.next;
974
975                 size++;
976             } else if (i > 0) { // r > r2
977
n2 = n2.next;
978             } else { // r < r2
979
n = n.next;
980             }
981         }
982
983         if (rootr) { // if no lines in resultset
984
rRoot = null; // then return null
985
last = null;
986         } else {
987             last.next = null; // else end resultset
988
}
989
990         rTail = last;
991     }
992
993     /**
994      * Method declaration
995      *
996      * @param order
997      * @param way
998      * @throws HsqlException
999      */

1000    void sortResult(Session session, final int[] order,
1001                    final int[] way) throws HsqlException {
1002
1003        if (rRoot == null || rRoot.next == null) {
1004            return;
1005        }
1006
1007        Record source0, source1;
1008        Record[] target = new Record[2];
1009        Record[] targetlast = new Record[2];
1010        int dest = 0;
1011        Record n = rRoot;
1012
1013        while (n != null) {
1014            Record next = n.next;
1015
1016            n.next = target[dest];
1017            target[dest] = n;
1018            n = next;
1019            dest ^= 1;
1020        }
1021
1022        for (int blocksize = 1; target[1] != null; blocksize <<= 1) {
1023            source0 = target[0];
1024            source1 = target[1];
1025            target[0] = target[1] = targetlast[0] = targetlast[1] = null;
1026
1027            for (dest = 0; source0 != null; dest ^= 1) {
1028                int n0 = blocksize,
1029                    n1 = blocksize;
1030
1031                while (true) {
1032                    if (n0 == 0 || source0 == null) {
1033                        if (n1 == 0 || source1 == null) {
1034                            break;
1035                        }
1036
1037                        n = source1;
1038                        source1 = source1.next;
1039
1040                        n1--;
1041                    } else if (n1 == 0 || source1 == null) {
1042                        n = source0;
1043                        source0 = source0.next;
1044
1045                        n0--;
1046                    } else if (compareRecord(session, source0.data, source1
1047                            .data, order, way) > 0) {
1048                        n = source1;
1049                        source1 = source1.next;
1050
1051                        n1--;
1052                    } else {
1053                        n = source0;
1054                        source0 = source0.next;
1055
1056                        n0--;
1057                    }
1058
1059                    if (target[dest] == null) {
1060                        target[dest] = n;
1061                    } else {
1062                        targetlast[dest].next = n;
1063                    }
1064
1065                    targetlast[dest] = n;
1066                    n.next = null;
1067                }
1068            }
1069        }
1070
1071        rRoot = target[0];
1072        rTail = targetlast[0];
1073    }
1074
1075    /**
1076     * Method declaration
1077     *
1078     * @param a
1079     * @param b
1080     * @param order
1081     * @param way
1082     * @return -1, 0, +1
1083     * @throws HsqlException
1084     */

1085    private int compareRecord(Session session, Object JavaDoc[] a, final Object JavaDoc[] b,
1086                              final int[] order,
1087                              int[] way) throws HsqlException {
1088
1089        int i = Column.compare(session.database.collation, a[order[0]],
1090                               b[order[0]], metaData.colTypes[order[0]]);
1091
1092        if (i == 0) {
1093            for (int j = 1; j < order.length; j++) {
1094                i = Column.compare(session.database.collation, a[order[j]],
1095                                   b[order[j]], metaData.colTypes[order[j]]);
1096
1097                if (i != 0) {
1098                    return i * way[j];
1099                }
1100            }
1101        }
1102
1103        return i * way[0];
1104    }
1105
1106    /**
1107     * Method declaration
1108     *
1109     * @param a
1110     * @param b
1111     * @param len
1112     * @return -1, 0, +1
1113     * @throws HsqlException
1114     */

1115    private int compareRecord(Session session, Object JavaDoc[] a, Object JavaDoc[] b,
1116                              int len) throws HsqlException {
1117
1118        for (int j = 0; j < len; j++) {
1119            int i = Column.compare(session.database.collation, a[j], b[j],
1120                                   metaData.colTypes[j]);
1121
1122            if (i != 0) {
1123                return i;
1124            }
1125        }
1126
1127        return 0;
1128    }
1129
1130    /**
1131     * Result structure used for set/get session attributes
1132     */

1133    static Result newSessionAttributesResult() {
1134
1135        Result r = new Result(ResultConstants.DATA, 7);
1136
1137        r.metaData.colNames = r.metaData.colLabels = r.metaData.tableNames =
1138            new String JavaDoc[] {
1139            "", "", "", "", "", "", ""
1140        };
1141        r.metaData.colTypes = new int[] {
1142            Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.INTEGER,
1143            Types.BOOLEAN, Types.BOOLEAN, Types.BOOLEAN
1144        };
1145
1146        return r;
1147    }
1148
1149    void write(RowOutputBinary out) throws IOException JavaDoc, HsqlException {
1150
1151        if (mode == ResultConstants.MULTI) {
1152            writeMulti(out);
1153
1154            return;
1155        }
1156
1157        int startPos = out.size();
1158
1159        out.writeSize(0);
1160        out.writeIntData(mode);
1161        out.writeIntData(databaseID);
1162        out.writeIntData(sessionID);
1163
1164        switch (mode) {
1165
1166            case ResultConstants.GETSESSIONATTR :
1167            case ResultConstants.SQLDISCONNECT :
1168            case ResultConstants.SQLSTARTTRAN :
1169            case ResultConstants.HSQLRESETSESSION :
1170                break;
1171
1172            case ResultConstants.SQLPREPARE :
1173
1174                // Allows the engine side to fast-fail prepare of non-CALL
1175
// statement against a CallableStatement object and CALL
1176
// statement against PreparedStatement.
1177
//
1178
// May be useful in the future for other things
1179
out.writeIntData(getStatementType());
1180                out.writeString(mainString);
1181                break;
1182
1183            case ResultConstants.PREPARE_ACK :
1184            case ResultConstants.SQLFREESTMT :
1185                out.writeIntData(statementID);
1186                break;
1187
1188            case ResultConstants.SQLEXECDIRECT :
1189                out.writeIntData(updateCount);
1190                out.writeIntData(statementID); // currently unused
1191
out.writeString(mainString);
1192                break;
1193
1194            case ResultConstants.ERROR :
1195            case ResultConstants.SQLCONNECT :
1196                out.writeString(mainString);
1197                out.writeString(subString);
1198                out.writeString(subSubString);
1199                out.writeIntData(statementID);
1200                break;
1201
1202            case ResultConstants.UPDATECOUNT :
1203                out.writeIntData(updateCount);
1204                break;
1205
1206            case ResultConstants.SQLENDTRAN : {
1207                int type = getEndTranType();
1208
1209                out.writeIntData(type); // endtran type
1210

1211                switch (type) {
1212
1213                    case ResultConstants.SAVEPOINT_NAME_RELEASE :
1214                    case ResultConstants.SAVEPOINT_NAME_ROLLBACK :
1215                        out.writeString(mainString); // savepoint name
1216

1217                    // default; // do nothing
1218
}
1219
1220                break;
1221            }
1222            case ResultConstants.BATCHEXECUTE :
1223            case ResultConstants.BATCHEXECDIRECT :
1224            case ResultConstants.SQLEXECUTE :
1225            case ResultConstants.SETSESSIONATTR : {
1226                out.writeIntData(updateCount);
1227                out.writeIntData(statementID);
1228
1229                int l = significantColumns;
1230
1231                out.writeIntData(l);
1232
1233                for (int i = 0; i < l; i++) {
1234                    out.writeType(metaData.colTypes[i]);
1235                }
1236
1237                out.writeIntData(size);
1238
1239                Record n = rRoot;
1240
1241                while (n != null) {
1242                    out.writeData(l, metaData.colTypes, n.data, null, null);
1243
1244                    n = n.next;
1245                }
1246
1247                break;
1248            }
1249            case ResultConstants.DATA :
1250            case ResultConstants.PARAM_META_DATA : {
1251                metaData.write(out, significantColumns);
1252                out.writeIntData(size);
1253
1254                Record n = rRoot;
1255
1256                while (n != null) {
1257                    out.writeData(significantColumns, metaData.colTypes,
1258                                  n.data, null, null);
1259
1260                    n = n.next;
1261                }
1262
1263                break;
1264            }
1265            case ResultConstants.SQLSETCONNECTATTR : {
1266                int type = getConnectionAttrType();
1267
1268                out.writeIntData(type); // attr type
1269

1270                switch (type) {
1271
1272                    case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
1273                        out.writeString(mainString); // savepoint name
1274

1275                    // case ResultConstants.SQL_ATTR_AUTO_IPD // always true
1276
// default: // throw, but case never happens
1277
}
1278
1279                break;
1280            }
1281            default :
1282                throw new HsqlException(
1283                    Trace.getMessage(
1284                        Trace.Result_Result, true, new Object JavaDoc[]{
1285                            new Integer JavaDoc(mode) }), null, 0);
1286        }
1287
1288        out.writeIntData(out.size(), startPos);
1289    }
1290
1291    void readMultiResult(RowInputBinary in)
1292    throws HsqlException, IOException JavaDoc {
1293
1294        mode = ResultConstants.MULTI;
1295        databaseID = in.readIntData();
1296        sessionID = in.readIntData();
1297
1298        int count = in.readIntData();
1299
1300        for (int i = 0; i < count; i++) {
1301
1302            // Currently required for the outer result, but can simply
1303
// be ignored for sub-results
1304
in.readIntData();
1305            add(new Object JavaDoc[]{ new Result(in) });
1306        }
1307    }
1308
1309    private void writeMulti(RowOutputBinary out)
1310    throws IOException JavaDoc, HsqlException {
1311
1312        int startPos = out.size();
1313
1314        out.writeSize(0);
1315        out.writeIntData(mode);
1316        out.writeIntData(databaseID);
1317        out.writeIntData(sessionID);
1318        out.writeIntData(size);
1319
1320        Record n = rRoot;
1321
1322        while (n != null) {
1323            ((Result) n.data[0]).write(out);
1324
1325            n = n.next;
1326        }
1327
1328        out.writeIntData(out.size(), startPos);
1329    }
1330
1331    /**
1332     * Convenience method for writing, shared by Server side.
1333     */

1334    public static void write(Result r, RowOutputBinary rowout,
1335                             OutputStream JavaDoc dataout)
1336                             throws IOException JavaDoc, HsqlException {
1337
1338        rowout.reset();
1339        r.write(rowout);
1340        dataout.write(rowout.getOutputStream().getBuffer(), 0,
1341                      rowout.getOutputStream().size());
1342        dataout.flush();
1343    }
1344
1345    /**
1346     * Convenience method for reading, shared by Server side.
1347     */

1348    public static Result read(RowInputBinary rowin,
1349                              DataInput JavaDoc datain)
1350                              throws IOException JavaDoc, HsqlException {
1351
1352        int length = datain.readInt();
1353
1354        rowin.resetRow(0, length);
1355
1356        byte[] byteArray = rowin.getBuffer();
1357        int offset = 4;
1358
1359        datain.readFully(byteArray, offset, length - offset);
1360
1361        return new Result(rowin);
1362    }
1363
1364/** @todo fredt - move the messages to Trace.java */
1365    public Result(Throwable JavaDoc t, String JavaDoc statement) {
1366
1367        mode = ResultConstants.ERROR;
1368        exception = t;
1369
1370        if (t instanceof HsqlException) {
1371            HsqlException he = (HsqlException) t;
1372
1373            subString = he.getSQLState();
1374            mainString = he.getMessage();
1375
1376            if (statement != null) {
1377                mainString += " in statement [" + statement + "]";
1378            }
1379
1380            statementID = he.getErrorCode();
1381        } else if (t instanceof OutOfMemoryError JavaDoc) {
1382
1383            // At this point, we've nothing to lose by doing this
1384
System.gc();
1385
1386            subString = "S1000";
1387            mainString = "out of memory";
1388            statementID = Trace.OUT_OF_MEMORY;
1389        } else {
1390            subString = "S1000";
1391            mainString = Trace.getMessage(Trace.GENERAL_ERROR) + " " + t;
1392
1393            if (statement != null) {
1394                mainString += " in statement [" + statement + "]";
1395            }
1396
1397            statementID = Trace.GENERAL_ERROR;
1398        }
1399
1400        subSubString = "";
1401    }
1402
1403    public Throwable JavaDoc getException() {
1404        return exception;
1405    }
1406
1407    public int getStatementID() {
1408        return statementID;
1409    }
1410
1411    void setStatementID(int id) {
1412        statementID = id;
1413    }
1414
1415    public String JavaDoc getMainString() {
1416        return mainString;
1417    }
1418
1419    public void setMainString(String JavaDoc sql) {
1420        mainString = sql;
1421    }
1422
1423    public String JavaDoc getSubString() {
1424        return subString;
1425    }
1426
1427    public void setMaxRows(int count) {
1428        updateCount = count;
1429    }
1430
1431    public int getUpdateCount() {
1432        return updateCount;
1433    }
1434
1435    int getConnectionAttrType() {
1436        return updateCount;
1437    }
1438
1439    void setConnectionAttrType(int type) {
1440        updateCount = type;
1441    }
1442
1443    int getEndTranType() {
1444        return updateCount;
1445    }
1446
1447    void setEndTranType(int type) {
1448        updateCount = type;
1449    }
1450
1451    /** @todo fred - check this repurposing */
1452    public int[] getUpdateCounts() {
1453        return metaData.colTypes;
1454    }
1455
1456    Object JavaDoc[] getParameterData() {
1457        return (rRoot == null) ? null
1458                               : rRoot.data;
1459    }
1460
1461    public void setParameterData(Object JavaDoc[] data) {
1462
1463        if (rRoot == null) {
1464            rRoot = new Record();
1465        }
1466
1467        rRoot.data = data;
1468        rRoot.next = null;
1469        rTail = rRoot;
1470        size = 1;
1471    }
1472
1473    public void setResultType(int type) {
1474        mode = type;
1475    }
1476
1477    public void setStatementType(int type) {
1478        updateCount = type;
1479    }
1480
1481    public int getStatementType() {
1482        return updateCount;
1483    }
1484
1485    public int getType() {
1486        return mode;
1487    }
1488
1489    public boolean isData() {
1490        return mode == ResultConstants.DATA;
1491    }
1492
1493    public boolean isError() {
1494        return mode == ResultConstants.ERROR;
1495    }
1496
1497    public boolean isUpdateCount() {
1498        return mode == ResultConstants.UPDATECOUNT;
1499    }
1500
1501    public Iterator iterator() {
1502        return new ResultIterator();
1503    }
1504
1505    private class ResultIterator implements Iterator {
1506
1507        boolean removed;
1508        int counter;
1509        Record current = rRoot;
1510        Record last;
1511
1512        public boolean hasNext() {
1513            return counter < size;
1514        }
1515
1516        public Object JavaDoc next() {
1517
1518            if (hasNext()) {
1519                removed = false;
1520
1521                if (counter != 0) {
1522                    last = current;
1523                    current = current.next;
1524                }
1525
1526                counter++;
1527
1528                return current.data;
1529            }
1530
1531            throw new NoSuchElementException JavaDoc();
1532        }
1533
1534        public int nextInt() {
1535            throw new NoSuchElementException JavaDoc();
1536        }
1537
1538        public long nextLong() {
1539            throw new NoSuchElementException JavaDoc();
1540        }
1541
1542        public void remove() {
1543
1544            if (counter <= size && counter != 0 &&!removed) {
1545                removed = true;
1546
1547                if (current == rTail) {
1548                    rTail = last;
1549                }
1550
1551                if (current == rRoot) {
1552                    current = rRoot = rRoot.next;
1553                } else {
1554                    current = last;
1555                    last = null;
1556                    current.next = current.next.next;
1557                }
1558
1559                size--;
1560                counter--;
1561
1562                return;
1563            }
1564
1565            throw new NoSuchElementException JavaDoc();
1566        }
1567    }
1568}
1569
Popular Tags