KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.data.StreamFileContainer
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.impl.store.raw.data;
23
24 import org.apache.derby.iapi.reference.SQLState;
25
26 import org.apache.derby.iapi.services.context.ContextService;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import org.apache.derby.iapi.services.io.Storable;
30 import org.apache.derby.iapi.services.io.StreamStorable;
31 import org.apache.derby.iapi.services.io.FormatIdInputStream;
32 import org.apache.derby.iapi.services.io.FormatIdOutputStream;
33 import org.apache.derby.iapi.services.io.FormatIdUtil;
34 import org.apache.derby.iapi.services.io.StoredFormatIds;
35 import org.apache.derby.iapi.services.io.TypedFormat;
36 import org.apache.derby.iapi.services.monitor.Monitor;
37
38 import org.apache.derby.iapi.error.StandardException;
39 import org.apache.derby.iapi.store.access.AccessFactory;
40 import org.apache.derby.iapi.store.access.RowSource;
41 import org.apache.derby.iapi.store.access.RowUtil;
42 import org.apache.derby.iapi.store.access.TransactionController;
43 import org.apache.derby.iapi.store.raw.ContainerKey;
44 import org.apache.derby.iapi.store.raw.RawStoreFactory;
45 import org.apache.derby.iapi.store.raw.StreamContainerHandle;
46
47 import org.apache.derby.io.StorageFactory;
48 import org.apache.derby.io.WritableStorageFactory;
49 import org.apache.derby.io.StorageFile;
50
51 import org.apache.derby.impl.store.raw.data.DecryptInputStream;
52 import org.apache.derby.impl.store.raw.data.StoredFieldHeader;
53 import org.apache.derby.impl.store.raw.data.StoredRecordHeader;
54
55 import org.apache.derby.iapi.services.io.ArrayInputStream;
56 import org.apache.derby.iapi.services.io.FormatableBitSet;
57 import org.apache.derby.iapi.services.io.CompressedNumber;
58 import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;
59 import org.apache.derby.iapi.services.io.LimitInputStream;
60 import org.apache.derby.iapi.services.property.PropertyUtil;
61 import org.apache.derby.iapi.util.ReuseFactory;
62
63 import java.util.Properties JavaDoc;
64 import java.io.InputStream JavaDoc;
65 import java.io.BufferedInputStream JavaDoc;
66 import java.io.OutputStream JavaDoc;
67 import java.io.IOException JavaDoc;
68 import java.io.EOFException JavaDoc;
69 import java.io.InvalidClassException JavaDoc;
70 import java.io.Externalizable JavaDoc;
71 import java.security.AccessController JavaDoc;
72 import java.security.PrivilegedExceptionAction JavaDoc;
73 import java.security.PrivilegedActionException JavaDoc;
74 import java.io.FileNotFoundException JavaDoc;
75
76 /**
77
78   The format of this stream file is:
79   (RH) (FH) (field data) (FH) (field data) ........ (FH) (field data)
80
81   Record header is stored once at the beginning of the file
82   for all the rows stored in this file.
83   Record Header indicates how many fields are in each row.
84   Then we just stored all the column from each row.
85   Field header stored on this file is fixed size with fieldDataLength
86   size set to LARGE_SLOT_SIZE (4) bytes.
87
88   NOTE: No locks are used in this container. All transaction are not logged.
89
90 **/

