KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > data > StoredFieldHeader


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.data.StoredFieldHeader
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 package org.apache.derby.impl.store.raw.data;
22
23 import org.apache.derby.iapi.store.raw.RecordHandle;
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25
26 import java.io.IOException JavaDoc;
27 import java.io.EOFException JavaDoc;
28
29 import java.io.ObjectInput JavaDoc;
30 import java.io.OutputStream JavaDoc;
31
32 import org.apache.derby.iapi.services.io.ArrayInputStream;
33 import org.apache.derby.iapi.services.io.CompressedNumber;
34
35 import java.io.InputStream JavaDoc;
36
37 /**
38     A class to provide static methods to manipulate fields in the field header.
39
40     A class StoredPage uses to read/write field status and field data length.
41     No attributes exist in this class, this class provides a set of static
42     methods for writing field status and field data length, and for reading
43     field status and field data length.
44
45     <P><B>Stored Field Header Format</B><BR>
46     The field header is broken into two sections.
47     Only the Status byte is required to be there.
48     <PRE>
49     Field header format:
50     +--------+-------------------+
51     | status | <fieldDataLength> |
52     +--------+-------------------+
53     Overflow page and overflow id are stored as field data.
54     If the overflow bit in status is set, the field data is the overflow
55     information. When the overflow bit is not set in status, then,
56     fieldData is the actually user data for the field.
57     That means, field header consists only field status, and field data length.
58
59     A non-overflow field:
60     +--------+-------------------+-------------+
61     | status | <fieldDataLength> | <fieldData> |
62     +--------+-------------------+-------------+
63
64     An overflow field:
65     +--------+-------------------+-----------------+--------------+
66     | status | <fieldDataLength> | <overflow page> | <overflowID> |
67     +--------+-------------------+-----------------+--------------+
68
69     </PRE>
70     <BR><B>status</B><BR>
71     The status is 1 byte, it indicates the state of the field.
72
73     A FieldHeader can be in the following states:
74     NULL - if the field is NULL, no field data length is stored
75     OVERFLOW - indicates the field has been overflowed to another page.
76                   overflow page and overflow ID is stored at the end of the
77                   user data. field data length must be a number greater or
78                   equal to 0, indicating the length of the field that is stored
79                   on the current page.
80
81                   The format looks like this:
82                   +--------+-----------------+---------------+------------+
83                   |<status>|<fieldDataLength>|<overflow page>|<overflowID>|
84                   +--------+-----------------+---------------+------------+
85
86                   overflowPage will be written as compressed long,
87                   overflowId will be written as compressed Int
88
89     NONEXISTENT - the field no longer exists,
90                   e.g. column has been dropped during an alter table
91
92     EXTENSIBLE - the field is of user defined data type.
93                   The field may be tagged.
94                   
95     TAGGED - the field is TAGGED if and only if it is EXTENSIBLE.
96
97     FIXED - the field is FIXED if and only if it is used in the log
98                   records for version 1.2 and higher.
99
100     <BR><B>fieldDataLength</B><BR>
101     The fieldDataLength is only set if the field is not NULL. It is the length
102     of the field that is stored on the current page.
103     The fieldDataLength is a variable length CompressedInt.
104     <BR><B>overflowPage and overflowID</B><BR>
105     The overflowPage is a variable length CompressedLong, overflowID is a
106     variable Length CompressedInt.
107     They are only stored when the field state is OVERFLOW.
108     And they are not stored in the field header.
109     Instead, they are stored at the end of the field data.
110     The reason we do that is to save a copy if the field has to overflow.
111
112     <BR> MT - Mutable - Immutable identity - Thread Aware
113 */

