KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > store > access > RowUtil


1 /*
2
3    Derby - Class org.apache.derby.iapi.store.access.RowUtil
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.store.access;
23
24 import org.apache.derby.iapi.services.monitor.Monitor;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.error.StandardException;
29 import org.apache.derby.iapi.services.io.Storable;
30 import org.apache.derby.iapi.types.DataValueDescriptor;
31 import org.apache.derby.iapi.services.io.FormatableBitSet;
32 import org.apache.derby.iapi.services.loader.InstanceGetter;
33
34 import org.apache.derby.iapi.store.raw.FetchDescriptor;
35
36 import java.lang.reflect.InvocationTargetException JavaDoc;
37
38 import java.util.Enumeration JavaDoc;
39 import java.util.Hashtable JavaDoc;
40 import java.util.Vector JavaDoc;
41
42 /**
43   A set of static utility methods to work with rows.
44   <P>
45   A row or partial row is described by two or three parameters.
46   <OL>
47   <LI>DataValueDescriptor[] row - an array of objects, one per column.
48   <LI>FormatableBitSet validColumns -
49       an indication of which objects in row map to which columns
50   </OL>
51   These objects can describe a complete row or a partial row. A partial row is
52   one where a sub-set (e.g. columns 0, 4 and 7) of the columns are supplied
53   for update, or requested to be fetched on a read. Here's an example
54   of code to set up a partial column list to fetch the 0th (type FOO),
55   4th (type BAR), and 7th (type MMM) columns from a row with 10 columns, note
56   that the format for a partial row changed from a "packed" representation
57   in the 3.0 release to a "sparse" representation in later releases:
58
59   <blockquote><pre>
60
61   // allocate/initialize the row
62   DataValueDescriptor row = new DataValueDescriptor[10]
63   row[0] = new FOO();
64   row[4] = new BAR();
65   row[7] = new MMM();
66   
67   // allocate/initialize the bit set
68   FormatableBitSet FormatableBitSet = new FormatableBitSet(10);
69   
70   FormatableBitSet.set(0);
71   FormatableBitSet.set(4);
72   FormatableBitSet.set(7);
73   </blockquote></pre>
74
75
76   <BR><B>Column mapping<B><BR>
77   When validColumns is null:
78   <UL>
79   <LI> The number of columns is given by row.length
80   <LI> Column N maps to row[N], where column numbers start at zero.
81   </UL>
82   <BR>
83   When validColumns is not null, then
84   <UL>
85   <LI> The number of requested columns is given by the number of bits set in
86        validColumns.
87   <LI> Column N is not in the partial row if validColumns.isSet(N)
88        returns false.
89   <LI> Column N is in the partial row if validColumns.isSet(N) returns true.
90   <LI> If column N is in the partial row then it maps to row[N].
91        If N >= row.length then the column is taken as non existent for an
92        insert or update, and not fetched on a fetch.
93   </UL>
94   If row.length is greater than the number of columns indicated by validColumns
95   the extra entries are ignored.
96
97 **/