91
92
93 public class StreamFileContainer implements TypedFormat, PrivilegedExceptionAction JavaDoc
94 {
95
96     /**************************************************************************
97      * Constant Fields of the class
98      **************************************************************************
99      */

100
101     /*
102      * typed format
103      * format Id must fit in 4 bytes
104      */

105     protected static int formatIdInteger =
106         StoredFormatIds.RAW_STORE_SINGLE_CONTAINER_STREAM_FILE;
107
108
109     // 4 bytes for field data length
110
protected static final int LARGE_SLOT_SIZE = 4;
111
112     protected static final int MIN_BUFFER_SIZE =
113         RawStoreFactory.STREAM_FILE_BUFFER_SIZE_MINIMUM;
114     protected static final int FIELD_STATUS =
115         StoredFieldHeader.setFixed(StoredFieldHeader.setInitial(), true);
116     protected static final int FIELD_HEADER_SIZE =
117         StoredFieldHeader.size(FIELD_STATUS, 0, LARGE_SLOT_SIZE);
118
119
120     /**************************************************************************
121      * Fields of the class
122      **************************************************************************
123      */

124     protected ContainerKey identity;
125     private BaseDataFileFactory dataFactory; // the factory that made me
126

127     private int bufferSize;
128
129     private StorageFile file;
130
131     private OutputStream fileOut;
132     private DynamicByteArrayOutputStream out;
133     private FormatIdOutputStream logicalDataOut;
134
135     private InputStream fileIn;
136     private BufferedInputStream JavaDoc bufferedIn;
137     private DecryptInputStream decryptIn;
138     private LimitInputStream limitIn;
139     private FormatIdInputStream logicalDataIn;
140
141     private StoredRecordHeader recordHeader;
142
143     private byte[] ciphertext;
144     private byte[] zeroBytes; // in case encryption
145
// stream needs pad.
146

147
148     /* privileged actions */
149     private static final int STORAGE_FILE_EXISTS_ACTION = 1;
150     private static final int STORAGE_FILE_DELETE_ACTION = 2;
151     private static final int STORAGE_FILE_MKDIRS_ACTION = 3;
152     private static final int STORAGE_FILE_GET_OUTPUT_STREAM_ACTION = 4;
153     private static final int STORAGE_FILE_GET_INPUT_STREAM_ACTION = 5;
154     private int actionCode;
155     private StorageFile actionStorageFile;
156
157
158     /**************************************************************************
159      * Constructors for This class:
160      **************************************************************************
161      */

162
163     /**
164      * Constructor.
165      *
166      * @exception StandardException Standard exception policy.
167      **/

168     StreamFileContainer(
169     ContainerKey identity,
170     BaseDataFileFactory dataFactory)
171         throws StandardException
172     {
173         this.identity = identity;
174         this.dataFactory = dataFactory;
175     }
176
177     /**
178      * Constructor
179      * <p>
180      * when rowSource is passed to the constructor, it will be loaded into the
181      * container after the container has been created.
182      * <p>
183      *
184      * @exception StandardException Standard exception policy.
185      **/

186     StreamFileContainer(
187     ContainerKey identity,
188     BaseDataFileFactory dataFactory,
189     Properties JavaDoc prop)
190         throws StandardException
191     {
192         this.identity = identity;
193         this.dataFactory = dataFactory;
194
195         try
196         {
197             file = getFileName(identity, true, false);
198
199             if (privExists(file))
200             {
201                 // note I'm left in the no-identity state as fillInIdentity()
202
// hasn't been called.
203
throw StandardException.newException(
204                         SQLState.FILE_EXISTS, file);
205             }
206
207             // get the properties to set buffer size
208
// derby.storage.streamFileBufferSize
209
getContainerProperties(prop);
210
211         }
212         catch (SecurityException JavaDoc se)
213         {
214             throw StandardException.newException(
215                     SQLState.FILE_CREATE, se, file);
216         }
217     }
218
219     /**************************************************************************
220      * Private/Protected methods of This class:
221      **************************************************************************
222      */

223
224     /**
225      * Open a stream file container.
226      * <p>
227      * Open a container. Open the file that maps to this container, if the
228      * file does not exist then we assume the container was never created
229      * and return.
230      * If the file exists but we have trouble opening it then we throw some
231      * exception.
232      * <p>
233      *
234      * @return The opened StreamFileContainer.
235      *
236      * @param forUpdate Currently only accepts false, updating and existing
237      * stream file container is not currently supported.
238      *
239      * @exception StandardException Standard exception policy.
240      **/

241     protected StreamFileContainer open(boolean forUpdate)
242         throws StandardException
243     {
244
245         file = getFileName(this.identity, false, true);
246         if (!privExists(file))
247             return null;
248
249         try
250         {
251             if (!forUpdate)
252             {
253                 fileIn = privGetInputStream(file);
254
255                 if (dataFactory.databaseEncrypted())
256                 {
257                     // if the database is encrypted, when reading the data back
258
// from the file stream, we need to used the decrypt stream
259
// to buffer up the bytes for reading. DecryptInputStream
260
// also decrypts the data.
261

262                     MemByteHolder byteHolder =
263                         new MemByteHolder(
264                             RawStoreFactory.STREAM_FILE_BUFFER_SIZE_DEFAULT);
265
266                     decryptIn =
267                         new DecryptInputStream(fileIn, byteHolder, dataFactory);
268
269                     limitIn = new LimitInputStream(decryptIn);
270                 }
271                 else
272                 {
273                     bufferedIn =
274                         new BufferedInputStream JavaDoc(
275                             fileIn,
276                             RawStoreFactory.STREAM_FILE_BUFFER_SIZE_DEFAULT);
277
278                     limitIn = new LimitInputStream(bufferedIn);
279                 }
280
281                 // the logicalDataIn input stream is on top of a limit Input
282
// stream, use a limit stream to make sure we don't read off
283
// more then what each column says it contains
284

285                 logicalDataIn = new FormatIdInputStream(limitIn);
286
287                 // get the record header
288
recordHeader = new StoredRecordHeader();
289                 recordHeader.read(logicalDataIn);
290
291             }
292             else
293             {
294                 if (SanityManager.DEBUG)
295                     SanityManager.THROWASSERT(
296                         "updating existing stream container not supported yet");
297
298                 return null;
299             }
300         }
301         catch (IOException JavaDoc ioe)
302         {
303             throw StandardException.newException(
304                     SQLState.FILE_CREATE, ioe, file);
305         }
306
307         return this;
308     }
309
310     /**
311      * Close the stream file.
312      * <p>
313      * Close this stream file, and all streams associated with it.
314      * <p>
315      *
316      * @exception StandardException Standard exception policy.
317      **/

318     protected void close()
319     {
320         try
321         {
322
323             if (fileIn != null)
324             {
325                 fileIn.close();
326                 fileIn = null;
327                 if (dataFactory.databaseEncrypted())
328                 {
329                     decryptIn.close();
330                     decryptIn = null;
331                 }
332                 else
333                 {
334                     bufferedIn.close();
335                     bufferedIn = null;
336                 }
337                 logicalDataIn.close();
338                 logicalDataIn = null;
339             }
340
341             if (fileOut != null)
342             {
343                 fileOut.close();
344                 logicalDataOut.close();
345                 fileOut = null;
346                 logicalDataOut = null;
347                 out = null;
348             }
349
350         }
351         catch (IOException JavaDoc ioe)
352         {
353             // ignore close errors from fileOut.close() and fileIn.close() -
354
// there isn't much we can do about them anyway - and some of the
355
// interfaces don't want to deal with exceptions from close().
356

357             /*
358             throw StandardException.newException(
359                     SQLState.FILE_CREATE, ioe, file);
360             */

361         }
362     }
363
364     /**************************************************************************
365      * Public Methods of This class:
366      **************************************************************************
367      */

368
369     /**
370      * Return my format identifier.
371      **/

372     public int getTypeFormatId()
373     {
374         return StoredFormatIds.RAW_STORE_SINGLE_CONTAINER_STREAM_FILE;
375     }
376
377     /**
378      * Request the system properties associated with a stream container.
379      * <p>
380      * Request the value of properties associated with a stream container.
381      * The following properties can be requested:
382      * derby.storage.streamFileBufferSize
383      *
384      * <p>
385      * To get the value of a particular property add it to the property list,
386      * and on return the value of the property will be set to it's current
387      * value. For example:
388      *
389      * get_prop(ConglomerateController cc)
390      * {
391      * Properties prop = new Properties();
392      * prop.put("derby.storage.streamFileBufferSize", "");
393      * cc.getContainerProperties(prop);
394      *
395      * System.out.println(
396      * "stream table's buffer size = " +
397      * prop.getProperty("derby.storage.streamFileBufferSize");
398      * }
399      *
400      * @param prop Property list to fill in.
401      *
402      * @exception StandardException Standard exception policy.
403      **/

404     public void getContainerProperties(Properties JavaDoc prop)
405         throws StandardException
406     {
407
408         AccessFactory af = (AccessFactory)
409             Monitor.getServiceModule(dataFactory, AccessFactory.MODULE);
410
411         TransactionController tc =
412             (af == null) ?
413                 null :
414                 af.getTransaction(
415                     ContextService.getFactory().getCurrentContextManager());
416
417         bufferSize =
418             PropertyUtil.getServiceInt(tc, prop,
419                 RawStoreFactory.STREAM_FILE_BUFFER_SIZE_PARAMETER,
420                 RawStoreFactory.STREAM_FILE_BUFFER_SIZE_MINIMUM,
421                 RawStoreFactory.STREAM_FILE_BUFFER_SIZE_MAXIMUM,
422                 RawStoreFactory.STREAM_FILE_BUFFER_SIZE_DEFAULT);
423     }
424
425     /**
426      * Request the container key associated with the stream container.
427      **/

428     public ContainerKey getIdentity()
429     {
430         return this.identity;
431     }
432
433     /**
434      * Can I use this container?
435      * <p>
436      * This method always return true right now.
437      * In the future when there are different uses for this container,
438      * we may need to add qualifications for this.
439      *
440      * @exception StandardException Standard exception policy.
441      **/

442     protected boolean use(StreamContainerHandle handle)
443         throws StandardException
444     {
445         return true;
446     }
447
448     /**
449      * load data into this container.
450      * <p>
451      * populate the stream container with data in the rowSource
452      * <p>
453      *
454      * @param rowSource The row source to get rows to load into this container.
455      *
456      * @exception StandardException Standard exception policy.
457      **/

458     public void load(RowSource rowSource)
459         throws StandardException
460     {
461         // use this output stream to buffer rows before inserting into file.
462
out = new DynamicByteArrayOutputStream(bufferSize);
463         logicalDataOut = new FormatIdOutputStream(out);
464         boolean encrypted = dataFactory.databaseEncrypted();
465
466         // reserve the first dataFactory.getEncryptionBlockSize() - 1 bytes, if the database is
467
// encrypted These reserved bytes will be used to pad the byte array if
468
// it is not dataFactory.getEncryptionBlockSize() aligned.
469
if (encrypted)
470         {
471             if (zeroBytes == null)
472                 zeroBytes = new byte[dataFactory.getEncryptionBlockSize() - 1];
473
474             out.write(zeroBytes, 0, dataFactory.getEncryptionBlockSize() - 1);
475         }
476
477         try
478         {
479             fileOut = privGetOutputStream(file);
480
481             FormatableBitSet validColumns = rowSource.getValidColumns();
482
483             Object JavaDoc[] row = rowSource.getNextRowFromRowSource();
484
485             int numberFields = 0;
486             if (validColumns != null)
487             {
488                 for (int i = validColumns.getLength() - 1; i >= 0; i--)
489                 {
490                     if (validColumns.isSet(i))
491                     {
492                         numberFields = i + 1;
493                         break;
494                     }
495                 }
496             }
497             else
498             {
499                 numberFields = row.length;
500             }
501
502             // make the record header to have 0 record id
503
recordHeader = new StoredRecordHeader(0, numberFields);
504
505             // write the record header once for all the rows, directly to the
506
// beginning of the file.
507
int rhLen = recordHeader.write(out);
508
509             int validColumnsSize =
510                 validColumns == null ? 0 : validColumns.getLength();
511
512             while (row != null)
513             {
514
515                 int arrayPosition = -1;
516
517                 for (int i = 0; i < numberFields; i++)
518                 {
519
520                     // write each column out
521
if (validColumns == null)
522                     {
523                         arrayPosition++;
524                         Object JavaDoc column = row[arrayPosition];
525                         writeColumn(column);
526                     }
527                     else
528                     {
529
530                         if (validColumnsSize > i && validColumns.isSet(i))
531                         {
532                             arrayPosition++;
533                             Object JavaDoc column = row[arrayPosition];
534                             writeColumn(column);
535                         }
536                         else
537                         {
538                             // it is a non-existent column
539
writeColumn(null);
540                         }
541                     }
542
543                     // put the buffer onto the page, only if it exceeded the
544
// original buffer size or it has less than 100 bytes left
545
// in the buffer
546
if ((out.getUsed() >= bufferSize) ||
547                         ((bufferSize - out.getUsed()) < MIN_BUFFER_SIZE))
548                     {
549                         writeToFile();
550                     }
551                 }
552
553                 // get the next row and its valid columns from the rowSource
554
row = rowSource.getNextRowFromRowSource();
555             }
556
557
558             // Write the buffer to the file if there is something in the output
559
// buffer. Remember we pad the output buffer with
560
// dataFactory.getEncryptionBlockSize() - 1 if this is an encypted database
561
if (encrypted)
562             {
563                 if (out.getUsed() > (dataFactory.getEncryptionBlockSize() - 1))
564                     writeToFile();
565             }
566             else if (out.getUsed() > 0)
567             {
568                 writeToFile();
569             }
570
571         }
572         catch (IOException JavaDoc ioe)
573         {
574             // handle IO error...
575
throw StandardException.newException(
576                     SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);
577
578         }
579         finally
580         {
581             close();
582         }
583     }
584
585     /*
586
587      */

588     /**
589      * Write the buffer to the file.
590      * <p>
591      * If the database is encrypted, the dataFactory.getEncryptionBlockSize() - 1 reserved bytes will
592      * be used to pad the byte array to be dataFactory.getEncryptionBlockSize()
593      * aligned. Before the bytes are encrypted and written to the file stream,
594      * the actual length of the byte array is written out as a compressed
595      * integer. This number will be used when decrypting the data.
596      *
597      * If the database is not encrypted, then, we don't reserve the bytes
598      * upfront, and we simple just write the bytes out to the file stream.
599      *
600      * @exception StandardException Standard exception policy.
601      **/

602     private void writeToFile()
603         throws StandardException
604     {
605
606         try
607         {
608             if (dataFactory.databaseEncrypted())
609             {
610                 // if db is encrypted,
611
// use the first ENCRYPTION_ALIGN bytes for padding.
612
//
613
int realLen = out.getUsed() - (dataFactory.getEncryptionBlockSize() - 1);
614                 int tail = realLen % dataFactory.getEncryptionBlockSize();
615                 int padding =
616                     (tail == 0) ? 0 :
617                     (dataFactory.getEncryptionBlockSize() - tail);
618
619                 int startByte = (tail == 0) ? (dataFactory.getEncryptionBlockSize() - 1) : (tail - 1);
620                 int encryptedLen = realLen + padding;
621
622                 // there is nothing to write, just the encryption padding
623
if (realLen <= 0)
624                     return;
625
626                 if (ciphertext == null)
627                 {
628                     ciphertext = new byte[encryptedLen];
629                 }
630                 else
631                 {
632                     if (ciphertext.length < encryptedLen)
633                         ciphertext = new byte[encryptedLen];
634                 }
635
636                 dataFactory.encrypt(
637                     out.getByteArray(), startByte, encryptedLen, ciphertext, 0, false);
638
639                 // write out the actual length, then the encrypted bytes.
640
CompressedNumber.writeInt(fileOut, realLen);
641                 dataFactory.writeInProgress();
642                 try
643                 {
644                     fileOut.write(ciphertext, 0, encryptedLen);
645                 }
646                 finally
647                 {
648                     dataFactory.writeFinished();
649                 }
650
651                 // reset the dynamic buffer
652
out.reset();
653
654                 // reserve bytes if database is encrypted.
655
if (dataFactory.databaseEncrypted())
656                 {
657                     if (zeroBytes == null)
658                         zeroBytes = new byte[dataFactory.getEncryptionBlockSize() - 1];
659
660                     out.write(zeroBytes, 0, dataFactory.getEncryptionBlockSize() - 1);
661                 }
662
663             }
664             else
665             {
666                 // nothing to write
667
if (out.getUsed() == 0)
668                     return;
669
670                 dataFactory.writeInProgress();
671                 try
672                 {
673                     fileOut.write(out.getByteArray(), 0, out.getUsed());
674                 }
675                 finally
676                 {
677                     dataFactory.writeFinished();
678                 }
679
680                 // reset the dynamic buffer
681
out.reset();
682             }
683         }
684         catch (IOException JavaDoc ioe)
685         {
686             throw StandardException.newException(
687                     SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);
688         }
689     }
690
691     private void writeColumn(Object JavaDoc column)
692         throws StandardException, IOException JavaDoc
693     {
694
695         int fieldStatus = FIELD_STATUS;
696         if (column == null)
697         {
698             // just write a non-existent header.
699
fieldStatus = StoredFieldHeader.setNonexistent(fieldStatus);
700             StoredFieldHeader.write(out, fieldStatus, 0, LARGE_SLOT_SIZE);
701             return;
702         }
703
704         // if the column is a null column, write the field header now.
705
if (column instanceof Storable)
706         {
707             Storable sColumn = (Storable) column;
708             if (sColumn.isNull())
709             {
710                 fieldStatus = StoredFieldHeader.setNull(fieldStatus, true);
711                 StoredFieldHeader.write(out, fieldStatus, 0, LARGE_SLOT_SIZE);
712                 return;
713             }
714         }
715
716         int beginPosition = out.getPosition();
717         int fieldDataLength = 0;
718
719         // write out the header, mostly to reserve the space
720
StoredFieldHeader.write(
721             out, fieldStatus, fieldDataLength, LARGE_SLOT_SIZE);
722
723         if (column instanceof StreamStorable)
724         {
725             if (((StreamStorable) column).returnStream() != null)
726             {
727                 column = (InputStream) ((StreamStorable) column).returnStream();
728             }
729         }
730
731         if (column instanceof InputStream)
732         {
733             InputStream inColumn = (InputStream) column;
734             int bufferLen = inColumn.available();
735             byte[] bufData = new byte[bufferLen];
736
737             do
738             {
739                 int lenRead = inColumn.read(bufData, bufferLen, 0);
740                 if (lenRead != -1)
741                 {
742                     fieldDataLength += lenRead;
743                     out.write(bufData, lenRead, 0);
744                 }
745                 else
746                 {
747                     break;
748                 }
749             } while (true);
750
751         }
752         else if (column instanceof Storable)
753         {
754
755             Storable sColumn = (Storable) column;
756             // write field data to the stream, we already handled the null case
757

758             sColumn.writeExternal(logicalDataOut);
759             fieldDataLength =
760                 out.getPosition() - beginPosition - FIELD_HEADER_SIZE;
761
762         }
763         else
764         {
765             // Serializable/Externalizable/Formattable
766
// all look the same at this point.
767
logicalDataOut.writeObject(column);
768             fieldDataLength =
769                 out.getPosition() - beginPosition - FIELD_HEADER_SIZE;
770         }
771
772         // Now we go back to update the fieldDataLength in the field header
773
int endPosition = out.getPosition();
774         out.setPosition(beginPosition);
775
776         StoredFieldHeader.write(
777             out, fieldStatus, fieldDataLength, LARGE_SLOT_SIZE);
778
779         // set position to the end of the field
780
if (!StoredFieldHeader.isNull(fieldStatus))
781             out.setPosition(endPosition);
782     }
783
784     public boolean fetchNext(Object JavaDoc[] row)
785         throws StandardException
786     {
787
788         boolean inUserCode = false;
789         int columnId = 0;
790         
791         try
792         {
793
794             // Get the number of columns in the row.
795
int numberFields = recordHeader.getNumberFields();
796
797             int arrayPosition = 0;
798             for (columnId = 0; columnId < numberFields; columnId++)
799             {
800
801                 if (arrayPosition >= row.length)
802                     break;
803     
804                 limitIn.clearLimit();
805
806                 // read the field header
807
int fieldStatus = StoredFieldHeader.readStatus(logicalDataIn);
808                 int fieldDataLength = StoredFieldHeader.readFieldDataLength(
809                     logicalDataIn, fieldStatus, LARGE_SLOT_SIZE);
810
811                 limitIn.setLimit(fieldDataLength);
812
813                 if (SanityManager.DEBUG)
814                 {
815
816                     if (StoredFieldHeader.isExtensible(fieldStatus))
817                     {
818                         SanityManager.THROWASSERT(
819                             "extensible fields not supported yet. columnId = "
820                             + columnId);
821                     }
822
823                     SanityManager.ASSERT(!StoredFieldHeader.isOverflow(fieldStatus),
824                         "overflow field is not supported yet");
825                 }
826
827                 Object JavaDoc column = row[arrayPosition];
828                 
829                 // Deal with Storable columns
830
if (StoredFieldHeader.isNullable(fieldStatus))
831                 {
832                                     
833                     if (column == null)
834                     {
835                         throw StandardException.newException(
836                                 SQLState.DATA_NULL_STORABLE_COLUMN,
837                                 Integer.toString(columnId));
838                     }
839
840                     // SRW-DJD RESOLVE: - fix error message
841
if (!(column instanceof Storable))
842                     {
843                         throw StandardException.newException(
844                             SQLState.DATA_NULL_STORABLE_COLUMN,
845                             column.getClass().getName());
846                     }
847
848                     Storable sColumn = (Storable) column;
849
850                     // is the column null ?
851
if (StoredFieldHeader.isNull(fieldStatus))
852                     {
853
854                         sColumn.restoreToNull();
855                         arrayPosition++;
856                         continue;
857                     }
858
859                     inUserCode = true;
860                     sColumn.readExternal(logicalDataIn);
861                     inUserCode = false;
862                     arrayPosition++;
863                     continue;
864                 }
865
866                 // Only Storables can be null ... SRW-DJD RESOLVE: - fix error message
867
if (StoredFieldHeader.isNull(fieldStatus))
868                 {
869                     throw StandardException.newException(
870                         SQLState.DATA_NULL_STORABLE_COLUMN,
871                         Integer.toString(columnId));
872                 }
873
874                 // This is a non-extensible field, which means the caller must
875
// know the correct type and thus the element in row is the
876
// correct type or null. If the element implements
877
// Externalizable then we can just fill it in, otherwise it
878
// must be Serializable and we have to throw it away.
879

880                 Object JavaDoc neColumn = row[arrayPosition];
881
882                 if (neColumn instanceof Externalizable JavaDoc)
883                 {
884
885                     Externalizable JavaDoc exColumn = (Externalizable JavaDoc) neColumn;
886
887                     inUserCode = true;
888                     exColumn.readExternal(logicalDataIn);
889                     inUserCode = false;
890
891                     arrayPosition++;
892                     continue;
893                 }
894
895                 // neColumn will be ignored
896
neColumn = null;
897                 inUserCode = true;
898                 row[arrayPosition] = logicalDataIn.readObject();
899                 inUserCode = false;
900
901                 arrayPosition++;
902                 continue;
903             }
904
905         }
906         catch (IOException JavaDoc ioe)
907         {
908
909             // an exception during the restore of a user column, this doesn't
910
// make the databse corrupt, just that this field is inaccessable
911
if (inUserCode)
912             {
913
914                 if (ioe instanceof EOFException JavaDoc)
915                 {
916                     throw StandardException.newException(
917                         SQLState.DATA_STORABLE_READ_MISMATCH,
918                         ioe, logicalDataIn.getErrorInfo());
919                 }
920
921                 throw StandardException.newException(
922                     SQLState.DATA_STORABLE_READ_EXCEPTION,
923                     ioe, logicalDataIn.getErrorInfo());
924             }
925
926             if (ioe instanceof InvalidClassException JavaDoc)
927             {
928                 throw StandardException.newException(
929                         SQLState.DATA_STORABLE_READ_EXCEPTION,
930                         ioe, logicalDataIn.getErrorInfo());
931             }
932
933             // If we are at the end of the file, trying to fetch the first
934
// column, then we know there is no more rows to fetch
935
if ((ioe instanceof EOFException JavaDoc) && (columnId == 0))
936             {
937                 close();
938                 return false;
939             }
940
941             throw dataFactory.markCorrupt(
942                 StandardException.newException(
943                     SQLState.DATA_CORRUPT_STREAM_CONTAINER, ioe, identity));
944
945         }
946         catch (ClassNotFoundException JavaDoc cnfe)
947         {
948
949             if (SanityManager.DEBUG)
950             {
951                 SanityManager.ASSERT(inUserCode);
952             }
953
954             // an exception during the restore of a user column, this doesn't
955
// make the databse corrupt, just that this field is inaccessable
956
throw StandardException.newException(
957                 SQLState.DATA_STORABLE_READ_MISSING_CLASS, cnfe,
958                 logicalDataIn.getErrorInfo());
959
960         }
961         catch (LinkageError JavaDoc le)
962         {
963             if (inUserCode)
964             {
965                 throw StandardException.newException(
966                     SQLState.DATA_STORABLE_READ_EXCEPTION, le,
967                     logicalDataIn.getErrorInfo());
968             }
969             throw le;
970         }
971
972         return true;
973
974     }
975
976     /**
977      * Close the stream file and remove the file.
978      *
979      * @exception StandardException Segment directory cannot be created
980      **/

981     public boolean removeContainer()
982         throws StandardException
983     {
984         close();
985
986         if (privExists(file))
987         {
988             return privDelete(file);
989         }
990         else
991         {
992             return true;
993         }
994
995
996     }
997
998     /**
999      * Return a file name for the identity.
1000     * <p>
1001     * Return a valid file name for the identity, or null if the data
1002     * directory for this segment cannot be created
1003     *
1004     * @exception StandardException Segment directory cannot be created
1005     **/

1006    protected StorageFile getFileName(
1007    ContainerKey identity,
1008    boolean forCreate,
1009    boolean errorOK)
1010         throws StandardException
1011    {
1012        if (identity.getSegmentId() == StreamContainerHandle.TEMPORARY_SEGMENT)
1013        {
1014            return( dataFactory.storageFactory.newStorageFile( dataFactory.storageFactory.getTempDir(),
1015                    "T" + identity.getContainerId() + ".tmp"));
1016        }
1017        else
1018        {
1019            if (SanityManager.DEBUG)
1020                SanityManager.THROWASSERT(
1021                    "cannot create stream container in non-temp segments yet.");
1022
1023            StorageFile container = dataFactory.getContainerPath( identity, false);
1024
1025            if (!privExists(container))
1026            {
1027
1028                if (!forCreate)
1029                    return null;
1030
1031                StorageFile directory = container.getParentDir();
1032
1033                if (!privExists(directory))
1034                {
1035                    // make sure only 1 thread can create a segment at one time
1036
synchronized(dataFactory)
1037                    {
1038                        if (!privExists(directory))
1039                        {
1040                            if (!privMkdirs(directory))
1041                            {
1042                                if (errorOK)
1043                                    return null;
1044                                else
1045                                    throw StandardException.newException(
1046                                            SQLState.FILE_CANNOT_CREATE_SEGMENT,
1047                                            directory);
1048                            }
1049                        }
1050                    }
1051                }
1052            }
1053            return container;
1054        }
1055    }
1056
1057
1058
1059    
1060    private synchronized boolean privExists(StorageFile file)
1061    {
1062        actionCode = STORAGE_FILE_EXISTS_ACTION;
1063        actionStorageFile = file;
1064
1065        try
1066        {
1067            Object JavaDoc ret = AccessController.doPrivileged( this);
1068            return ((Boolean JavaDoc) ret).booleanValue();
1069        }catch( PrivilegedActionException JavaDoc pae)
1070        {
1071            // method executed under this priveleged block
1072
// does not throw an exception
1073
return false;
1074        }
1075        finally
1076        {
1077            actionStorageFile = null;
1078        }
1079    }
1080
1081    private synchronized boolean privMkdirs(StorageFile file)
1082    {
1083        actionCode = STORAGE_FILE_MKDIRS_ACTION;
1084        actionStorageFile = file;
1085
1086        try
1087        {
1088            Object JavaDoc ret = AccessController.doPrivileged( this);
1089            return ((Boolean JavaDoc) ret).booleanValue();
1090        }catch( PrivilegedActionException JavaDoc pae)
1091        {
1092            // method executed under this priveleged block
1093
// does not throw an exception
1094
return false;
1095        }
1096        finally
1097        {
1098            actionStorageFile = null;
1099        }
1100    }
1101
1102    
1103    private synchronized boolean privDelete(StorageFile file)
1104    {
1105        actionCode = STORAGE_FILE_DELETE_ACTION;
1106        actionStorageFile = file;
1107
1108        try
1109        {
1110            Object JavaDoc ret = AccessController.doPrivileged( this);
1111            return ((Boolean JavaDoc) ret).booleanValue();
1112        }catch( PrivilegedActionException JavaDoc pae)
1113        {
1114            // method executed under this priveleged block
1115
// does not throw an exception
1116
return false;
1117        }
1118        finally
1119        {
1120            actionStorageFile = null;
1121        }
1122    }
1123
1124    private synchronized OutputStream privGetOutputStream(StorageFile file)
1125        throws FileNotFoundException JavaDoc
1126    {
1127        actionCode = STORAGE_FILE_GET_OUTPUT_STREAM_ACTION;
1128        actionStorageFile = file;
1129
1130        try
1131        {
1132            return (OutputStream) AccessController.doPrivileged( this);
1133        }catch( PrivilegedActionException JavaDoc pae)
1134        {
1135            throw (FileNotFoundException JavaDoc)pae.getException();
1136        }
1137        finally
1138        {
1139            actionStorageFile = null;
1140        }
1141    }
1142
1143
1144    private synchronized InputStream privGetInputStream(StorageFile file)
1145        throws FileNotFoundException JavaDoc
1146    {
1147        actionCode = STORAGE_FILE_GET_INPUT_STREAM_ACTION;
1148        actionStorageFile = file;
1149
1150        try
1151        {
1152            return (InputStream) AccessController.doPrivileged( this);
1153        }catch( PrivilegedActionException JavaDoc pae)
1154        {
1155            throw (FileNotFoundException JavaDoc)pae.getException();
1156        }
1157        finally
1158        {
1159            actionStorageFile = null;
1160        }
1161    }
1162
1163
1164    // PrivilegedAction method
1165
public Object JavaDoc run() throws FileNotFoundException JavaDoc
1166    {
1167        switch(actionCode)
1168        {
1169        case STORAGE_FILE_EXISTS_ACTION:
1170            return ReuseFactory.getBoolean(actionStorageFile.exists());
1171        case STORAGE_FILE_DELETE_ACTION:
1172            return ReuseFactory.getBoolean(actionStorageFile.delete());
1173        case STORAGE_FILE_MKDIRS_ACTION:
1174            return ReuseFactory.getBoolean(actionStorageFile.mkdirs());
1175        case STORAGE_FILE_GET_OUTPUT_STREAM_ACTION:
1176            return actionStorageFile.getOutputStream();
1177        case STORAGE_FILE_GET_INPUT_STREAM_ACTION:
1178            return actionStorageFile.getInputStream();
1179        }
1180
1181        return null;
1182    }
1183
1184}
1185
Popular Tags