Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/iapi/store/access/RowUtil.java


1   /*
2   
3      Derby - Class org.apache.derby.iapi.store.access.RowUtil
4   
5      Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.iapi.store.access;
22  
23  import org.apache.derby.iapi.services.monitor.Monitor;
24  
25  import org.apache.derby.iapi.services.sanity.SanityManager;
26  
27  import org.apache.derby.iapi.error.StandardException; 
28  import org.apache.derby.iapi.services.io.Storable;
29  import org.apache.derby.iapi.types.DataValueDescriptor;
30  import org.apache.derby.iapi.services.io.FormatableBitSet;
31  import org.apache.derby.iapi.services.loader.InstanceGetter;
32  
33  import org.apache.derby.iapi.store.raw.FetchDescriptor;
34  
35  import java.lang.reflect.InvocationTargetException;
36  
37  import java.util.Enumeration;
38  import java.util.Hashtable;
39  import java.util.Vector;
40  
41  /**
42    A set of static utility methods to work with rows.
43    <P>
44    A row or partial row is described by two or three parameters.
45    <OL>
46    <LI>DataValueDescriptor[] row - an array of objects, one per column.
47    <LI>FormatableBitSet validColumns - 
48        an indication of which objects in row map to which columns
49    </OL>
50    These objects can describe a complete row or a partial row. A partial row is 
51    one where a sub-set (e.g. columns 0, 4 and 7) of the columns are supplied 
52    for update, or requested to be fetched on a read.  Here's an example
53    of code to set up a partial column list to fetch the 0th (type FOO), 
54    4th (type BAR), and 7th (type MMM) columns from a row with 10 columns, note
55    that the format for a partial row changed from a "packed" representation
56    in the 3.0 release to a "sparse" representation in later releases:
57  
58    <blockquote><pre>
59  
60    // allocate/initialize the row 
61    DataValueDescriptor row = new DataValueDescriptor[10]
62    row[0] = new FOO();
63    row[4] = new BAR();
64    row[7] = new MMM();
65    
66    // allocate/initialize the bit set 
67    FormatableBitSet FormatableBitSet = new FormatableBitSet(10);
68    
69    FormatableBitSet.set(0);
70    FormatableBitSet.set(4);
71    FormatableBitSet.set(7);
72    </blockquote></pre>
73  
74  
75    <BR><B>Column mapping<B><BR>
76    When validColumns is null:
77    <UL>
78    <LI> The number of columns is given by row.length
79    <LI> Column N maps to row[N], where column numbers start at zero.
80    </UL>
81    <BR>
82    When validColumns is not null, then
83    <UL>
84    <LI> The number of requested columns is given by the number of bits set in 
85         validColumns.
86    <LI> Column N is not in the partial row if validColumns.isSet(N) 
87         returns false.
88    <LI> Column N is in the partial row if validColumns.isSet(N) returns true.
89    <LI> If column N is in the partial row then it maps to row[N].
90       If N >= row.length then the column is taken as non existent for an
91       insert or update, and not fetched on a fetch.
92    </UL>
93    If row.length is greater than the number of columns indicated by validColumns
94    the extra entries are ignored.
95  
96  **/
97  public class RowUtil
98  {
99    private RowUtil() {}
100 
101   /**
102     An object that can be used on a fetch to indicate no fields
103     need to be fetched.
104   */
105   public static final DataValueDescriptor[] EMPTY_ROW = 
106         new DataValueDescriptor[0];
107 
108   /**
109     An object that can be used on a fetch as a FormatableBitSet to indicate no fields
110     need to be fetched.
111   */
112   public static final FormatableBitSet EMPTY_ROW_BITSET  = 
113         new FormatableBitSet(0);
114 
115   /**
116     An object that can be used on a fetch as a FormatableBitSet to indicate no fields
117     need to be fetched.
118   */
119   public static final FetchDescriptor EMPTY_ROW_FETCH_DESCRIPTOR  = 
120         new FetchDescriptor(0);
121 
122   public static final FetchDescriptor[] ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS  =
123         {EMPTY_ROW_FETCH_DESCRIPTOR,
124          new FetchDescriptor(1, 1),
125          new FetchDescriptor(2, 2),
126          new FetchDescriptor(3, 3),
127          new FetchDescriptor(4, 4),
128          new FetchDescriptor(5, 5),
129          new FetchDescriptor(6, 6),
130          new FetchDescriptor(7, 7)};
131 
132 
133   /**
134     Get the object for a column identifer (0 based) from a complete or 
135         partial row.
136 
137     @param row the row
138     @param columnList valid columns in the row
139     @param columnId which column to return (0 based)
140 
141     @return the obejct for the column, or null if the column is not represented.
142   */
143   public static DataValueDescriptor getColumn(
144     DataValueDescriptor[]   row, 
145     FormatableBitSet                 columnList, 
146     int                     columnId) 
147     {
148 
149     if (columnList == null)
150       return columnId < row.length ? row[columnId] : null;
151 
152 
153     if (!(columnList.getLength() > columnId && columnList.isSet(columnId)))
154       return null;
155 
156         return columnId < row.length ? row[columnId] : null;
157 
158   }
159 
160   public static Object getColumn(
161     Object[]   row, 
162     FormatableBitSet                 columnList, 
163     int                     columnId) 
164     {
165 
166     if (columnList == null)
167       return columnId < row.length ? row[columnId] : null;
168 
169 
170     if (!(columnList.getLength() > columnId && columnList.isSet(columnId)))
171       return null;
172 
173         return columnId < row.length ? row[columnId] : null;
174 
175   }
176 
177   /**
178     Get a FormatableBitSet representing all the columns represented in
179     a qualifier list.
180 
181     @return a FormatableBitSet describing the valid columns.
182   */
183   public static FormatableBitSet getQualifierBitSet(Qualifier[][] qualifiers) 
184     {
185     FormatableBitSet qualifierColumnList = new FormatableBitSet();
186 
187     if (qualifiers != null) 
188         {
189       for (int i = 0; i < qualifiers.length; i++)
190       {
191                 for (int j = 0; j < qualifiers[i].length; j++)
192                 {
193                     int colId = qualifiers[i][j].getColumnId();
194 
195                     // we are about to set bit colId, need length to be colId+1
196                     qualifierColumnList.grow(colId+1);
197                     qualifierColumnList.set(colId);
198                 }
199       }
200     }
201 
202     return qualifierColumnList;
203   }
204 
205     /**
206      * Get the number of columns represented by a FormatableBitSet.
207      * <p>
208      * This is simply a count of the number of bits set in the FormatableBitSet.
209      * <p>
210      *
211      * @param maxColumnNumber Because the FormatableBitSet.size() can't be used as
212      *                        the number of columns, allow caller to tell
213      *                        the maximum column number if it knows.  
214      *                        -1  means caller does not know.
215      *                        >=0 number is the largest column number.
216      *                           
217      * @param columnList valid columns in the row
218      *
219    * @return The number of columns represented in the FormatableBitSet.
220      **/
221     public static int getNumberOfColumns(
222     int     maxColumnNumber,
223     FormatableBitSet  columnList)
224     {
225         if (SanityManager.DEBUG)
226             SanityManager.ASSERT(columnList != null);
227 
228         int max_col_number = columnList.getLength();
229 
230     if (maxColumnNumber > 0 && maxColumnNumber < max_col_number)
231       max_col_number = maxColumnNumber;
232 
233         int ret_num_cols = 0;
234 
235         for (int i = 0; i < max_col_number; i++)
236         {
237             if (columnList.isSet(i))
238                 ret_num_cols++;
239         }
240 
241         return(ret_num_cols);
242     }
243 
244   /**
245     See if a row actually contains no columns.
246     Returns true if row is null, row.length is null,
247     or columnList is not null but has not bits set.
248 
249     @return true if no columns are selected in this row.
250   */
251   public static boolean isRowEmpty(
252     DataValueDescriptor[]   row, 
253     FormatableBitSet                 columnList) 
254     {
255 
256     if (row == null)
257       return true;
258 
259     if (row.length == 0)
260       return true;
261 
262     if (columnList == null)
263       return false;
264 
265     int size = columnList.getLength();
266     for (int i = 0; i < size; i--) {
267       if (columnList.isSet(i))
268         return true;
269     }
270     return false;
271   }
272 
273   /**
274     Return the column number of the first column out of range, or a number
275         less than zero if all columns are in range.
276   */
277   public static int columnOutOfRange(
278     DataValueDescriptor[]   row, 
279     FormatableBitSet                 columnList, 
280     int                     maxColumns) 
281     {
282 
283     if (columnList == null) {
284       if (row.length > maxColumns)
285         return maxColumns;
286 
287       return -1;
288     }
289 
290     int size = columnList.getLength();
291     for (int i = maxColumns; i < size; i++) {
292       if (columnList.isSet(i))
293         return i;
294     }
295 
296     return -1;
297   }
298 
299   /**
300     Get the next valid column after or including start column.
301     Returns -1 if no valid columns exist after startColumn
302   */
303   public static int nextColumn(
304     Object[]   row, 
305     FormatableBitSet                 columnList, 
306     int                     startColumn) 
307     {
308 
309     if (columnList != null) {
310 
311       int size = columnList.getLength();
312 
313       for (; startColumn < size; startColumn++) {
314         if (columnList.isSet(startColumn)) {
315           return startColumn;
316         }
317       }
318 
319       return -1;
320     }
321 
322     if (row == null)
323       return -1;
324 
325     return startColumn < row.length ? startColumn : -1;
326   }
327 
328     /**
329      * Return a FetchDescriptor which describes a single column set.
330      * <p>
331      * This routine returns one of a set of constant FetchDescriptor's, and
332      * should not be altered by the caller.
333      **/
334     public static final FetchDescriptor getFetchDescriptorConstant(
335     int     single_column_number)
336     {
337         if (single_column_number < ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS.length)
338         {
339             return(ROWUTIL_FETCH_DESCRIPTOR_CONSTANTS[single_column_number]);
340         }
341         else
342         {
343             return(
344                 new FetchDescriptor(
345                     single_column_number, single_column_number));
346         }
347     }
348 
349     /**************************************************************************
350      * Public Methods dealing with cloning and row copying util functions
351      **************************************************************************
352      */
353 
354     /**
355      * Generate a row of InstanceGetter objects to be used to generate  "empty" rows.
356      * <p>
357      * Generate an array of InstanceGetter objects which will be used to make
358      * repeated calls to newRowFromClassInfoTemplate(), to repeatedly and
359      * efficiently generate new rows.  This is important for certain 
360      * applications like the sorter and fetchSet which generate large numbers
361      * of "new" empty rows.
362      * <p>
363      *
364    * @return The new row.
365      *
366      * @param format_ids an array of format id's, one per column in row.
367      *
368    * @exception  StandardException  Standard exception policy.
369      **/
370     public static InstanceGetter[] newClassInfoTemplate(
371     FormatableBitSet column_list,
372     int[]    format_ids) 
373         throws StandardException
374     {
375         int         num_cols = format_ids.length;
376         InstanceGetter[] ret_row  = new InstanceGetter[num_cols];
377 
378     int column_listSize = 
379             (column_list == null) ? 0 : column_list.getLength();
380 
381         for (int i = 0; i < num_cols; i++)
382         {
383             // does caller want this column?
384             if ((column_list != null)   && 
385                 !((column_listSize > i) && 
386                 (column_list.isSet(i))))
387             {
388                 // no - column should be skipped.
389             }
390             else
391             {
392                 // yes - create the column 
393 
394                 // get empty instance of object identified by the format id.
395 
396                 ret_row[i] = Monitor.classFromIdentifier(format_ids[i]);
397             }
398         }
399 
400         return(ret_row);
401     }
402 
403 
404     private static void newRowFromClassInfoTemplateError()
405     {
406         if (SanityManager.DEBUG)
407             SanityManager.THROWASSERT(
408                 "unexpected error in newRowFromClassInfoTemplate()");
409     }
410 
411     /**
412      * Generate an "empty" row from an array of classInfo objects.
413      * <p>
414      * Generate an array of new'd objects by using the getNewInstance()
415      * method on each of the InstanceGetter objects.  It is more
416      * efficient to allocate new objects based on this "cache'd"
417      * InstanceGetter object than to call the Monitor to generate a new class
418      * from a format id.
419      * <p>
420      *
421    * @return The new row.
422      *
423      * @param classinfo_template   An array of InstanceGetter objects each of 
424      *                             which can be used to create a new instance 
425      *                             of the appropriate type to build a new empty
426      *                             template row.
427      *
428    * @exception  StandardException  Standard exception policy.
429      **/
430     public static DataValueDescriptor[] newRowFromClassInfoTemplate(
431     InstanceGetter[]    classinfo_template) 
432         throws StandardException
433     {
434 
435         DataValueDescriptor[] columns = 
436             new DataValueDescriptor[classinfo_template.length];
437 
438         try
439         {
440             for (int column_index = classinfo_template.length; 
441                  column_index-- > 0;)
442             {
443                 if (classinfo_template[column_index] != null)
444                 {
445                     // get empty instance of DataValueDescriptor identified by 
446                     // the format id.
447                     columns[column_index] = (DataValueDescriptor) 
448                         classinfo_template[column_index].getNewInstance();
449                 }
450             }
451         }
452         catch (InstantiationException ie)
453         {
454             newRowFromClassInfoTemplateError();
455         }
456         catch (IllegalAccessException iae)
457         {
458             newRowFromClassInfoTemplateError();
459         }
460         catch (InvocationTargetException ite)
461         {
462             newRowFromClassInfoTemplateError();
463         }
464 
465     return columns;
466     }
467 
468 
469     /**
470      * return string version of row.
471      * <p>
472      * For debugging only. 
473      *
474    * @return The string version of row.
475      *
476      * @param row The row.
477      *
478      **/
479     public static String toString(Object[] row)
480     {
481         if (SanityManager.DEBUG)
482         {
483 
484             String str = new String();
485 
486             if (row != null)
487             {
488                 if (row.length == 0)
489                 {
490                     str = "empty row";
491                 }
492                 else
493                 {
494                     for (int i = 0; i < row.length; i++)
495                         str += "col[" + i + "]=" + row[i];
496                 }
497             }
498             else
499             {
500                 str = "row is null";
501             }
502 
503             return(str);
504         }
505         else
506         {
507             return(null);
508         }
509     }
510 
511     /**
512      * return string version of a HashTable returned from a FetchSet.
513      * <p>
514      *
515    * @return The string version of row.
516      *
517      *
518      **/
519 
520     // For debugging only. 
521     public static String toString(Hashtable hash_table)
522     {
523         if (SanityManager.DEBUG)
524         {
525             String str = new String();
526 
527             Object  row_or_vector;
528 
529             for (Enumeration e = hash_table.elements(); e.hasMoreElements();)
530             {
531                 row_or_vector = e.nextElement();
532 
533                 if (row_or_vector instanceof Object[])
534                 {
535                     // it's a row
536                     str += RowUtil.toString((Object[]) row_or_vector);
537                     str += "\n";
538                 }
539                 else if (row_or_vector instanceof Vector)
540                 {
541                     // it's a vector
542                     Vector vec = (Vector) row_or_vector;
543 
544                     for (int i = 0; i < vec.size(); i++)
545                     {
546                         str += 
547                             "vec[" + i + "]:" + 
548                             RowUtil.toString((Object[]) vec.elementAt(i));
549 
550                         str += "\n";
551                     }
552                 }
553                 else
554                 {
555                     str += "BAD ENTRY\n";
556                 }
557             }
558             return(str);
559         }
560         else
561         {
562             return(null);
563         }
564     }
565 
566     /**
567      * Process the qualifier list on the row, return true if it qualifies.
568      * <p>
569      * A two dimensional array is to be used to pass around a AND's and OR's in
570      * conjunctive normal form.  The top slot of the 2 dimensional array is 
571      * optimized for the more frequent where no OR's are present.  The first 
572      * array slot is always a list of AND's to be treated as described above 
573      * for single dimensional AND qualifier arrays.  The subsequent slots are 
574      * to be treated as AND'd arrays or OR's.  Thus the 2 dimensional array 
575      * qual[][] argument is to be treated as the following, note if 
576      * qual.length = 1 then only the first array is valid and it is and an 
577      * array of and clauses:
578      *
579      * (qual[0][0] and qual[0][0] ... and qual[0][qual[0].length - 1])
580      * and
581      * (qual[1][0] or  qual[1][1] ... or  qual[1][qual[1].length - 1])
582      * and
583      * (qual[2][0] or  qual[2][1] ... or  qual[2][qual[2].length - 1])
584      * ...
585      * and
586      * (qual[qual.length - 1][0] or  qual[1][1] ... or  qual[1][2])
587      *
588      * 
589    * @return true if the row qualifies.
590      *
591      * @param row               The row being qualified.
592      * @param qual_list         2 dimensional array representing conjunctive
593      *                          normal form of simple qualifiers.
594      *
595    * @exception  StandardException  Standard exception policy.
596      **/
597   public static final boolean qualifyRow(
598     Object[]        row, 
599     Qualifier[][]   qual_list)
600      throws StandardException
601   {
602         boolean     row_qualifies = true;
603 
604         if (SanityManager.DEBUG)
605         {
606             SanityManager.ASSERT(row != null);
607         }
608 
609         // First do the qual[0] which is an array of qualifer terms.
610 
611         if (SanityManager.DEBUG)
612         {
613             // routine should not be called if there is no qualifier
614             SanityManager.ASSERT(qual_list != null);
615             SanityManager.ASSERT(qual_list.length > 0);
616         }
617 
618         for (int i = 0; i < qual_list[0].length; i++)
619         {
620             // process each AND clause 
621 
622             row_qualifies = false;
623 
624             // process each OR clause.
625 
626             Qualifier q = qual_list[0][i];
627 
628             // Get the column from the possibly partial row, of the 
629             // q.getColumnId()'th column in the full row.
630             DataValueDescriptor columnValue = 
631                     (DataValueDescriptor) row[q.getColumnId()];
632 
633             row_qualifies =
634                 columnValue.compare(
635                     q.getOperator(),
636                     q.getOrderable(),
637                     q.getOrderedNulls(),
638                     q.getUnknownRV());
639 
640             if (q.negateCompareResult())
641                 row_qualifies = !row_qualifies;
642 
643             // Once an AND fails the whole Qualification fails - do a return!
644             if (!row_qualifies)
645                 return(false);
646         }
647 
648         // all the qual[0] and terms passed, now process the OR clauses
649 
650         for (int and_idx = 1; and_idx < qual_list.length; and_idx++)
651         {
652             // loop through each of the "and" clause.
653 
654             row_qualifies = false;
655 
656             if (SanityManager.DEBUG)
657             {
658                 // Each OR clause must be non-empty.
659                 SanityManager.ASSERT(qual_list[and_idx].length > 0);
660             }
661 
662             for (int or_idx = 0; or_idx < qual_list[and_idx].length; or_idx++)
663             {
664                 // Apply one qualifier to the row.
665                 Qualifier q      = qual_list[and_idx][or_idx];
666                 int       col_id = q.getColumnId();
667 
668                 if (SanityManager.DEBUG)
669                 {
670                     SanityManager.ASSERT(
671                         (col_id < row.length),
672                         "Qualifier is referencing a column not in the row.");
673                 }
674 
675                 // Get the column from the possibly partial row, of the 
676                 // q.getColumnId()'th column in the full row.
677                 DataValueDescriptor columnValue = 
678                     (DataValueDescriptor) row[q.getColumnId()];
679 
680                 if (SanityManager.DEBUG)
681                 {
682                     if (columnValue == null)
683                         SanityManager.THROWASSERT(
684                             "1:row = " + RowUtil.toString(row) +
685                             "row.length = " + row.length +
686                             ";q.getColumnId() = " + q.getColumnId());
687                 }
688 
689                 // do the compare between the column value and value in the
690                 // qualifier.
691                 row_qualifies = 
692                     columnValue.compare(
693                             q.getOperator(),
694                             q.getOrderable(),
695                             q.getOrderedNulls(),
696                             q.getUnknownRV());
697 
698                 if (q.negateCompareResult())
699                     row_qualifies = !row_qualifies;
700 
701                 // SanityManager.DEBUG_PRINT("StoredPage.qual", "processing qual[" + and_idx + "][" + or_idx + "] = " + qual_list[and_idx][or_idx] );
702 
703                 // SanityManager.DEBUG_PRINT("StoredPage.qual", "value = " + row_qualifies);
704 
705                 // processing "OR" clauses, so as soon as one is true, break
706                 // to go and process next AND clause.
707                 if (row_qualifies)
708                     break;
709 
710             }
711 
712             // The qualifier list represented a set of "AND'd" 
713             // qualifications so as soon as one is false processing is done.
714             if (!row_qualifies)
715                 break;
716         }
717 
718         return(row_qualifies);
719     }
720 
721 }