98 public class RowUtil
99 {
100     private RowUtil() {}
101
102     /**
103         An object that can be used on a fetch to indicate no fields
104         need to be fetched.
105     */

106     public static final DataValueDescriptor[] EMPTY_ROW =
107         new DataValueDescriptor[0];
108
109     /**
110         An object that can be used on a fetch as a FormatableBitSet to indicate no fields
111         need to be fetched.
112     */

113     public static final FormatableBitSet EMPTY_ROW_BITSET =
114         new FormatableBitSet(0);
115
116     /**
117         An object that can be used on a fetch as a FormatableBitSet to indicate no fields
118         need to be fetched.
119     */

120     public static final FetchDescriptor EMPTY_ROW_FETCH_DESCRIPTOR =
121         new FetchDescriptor(0);
122
123     public static final FetchDescriptor[] ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS =
124         {EMPTY_ROW_FETCH_DESCRIPTOR,
125          new FetchDescriptor(1, 1),
126          new FetchDescriptor(2, 2),
127          new FetchDescriptor(3, 3),
128          new FetchDescriptor(4, 4),
129          new FetchDescriptor(5, 5),
130          new FetchDescriptor(6, 6),
131          new FetchDescriptor(7, 7)};
132
133
134     /**
135         Get the object for a column identifer (0 based) from a complete or
136         partial row.
137
138         @param row the row
139         @param columnList valid columns in the row
140         @param columnId which column to return (0 based)
141
142         @return the obejct for the column, or null if the column is not represented.
143     */

144     public static DataValueDescriptor getColumn(
145     DataValueDescriptor[] row,
146     FormatableBitSet columnList,
147     int columnId)
148     {
149
150         if (columnList == null)
151             return columnId < row.length ? row[columnId] : null;
152
153
154         if (!(columnList.getLength() > columnId && columnList.isSet(columnId)))
155             return null;
156
157         return columnId < row.length ? row[columnId] : null;
158
159     }
160
161     public static Object JavaDoc getColumn(
162     Object JavaDoc[] row,
163     FormatableBitSet columnList,
164     int columnId)
165     {
166
167         if (columnList == null)
168             return columnId < row.length ? row[columnId] : null;
169
170
171         if (!(columnList.getLength() > columnId && columnList.isSet(columnId)))
172             return null;
173
174         return columnId < row.length ? row[columnId] : null;
175
176     }
177
178     /**
179         Get a FormatableBitSet representing all the columns represented in
180         a qualifier list.
181
182         @return a FormatableBitSet describing the valid columns.
183     */

184     public static FormatableBitSet getQualifierBitSet(Qualifier[][] qualifiers)
185     {
186         FormatableBitSet qualifierColumnList = new FormatableBitSet();
187
188         if (qualifiers != null)
189         {
190             for (int i = 0; i < qualifiers.length; i++)
191             {
192                 for (int j = 0; j < qualifiers[i].length; j++)
193                 {
194                     int colId = qualifiers[i][j].getColumnId();
195
196                     // we are about to set bit colId, need length to be colId+1
197
qualifierColumnList.grow(colId+1);
198                     qualifierColumnList.set(colId);
199                 }
200             }
201         }
202
203         return qualifierColumnList;
204     }
205
206     /**
207      * Get the number of columns represented by a FormatableBitSet.
208      * <p>
209      * This is simply a count of the number of bits set in the FormatableBitSet.
210      * <p>
211      *
212      * @param maxColumnNumber Because the FormatableBitSet.size() can't be used as
213      * the number of columns, allow caller to tell
214      * the maximum column number if it knows.
215      * -1 means caller does not know.
216      * >=0 number is the largest column number.
217      *
218      * @param columnList valid columns in the row
219      *
220      * @return The number of columns represented in the FormatableBitSet.
221      **/

222     public static int getNumberOfColumns(
223     int maxColumnNumber,
224     FormatableBitSet columnList)
225     {
226         if (SanityManager.DEBUG)
227             SanityManager.ASSERT(columnList != null);
228
229         int max_col_number = columnList.getLength();
230
231         if (maxColumnNumber > 0 && maxColumnNumber < max_col_number)
232             max_col_number = maxColumnNumber;
233
234         int ret_num_cols = 0;
235
236         for (int i = 0; i < max_col_number; i++)
237         {
238             if (columnList.isSet(i))
239                 ret_num_cols++;
240         }
241
242         return(ret_num_cols);
243     }
244
245     /**
246         See if a row actually contains no columns.
247         Returns true if row is null or row.length is zero.
248
249         @return true if row is empty.
250     */

251     public static boolean isRowEmpty(
252     DataValueDescriptor[] row)
253     {
254
255         if (row == null)
256             return true;
257
258         if (row.length == 0)
259             return true;
260
261         return false;
262     }
263
264     /**
265         Return the column number of the first column out of range, or a number
266         less than zero if all columns are in range.
267     */

268     public static int columnOutOfRange(
269     DataValueDescriptor[] row,
270     FormatableBitSet columnList,
271     int maxColumns)
272     {
273
274         if (columnList == null) {
275             if (row.length > maxColumns)
276                 return maxColumns;
277
278             return -1;
279         }
280
281         int size = columnList.getLength();
282         for (int i = maxColumns; i < size; i++) {
283             if (columnList.isSet(i))
284                 return i;
285         }
286
287         return -1;
288     }
289
290     /**
291         Get the next valid column after or including start column.
292         Returns -1 if no valid columns exist after startColumn
293     */

294     public static int nextColumn(
295     Object JavaDoc[] row,
296     FormatableBitSet columnList,
297     int startColumn)
298     {
299
300         if (columnList != null) {
301
302             int size = columnList.getLength();
303
304             for (; startColumn < size; startColumn++) {
305                 if (columnList.isSet(startColumn)) {
306                     return startColumn;
307                 }
308             }
309
310             return -1;
311         }
312
313         if (row == null)
314             return -1;
315
316         return startColumn < row.length ? startColumn : -1;
317     }
318
319     /**
320      * Return a FetchDescriptor which describes a single column set.
321      * <p>
322      * This routine returns one of a set of constant FetchDescriptor's, and
323      * should not be altered by the caller.
324      **/

325     public static final FetchDescriptor getFetchDescriptorConstant(
326     int single_column_number)
327     {
328         if (single_column_number < ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS.length)
329         {
330             return(ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS[single_column_number]);
331         }
332         else
333         {
334             return(
335                 new FetchDescriptor(
336                     single_column_number, single_column_number));
337         }
338     }
339
340     /**************************************************************************
341      * Public Methods dealing with cloning and row copying util functions
342      **************************************************************************
343      */

344
345     /**
346      * Generate a row of InstanceGetter objects to be used to generate "empty" rows.
347      * <p>
348      * Generate an array of InstanceGetter objects which will be used to make
349      * repeated calls to newRowFromClassInfoTemplate(), to repeatedly and
350      * efficiently generate new rows. This is important for certain
351      * applications like the sorter and fetchSet which generate large numbers
352      * of "new" empty rows.
353      * <p>
354      *
355      * @return The new row.
356      *
357      * @param format_ids an array of format id's, one per column in row.
358      *
359      * @exception StandardException Standard exception policy.
360      **/

361     public static InstanceGetter[] newClassInfoTemplate(
362     FormatableBitSet column_list,
363     int[] format_ids)
364         throws StandardException
365     {
366         int num_cols = format_ids.length;
367         InstanceGetter[] ret_row = new InstanceGetter[num_cols];
368
369         int column_listSize =
370             (column_list == null) ? 0 : column_list.getLength();
371
372         for (int i = 0; i < num_cols; i++)
373         {
374             // does caller want this column?
375
if ((column_list != null) &&
376                 !((column_listSize > i) &&
377                 (column_list.isSet(i))))
378             {
379                 // no - column should be skipped.
380
}
381             else
382             {
383                 // yes - create the column
384

385                 // get empty instance of object identified by the format id.
386

387                 ret_row[i] = Monitor.classFromIdentifier(format_ids[i]);
388             }
389         }
390
391         return(ret_row);
392     }
393
394
395     private static void newRowFromClassInfoTemplateError()
396     {
397         if (SanityManager.DEBUG)
398             SanityManager.THROWASSERT(
399                 "unexpected error in newRowFromClassInfoTemplate()");
400     }
401
402     /**
403      * Generate an "empty" row from an array of classInfo objects.
404      * <p>
405      * Generate an array of new'd objects by using the getNewInstance()
406      * method on each of the InstanceGetter objects. It is more
407      * efficient to allocate new objects based on this "cache'd"
408      * InstanceGetter object than to call the Monitor to generate a new class
409      * from a format id.
410      * <p>
411      *
412      * @return The new row.
413      *
414      * @param classinfo_template An array of InstanceGetter objects each of
415      * which can be used to create a new instance
416      * of the appropriate type to build a new empty
417      * template row.
418      *
419      * @exception StandardException Standard exception policy.
420      **/

421     public static DataValueDescriptor[] newRowFromClassInfoTemplate(
422     InstanceGetter[] classinfo_template)
423         throws StandardException
424     {
425
426         DataValueDescriptor[] columns =
427             new DataValueDescriptor[classinfo_template.length];
428
429         try
430         {
431             for (int column_index = classinfo_template.length;
432                  column_index-- > 0;)
433             {
434                 if (classinfo_template[column_index] != null)
435                 {
436                     // get empty instance of DataValueDescriptor identified by
437
// the format id.
438
columns[column_index] = (DataValueDescriptor)
439                         classinfo_template[column_index].getNewInstance();
440                 }
441             }
442         }
443         catch (InstantiationException JavaDoc ie)
444         {
445             newRowFromClassInfoTemplateError();
446         }
447         catch (IllegalAccessException JavaDoc iae)
448         {
449             newRowFromClassInfoTemplateError();
450         }
451         catch (InvocationTargetException JavaDoc ite)
452         {
453             newRowFromClassInfoTemplateError();
454         }
455
456         return columns;
457     }
458
459
460     /**
461      * return string version of row.
462      * <p>
463      * For debugging only.
464      *
465      * @return The string version of row.
466      *
467      * @param row The row.
468      *
469      **/

470     public static String JavaDoc toString(Object JavaDoc[] row)
471     {
472         if (SanityManager.DEBUG)
473         {
474
475             String JavaDoc str = new String JavaDoc();
476
477             if (row != null)
478             {
479                 if (row.length == 0)
480                 {
481                     str = "empty row";
482                 }
483                 else
484                 {
485                     for (int i = 0; i < row.length; i++)
486                         str += "col[" + i + "]=" + row[i];
487                 }
488             }
489             else
490             {
491                 str = "row is null";
492             }
493
494             return(str);
495         }
496         else
497         {
498             return(null);
499         }
500     }
501
502     /**
503      * return string version of a HashTable returned from a FetchSet.
504      * <p>
505      *
506      * @return The string version of row.
507      *
508      *
509      **/

510
511     // For debugging only.
512
public static String JavaDoc toString(Hashtable JavaDoc hash_table)
513     {
514         if (SanityManager.DEBUG)
515         {
516             String JavaDoc str = new String JavaDoc();
517
518             Object JavaDoc row_or_vector;
519
520             for (Enumeration JavaDoc e = hash_table.elements(); e.hasMoreElements();)
521             {
522                 row_or_vector = e.nextElement();
523
524                 if (row_or_vector instanceof Object JavaDoc[])
525                 {
526                     // it's a row
527
str += RowUtil.toString((Object JavaDoc[]) row_or_vector);
528                     str += "\n";
529                 }
530                 else if (row_or_vector instanceof Vector JavaDoc)
531                 {
532                     // it's a vector
533
Vector JavaDoc vec = (Vector JavaDoc) row_or_vector;
534
535                     for (int i = 0; i < vec.size(); i++)
536                     {
537                         str +=
538                             "vec[" + i + "]:" +
539                             RowUtil.toString((Object JavaDoc[]) vec.elementAt(i));
540
541                         str += "\n";
542                     }
543                 }
544                 else
545                 {
546                     str += "BAD ENTRY\n";
547                 }
548             }
549             return(str);
550         }
551         else
552         {
553             return(null);
554         }
555     }
556
557     /**
558      * Process the qualifier list on the row, return true if it qualifies.
559      * <p>
560      * A two dimensional array is to be used to pass around a AND's and OR's in
561      * conjunctive normal form. The top slot of the 2 dimensional array is
562      * optimized for the more frequent where no OR's are present. The first
563      * array slot is always a list of AND's to be treated as described above
564      * for single dimensional AND qualifier arrays. The subsequent slots are
565      * to be treated as AND'd arrays or OR's. Thus the 2 dimensional array
566      * qual[][] argument is to be treated as the following, note if
567      * qual.length = 1 then only the first array is valid and it is and an
568      * array of and clauses:
569      *
570      * (qual[0][0] and qual[0][0] ... and qual[0][qual[0].length - 1])
571      * and
572      * (qual[1][0] or qual[1][1] ... or qual[1][qual[1].length - 1])
573      * and
574      * (qual[2][0] or qual[2][1] ... or qual[2][qual[2].length - 1])
575      * ...
576      * and
577      * (qual[qual.length - 1][0] or qual[1][1] ... or qual[1][2])
578      *
579      *
580      * @return true if the row qualifies.
581      *
582      * @param row The row being qualified.
583      * @param qual_list 2 dimensional array representing conjunctive
584      * normal form of simple qualifiers.
585      *
586      * @exception StandardException Standard exception policy.
587      **/

588     public static final boolean qualifyRow(
589     Object JavaDoc[] row,
590     Qualifier[][] qual_list)
591          throws StandardException
592     {
593         boolean row_qualifies = true;
594
595         if (SanityManager.DEBUG)
596         {
597             SanityManager.ASSERT(row != null);
598         }
599
600         // First do the qual[0] which is an array of qualifer terms.
601

602         if (SanityManager.DEBUG)
603         {
604             // routine should not be called if there is no qualifier
605
SanityManager.ASSERT(qual_list != null);
606             SanityManager.ASSERT(qual_list.length > 0);
607         }
608
609         for (int i = 0; i < qual_list[0].length; i++)
610         {
611             // process each AND clause
612

613             row_qualifies = false;
614
615             // process each OR clause.
616

617             Qualifier q = qual_list[0][i];
618
619             // Get the column from the possibly partial row, of the
620
// q.getColumnId()'th column in the full row.
621
DataValueDescriptor columnValue =
622                     (DataValueDescriptor) row[q.getColumnId()];
623
624             row_qualifies =
625                 columnValue.compare(
626                     q.getOperator(),
627                     q.getOrderable(),
628                     q.getOrderedNulls(),
629                     q.getUnknownRV());
630
631             if (q.negateCompareResult())
632                 row_qualifies = !row_qualifies;
633
634             // Once an AND fails the whole Qualification fails - do a return!
635
if (!row_qualifies)
636                 return(false);
637         }
638
639         // all the qual[0] and terms passed, now process the OR clauses
640

641         for (int and_idx = 1; and_idx < qual_list.length; and_idx++)
642         {
643             // loop through each of the "and" clause.
644

645             row_qualifies = false;
646
647             if (SanityManager.DEBUG)
648             {
649                 // Each OR clause must be non-empty.
650
SanityManager.ASSERT(qual_list[and_idx].length > 0);
651             }
652
653             for (int or_idx = 0; or_idx < qual_list[and_idx].length; or_idx++)
654             {
655                 // Apply one qualifier to the row.
656
Qualifier q = qual_list[and_idx][or_idx];
657                 int col_id = q.getColumnId();
658
659                 if (SanityManager.DEBUG)
660                 {
661                     SanityManager.ASSERT(
662                         (col_id < row.length),
663                         "Qualifier is referencing a column not in the row.");
664                 }
665
666                 // Get the column from the possibly partial row, of the
667
// q.getColumnId()'th column in the full row.
668
DataValueDescriptor columnValue =
669                     (DataValueDescriptor) row[q.getColumnId()];
670
671                 if (SanityManager.DEBUG)
672                 {
673                     if (columnValue == null)
674                         SanityManager.THROWASSERT(
675                             "1:row = " + RowUtil.toString(row) +
676                             "row.length = " + row.length +
677                             ";q.getColumnId() = " + q.getColumnId());
678                 }
679
680                 // do the compare between the column value and value in the
681
// qualifier.
682
row_qualifies =
683                     columnValue.compare(
684                             q.getOperator(),
685                             q.getOrderable(),
686                             q.getOrderedNulls(),
687                             q.getUnknownRV());
688
689                 if (q.negateCompareResult())
690                     row_qualifies = !row_qualifies;
691
692                 // SanityManager.DEBUG_PRINT("StoredPage.qual", "processing qual[" + and_idx + "][" + or_idx + "] = " + qual_list[and_idx][or_idx] );
693

694                 // SanityManager.DEBUG_PRINT("StoredPage.qual", "value = " + row_qualifies);
695

696                 // processing "OR" clauses, so as soon as one is true, break
697
// to go and process next AND clause.
698
if (row_qualifies)
699                     break;
700
701             }
702
703             // The qualifier list represented a set of "AND'd"
704
// qualifications so as soon as one is false processing is done.
705
if (!row_qualifies)
706                 break;
707         }
708
709         return(row_qualifies);
710     }
711
712 }
713
Popular Tags