114 public final class StoredFieldHeader
115 {
116
117     /**************************************************************************
118      * Constants of the class
119      **************************************************************************
120      */

121
122     // DO NOT use 0x80, some code reads byte into an int without masking the
123
// sign bit, so do not use the high bit in the byte for a field status.
124
private static final int FIELD_INITIAL = 0x00;
125     public static final int FIELD_NULL = 0x01;
126     public static final int FIELD_OVERFLOW = 0x02;
127     private static final int FIELD_NOT_NULLABLE = 0x04;
128     public static final int FIELD_EXTENSIBLE = 0x08;
129     public static final int FIELD_TAGGED = 0x10;
130     protected static final int FIELD_FIXED = 0x20;
131
132     public static final int FIELD_NONEXISTENT = (FIELD_NOT_NULLABLE | FIELD_NULL);
133
134
135     public static final int STORED_FIELD_HEADER_STATUS_SIZE = 1;
136
137     /**************************************************************************
138      * Get accessors for testing bits in the status field.
139      **************************************************************************
140      */

141
142     /**
143         Get the status of the field
144
145         <BR> MT - single thread required
146     */

147     public static final boolean isNull(int status) {
148         return ((status & FIELD_NULL) == FIELD_NULL);
149     }
150
151     public static final boolean isOverflow(int status) {
152         return ((status & FIELD_OVERFLOW) == FIELD_OVERFLOW);
153     }
154
155     public static final boolean isNonexistent(int status) {
156         return ((status & FIELD_NONEXISTENT) == FIELD_NONEXISTENT);
157     }
158
159     public static final boolean isExtensible(int status) {
160         return ((status & FIELD_EXTENSIBLE) == FIELD_EXTENSIBLE);
161     }
162
163     public static final boolean isNullorNonExistent(int status) {
164         // just need to check whether null bit is set.
165
// return ((status & FIELD_NONEXISTENT) == FIELD_NONEXISTENT);
166
return ((status & FIELD_NULL) != 0);
167     }
168
169     public static final boolean isTagged(int status) {
170         // if (SanityManager.DEBUG)
171
// SanityManager.ASSERT(isExtensible(status), "a field cannot be tagged if it is not extensible");
172
return ((status & FIELD_TAGGED) == FIELD_TAGGED);
173     }
174
175     public static final boolean isFixed(int status) {
176         return ((status & FIELD_FIXED) == FIELD_FIXED);
177     }
178
179     public static final boolean isNullable(int status) {
180         return ((status & FIELD_NOT_NULLABLE) == 0);
181     }
182
183     public static final int size(
184     int status,
185     int fieldDataLength,
186     int fieldDataSize)
187     {
188
189         if ((status & (FIELD_NULL | FIELD_FIXED)) == 0)
190         {
191             // usual case - not-null, not-fixed
192

193             // WARNING - the following code hand inlined from
194
// CompressedNumber for performance.
195
//
196
// return(CompressedNumber.sizeInt(fieldDataLength) + 1);
197
//
198

199             if (fieldDataLength <=
200                         CompressedNumber.MAX_COMPRESSED_INT_ONE_BYTE)
201             {
202                 // compressed form is 1 byte
203
return(2);
204             }
205             else if (fieldDataLength <=
206                         CompressedNumber.MAX_COMPRESSED_INT_TWO_BYTES)
207             {
208                 // compressed form is 2 bytes
209
return(3);
210             }
211             else
212             {
213                 // compressed form is 4 bytes
214
return(5);
215             }
216         }
217         else if ((status & FIELD_NULL) != 0)
218         {
219             // field is null
220

221             return(1);
222         }
223         else
224         {
225             // fixed length field
226

227             return((fieldDataSize > 2) ? 5 : 3);
228         }
229     }
230
231
232     /**************************************************************************
233      * Set accessors for setting bits in the status field.
234      **************************************************************************
235      */

236
237     public final static int setInitial() {
238         return FIELD_INITIAL;
239     }
240
241     public final static int setNull(int status, boolean isNull) {
242         if (isNull)
243             status |= FIELD_NULL;
244         else
245             status &= ~FIELD_NULL;
246         return status;
247     }
248
249     public final static int setOverflow(int status, boolean isOverflow) {
250         if (isOverflow)
251             status |= FIELD_OVERFLOW;
252         else
253             status &= ~FIELD_OVERFLOW;
254         return status;
255     }
256
257     public final static int setNonexistent(int status) {
258         status |= FIELD_NONEXISTENT;
259         return status;
260     }
261
262     public final static int setExtensible(int status, boolean isExtensible) {
263         if (isExtensible)
264             status |= FIELD_EXTENSIBLE;
265         else
266             status &= ~FIELD_EXTENSIBLE;
267         return status;
268     }
269
270     public final static int setTagged(int status, boolean isTagged) {
271
272         if (SanityManager.DEBUG)
273             SanityManager.ASSERT(isExtensible(status),
274                 "a field cannot be set to tagged if it is not extensible");
275
276         if (isTagged)
277             status |= FIELD_TAGGED;
278         else
279             status &= ~FIELD_TAGGED;
280         return status;
281     }
282
283     public final static int setFixed(int status, boolean isFixed) {
284         if (isFixed)
285             status |= FIELD_FIXED;
286         else
287             status &= ~FIELD_FIXED;
288         return status;
289     }
290
291     /**************************************************************************
292      * routines used to write a field header to a OutputStream
293      **************************************************************************
294      */

295
296     /**
297         write out the field status and field data Length
298
299         @exception IOException Thrown by potential I/O errors while writing
300                                field header.
301      */

302     public static final int write(
303     OutputStream JavaDoc out,
304     int status,
305     int fieldDataLength,
306     int fieldDataSize)
307         throws IOException JavaDoc
308     {
309         int len = 1;
310
311         out.write(status);
312
313         if (isNull(status))
314             return len;
315
316         if (isFixed(status))
317         {
318             // if the field header is for log, we write it in compressed format,
319
// then we pad the field, so the total length is fixed.
320
if (fieldDataSize > 2)
321             {
322                 int diffLen =
323                     fieldDataSize -
324                     CompressedNumber.writeInt(out, fieldDataLength);
325
326                 for (int i = diffLen; i > 0; i--)
327                     out.write(0);
328                 len += fieldDataSize; // size of an int - 4 bytes
329
}
330             else
331             {
332                 // write the int out as a short
333
out.write((fieldDataLength >>> 8) & 0xFF);
334                 out.write((fieldDataLength >>> 0) & 0xFF);
335                 len += 2; // size of a short - 2 bytes
336
}
337
338             // NOTE: fixed version is used for logs only,
339
// the overflow information is stored at the end of the optional
340
// data, not in the field headers.
341
// That's why we are not writing overflow info here.
342

343         }
344         else
345         {
346             // if we are writing the fieldHeader for the page,
347
// we write in compressed format
348

349             len += CompressedNumber.writeInt(out, fieldDataLength);
350         }
351
352         return len;
353     }
354
355     /**************************************************************************
356      * routines used to read a field header from an ObjectInput stream, array
357      **************************************************************************
358      */

359
360     /**
361         read the field status
362
363         @exception IOException Thrown by potential I/O errors while reading
364                                field header.
365      */

366     public static final int readStatus(ObjectInput JavaDoc in)
367         throws IOException JavaDoc
368     {
369         int status;
370
371         if ((status = in.read()) >= 0)
372             return status;
373         else
374             throw new EOFException JavaDoc();
375     }
376
377     public static final int readStatus(
378     byte[] page,
379     int offset)
380     {
381         return(page[offset]);
382     }
383
384     /**
385      * read the length of the field and hdr.
386      * <p>
387      * Optimized routine used to skip a field on a page. It returns the
388      * total length of the field including the header portion. It operates
389      * directly on the array and does no checking of it's own for limits on
390      * the array length, so an array out of bounds exception may be thrown -
391      * the routine is meant to be used to read a field from a page so this
392      * should not happen.
393      * <p>
394      *
395      * @return The length of the field on the page, including it's header.
396      *
397      * @param data the array where the field is.
398      * @param offset the offset in the array where the field begin, ie.
399      * the status byte is at data[offset].
400      *
401      * @exception StandardException Standard exception policy.
402      **/

403     public static final int readTotalFieldLength(
404     byte[] data,
405     int offset)
406             throws IOException JavaDoc
407     {
408         if (SanityManager.DEBUG)
409         {
410             // this routine is meant to be called on the page, and FIXED fields
411
// are only used in the log.
412

413             if (isFixed(data[offset]))
414                 SanityManager.THROWASSERT("routine does not handle FIXED.");
415         }
416
417         if (((data[offset++]) & FIELD_NULL) != FIELD_NULL)
418         {
419             int value = data[offset];
420
421             if ((value & ~0x3f) == 0)
422             {
423                 // length is stored in this byte, we also know that the 0x80 bit
424
// was not set, so no need to mask off the sign extension from
425
// the byte to int conversion.
426

427                 // account for 1 byte stored length of field + 1 for status.
428
return(value + 2);
429             }
430             else if ((value & 0x80) == 0)
431             {
432                 // length stored in 2 bytes. only use low 6 bits from 1st byte.
433

434                 if (SanityManager.DEBUG)
435                 {
436                     SanityManager.ASSERT((value & 0x40) == 0x40);
437                 }
438
439                 // top 8 bits of 2 byte length is stored in this byte, we also
440
// know that the 0x80 bit was not set, so no need to mask off
441
// the sign extension from the 1st byte to int conversion. Need
442
// to mask the byte in data[offset + 1] to account for possible
443
// sign extension.
444

445                 // add 3 to account for 2 byte length + 1 for status
446

447                 return((((value & 0x3f) << 8) | (data[offset + 1] & 0xff)) + 3);
448             }
449             else
450             {
451                 // length stored in 4 bytes. only use low 7 bits from 1st byte.
452

453                 if (SanityManager.DEBUG)
454                 {
455                     SanityManager.ASSERT((value & 0x80) == 0x80);
456                 }
457
458                 // top 8 bits of 4 byte length is stored in this byte, we also
459
// know that the 0x80 bit was set, so need to mask off the
460
// sign extension from the 1st byte to int conversion. Need to
461
// mask the bytes from the next 3 bytes data[offset + 1,2,3] to
462
// account for possible sign extension.
463

464
465                 // add 5 to account for 4 byte length + 1 added to all returns
466
return(
467                     (((value & 0x7f) << 24) |
468                      ((data[offset + 1] & 0xff) << 16) |
469                      ((data[offset + 2] & 0xff) << 8) |
470                       (data[offset + 3] & 0xff)) + 5);
471             }
472         }
473         else
474         {
475             return(1);
476         }
477     }
478
479
480     public static final int readFieldLengthAndSetStreamPosition(
481     byte[] data,
482     int offset,
483     int status,
484     int fieldDataSize,
485     ArrayInputStream ais)
486             throws IOException JavaDoc
487     {
488         if ((status & (FIELD_NULL | FIELD_FIXED)) == 0)
489         {
490             // usual case-not null, not fixed. Length stored as compressed int.
491
// return(CompressedNumber.readInt(in));
492

493             int value = data[offset++];
494
495             if ((value & ~0x3f) == 0)
496             {
497                 // usual case.
498

499                 // length is stored in this byte, we also know that the 0x80 bit
500
// was not set, so no need to mask off the sign extension from
501
// the byte to int conversion.
502

503                 // nothing to do, value already has int to return.
504

505             }
506             else if ((value & 0x80) == 0)
507             {
508                 // length is stored in 2 bytes. use low 6 bits from 1st byte.
509

510                 if (SanityManager.DEBUG)
511                 {
512                     SanityManager.ASSERT((value & 0x40) == 0x40);
513                 }
514
515                 // top 8 bits of 2 byte length is stored in this byte, we also
516
// know that the 0x80 bit was not set, so no need to mask off
517
// the sign extension from the 1st byte to int conversion.
518
// Need to mask the byte in data[offset + 1] to account for
519
// possible sign extension.
520

521                 value = (((value & 0x3f) << 8) | (data[offset++] & 0xff));
522
523             }
524             else
525             {
526                 // length is stored in 4 bytes. only low 7 bits from 1st byte.
527

528                 if (SanityManager.DEBUG)
529                 {
530                     SanityManager.ASSERT((value & 0x80) == 0x80);
531                 }
532
533                 // top 8 bits of 4 byte length is stored in this byte, we also
534
// know that the 0x80 bit was set, so need to mask off the
535
// sign extension from the 1st byte to int conversion. Need to
536
// mask the bytes from the next 3 bytes data[offset + 1,2,3] to
537
// account for possible sign extension.
538

539
540                 // add 5 to account for 4 byte length + 1 added to all returns
541
value =
542                     (((value & 0x7f) << 24) |
543                      ((data[offset++] & 0xff) << 16) |
544                      ((data[offset++] & 0xff) << 8) |
545                       (data[offset++] & 0xff));
546             }
547
548             ais.setPosition(offset);
549
550             return(value);
551         }
552         else if ((status & FIELD_NULL) != 0)
553         {
554             ais.setPosition(offset);
555             return(0);
556         }
557         else
558         {
559             int fieldDataLength;
560
561             // field data length is in a fixed size field, not compressed.
562

563             if (fieldDataSize <= 2)
564             {
565                 // read it in as short, because it was written out as short
566
fieldDataLength =
567                     ((data[offset++] & 0xff) << 8) | (data[offset++] & 0xff);
568             }
569             else
570             {
571                 // fieldDataLength = CompressedNumber.readInt(in);
572

573                 fieldDataLength = data[offset];
574
575                 if ((fieldDataLength & ~0x3f) == 0)
576                 {
577                     // usual case.
578

579                     // length is stored in this byte, we also know that the 0x80
580
// bit was not set, so no need to mask off the sign
581
// extension from the byte to int conversion.
582

583                     // nothing to do, fieldDataLength already has int to return.
584

585                 }
586                 else if ((fieldDataLength & 0x80) == 0)
587                 {
588                     // len is stored in 2 bytes. use low 6 bits from 1st byte.
589

590                     if (SanityManager.DEBUG)
591                     {
592                         SanityManager.ASSERT((fieldDataLength & 0x40) == 0x40);
593                     }
594
595                     // top 8 bits of 2 byte length is stored in this byte, we
596
// also know that the 0x80 bit was not set, so no need to
597
// mask off the sign extension from the 1st byte to int
598
// conversion. Need to mask the byte in data[offset + 1] to
599
// account for possible sign extension.
600

601                     fieldDataLength =
602                         (((fieldDataLength & 0x3f) << 8) |
603                          (data[offset + 1] & 0xff));
604
605                 }
606                 else
607                 {
608                     // len is stored in 4 bytes. only low 7 bits from 1st byte.
609

610                     if (SanityManager.DEBUG)
611                     {
612                         SanityManager.ASSERT((fieldDataLength & 0x80) == 0x80);
613                     }
614
615                     // top 8 bits of 4 byte length is stored in this byte, we
616
// also know that the 0x80 bit was set, so need to mask off
617
// the sign extension from the 1st byte to int conversion.
618
// Need to mask the bytes from the next 3 bytes
619
// data[offset + 1,2,3] to account for possible sign
620
// extension.
621

622                     fieldDataLength =
623                         (((fieldDataLength & 0x7f) << 24) |
624                          ((data[offset + 1] & 0xff) << 16) |
625                          ((data[offset + 2] & 0xff) << 8) |
626                           (data[offset + 3] & 0xff));
627                 }
628
629                 offset = offset + fieldDataSize;
630             }
631
632             ais.setPosition(offset);
633             return(fieldDataLength);
634         }
635
636
637     }
638
639     /**
640         read the field data length
641
642         @exception IOException Thrown by potential I/O errors while reading
643                                field header.
644      */

645     public static final int readFieldDataLength(
646     ObjectInput JavaDoc in,
647     int status,
648     int fieldDataSize)
649             throws IOException JavaDoc
650     {
651         
652         if ((status & (FIELD_NULL | FIELD_FIXED)) == 0)
653         {
654             // usual case-not null, not fixed. Length stored as compressed int.
655
return(CompressedNumber.readInt(in));
656         }
657         else if ((status & FIELD_NULL) != 0)
658         {
659             // field is null or non-existent.
660
return(0);
661         }
662         else
663         {
664             int fieldDataLength;
665
666             // field data length is in a fixed size field, not compressed.
667

668             if (fieldDataSize <= 2)
669             {
670                 // read it in as short, because it was written out as short
671
int ch1 = in.read();
672                 int ch2 = in.read();
673                 if ((ch1 | ch2) < 0)
674                      throw new EOFException JavaDoc();
675
676                 fieldDataLength = ((ch1 << 8) + (ch2 << 0));
677             }
678             else
679             {
680                 fieldDataLength =
681                     CompressedNumber.readInt(in);
682
683                 int diffLen =
684                     fieldDataSize -
685                     CompressedNumber.sizeInt(fieldDataLength);
686
687                 if (diffLen != 0)
688                     in.skipBytes(diffLen);
689             }
690
691             return(fieldDataLength);
692         }
693     }
694
695
696     public static String JavaDoc toDebugString(int status)
697     {
698         if (SanityManager.DEBUG)
699         {
700             StringBuffer JavaDoc str = new StringBuffer JavaDoc(100);
701             if (isNull(status)) str.append("Null ");
702             if (isOverflow(status)) str.append("Overflow ");
703             if (isNonexistent(status)) str.append("Nonexistent ");
704             if (isExtensible(status)) str.append("Extensible ");
705             if (isTagged(status)) str.append("Tagged ");
706             if (isFixed(status)) str.append("Fixed ");
707             if (isNullable(status)) str.append("Nullable ");
708             if (str.length() == 0)
709                 str.append("INITIAL ");
710
711             return str.toString();
712         }
713         return null;
714     }
715 }
716
Popular Tags