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

Quick Search    Search Deep

Source code: org/hsqldb/TextCache.java


1   /* Copyright (c) 2001-2002, The HSQL Development Group
2    * All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    * Redistributions of source code must retain the above copyright notice, this
8    * list of conditions and the following disclaimer.
9    *
10   * Redistributions in binary form must reproduce the above copyright notice,
11   * this list of conditions and the following disclaimer in the documentation
12   * and/or other materials provided with the distribution.
13   *
14   * Neither the name of the HSQL Development Group nor the names of its
15   * contributors may be used to endorse or promote products derived from this
16   * software without specific prior written permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 
22   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  
31  
32  package org.hsqldb;
33  
34  import java.io.IOException;
35  import java.io.File;
36  import java.sql.SQLException;
37  
38  /**
39   * Handles operations on a DatabaseFile object and uses signle
40   * TextDdatbaseRowInput and TextDatabaseRowOutput objects to read and write
41   * rows of data to the file in text table format.
42   *
43   * @author sqlbob@users (RMP)
44   * @version 1.7.0
45   */
46  class TextCache extends org.hsqldb.Cache {
47  
48      public static final String NL = System.getProperty("line.separator");
49      private String                     fs;
50      private String                     vs;
51      private String                     lvs;
52      private DatabaseRowOutputInterface out;
53      protected boolean                  readOnly;
54      protected TextDatabaseRowInput     in;
55      protected boolean                  ignoreFirst;
56      protected String                   ignoredFirst = NL;
57  
58      private class TextSource {
59  
60          private String source;
61  
62          TextSource(String s) {
63              source = s;
64          }
65  
66          String getAttr(String id, String ret) {
67  
68              id = ";" + id + "=";
69  
70              int len = id.length();
71              int start;
72              int end;
73  
74              if ((start = source.indexOf(id)) != -1) {
75                  start += len;
76  
77                  if ((end = source.indexOf(";", start)) == -1) {
78                      end = source.length();
79                  }
80  
81                  ret = source.substring(start, end);
82                  source = source.substring(0, start - len)
83                           + source.substring(end);
84              }
85  
86              return (ret);
87          }
88      }
89  
90      /**
91       *  TextCache constructor declaration <P>
92       *
93       *  The cache constructor sets up the initial parameters of the cache
94       *  object, setting the name used for the file, etc.
95       *
96       * @param  name              of database file
97       * @param  propPrefix        prefix for relevant properties
98       * @param  props             Description of the Parameter
99       * @exception  SQLException  Description of the Exception
100      */
101     TextCache(String name, String propPrefix,
102               HsqlDatabaseProperties props) throws SQLException {
103 
104         super("", props);
105 
106         TextSource textSource = new TextSource(name);
107 
108         //-- Get separators:
109         fs = translateSep(textSource.getAttr("fs", null));
110         vs = textSource.getAttr("vs", fs);
111 
112         if (vs != fs) {
113             vs = translateSep(vs);
114         }
115 
116         String lvs = textSource.getAttr("lvs", fs);
117 
118         if (lvs != fs) {
119             lvs = translateSep(lvs);
120         }
121 
122         if (fs == null) {
123             fs = translateSep(props.getProperty(propPrefix + "fs"), true);
124 
125             if (fs == null) {
126                 fs = ",";
127             }
128         }
129 
130         if (vs == null) {
131             vs = props.getProperty(propPrefix + "vs", fs);
132 
133             if (vs != fs) {
134                 vs = translateSep(vs, true);
135             }
136         }
137 
138         if (lvs == null) {
139             lvs = props.getProperty(propPrefix + "lvs", fs);
140 
141             if (lvs != fs) {
142                 lvs = translateSep(lvs, true);
143             }
144         }
145 
146         //-- Get boolean settings:
147         String skipFirst = textSource.getAttr("ignore_first", null);
148 
149         if (skipFirst == null) {
150             skipFirst = props.getProperty(propPrefix + "ignore_first",
151                                           "false");
152         }
153 
154         ignoreFirst = skipFirst.equals("true");
155 
156         String quoted = textSource.getAttr("quoted", null);
157 
158         if (quoted == null) {
159             quoted = props.getProperty(propPrefix + "quoted", "true");
160         }
161 
162         String emptyIsNull = textSource.getAttr("empty_is_null", null);
163 
164         if (emptyIsNull == null) {
165             emptyIsNull = props.getProperty(propPrefix + "empty_is_null",
166                                             "true");
167         }
168 
169         // Get file name
170         sName = textSource.source;
171 
172         if (sName.endsWith(";")) {
173             sName = sName.substring(0, sName.length() - 1);
174         }
175 
176         try {
177             if (quoted.equals("true")) {
178                 in = new QuotedTextDatabaseRowInput(
179                     fs, vs, lvs, emptyIsNull.equals("true"));
180                 out = new QuotedTextDatabaseRowOutput(fs, vs, lvs);
181             } else {
182                 in = new TextDatabaseRowInput(fs, vs, lvs,
183                                               emptyIsNull.equals("true"));
184                 out = new TextDatabaseRowOutput(fs, vs, lvs);
185             }
186         } catch (IOException e) {
187             throw (Trace.error(Trace.FILE_IO_ERROR,
188                                "invalid separator(s):" + e));
189         }
190     }
191 
192     private String translateSep(String sep) {
193         return (translateSep(sep, false));
194     }
195 
196     private String translateSep(String sep, boolean isProperty) {
197 
198         if (sep == null) {
199             return (null);
200         }
201 
202         int next = 0;
203 
204         if ((next = sep.indexOf('\\')) != -1) {
205             int          start      = 0;
206             char         sepArray[] = sep.toCharArray();
207             char         ch         = 0;
208             int          len        = sep.length();
209             StringBuffer realSep    = new StringBuffer(len);
210 
211             do {
212                 realSep.append(sepArray, start, next - start);
213 
214                 start = ++next;
215 
216                 if (next >= len) {
217                     realSep.append('\\');
218 
219                     break;
220                 }
221 
222                 if (!isProperty) {
223                     ch = sepArray[next];
224                 }
225 
226                 if (ch == 'n') {
227                     realSep.append('\n');
228 
229                     start++;
230                 } else if (ch == 'r') {
231                     realSep.append('\r');
232 
233                     start++;
234                 } else if (ch == 't') {
235                     realSep.append('\t');
236 
237                     start++;
238                 } else if (ch == '\\') {
239                     realSep.append('\\');
240 
241                     start++;
242                 } else if (ch == 'u') {
243                     start++;
244 
245                     realSep.append(
246                         (char) Integer.parseInt(
247                             sep.substring(start, start + 4), 16));
248 
249                     start += 4;
250                 } else if (sep.startsWith("semi", next)) {
251                     realSep.append(';');
252 
253                     start += 4;
254                 } else if (sep.startsWith("space", next)) {
255                     realSep.append(' ');
256 
257                     start += 5;
258                 } else if (sep.startsWith("quote", next)) {
259                     realSep.append('\"');
260 
261                     start += 5;
262                 } else if (sep.startsWith("apos", next)) {
263                     realSep.append('\'');
264 
265                     start += 4;
266                 } else {
267                     realSep.append('\\');
268                     realSep.append(sepArray[next]);
269 
270                     start++;
271                 }
272             } while ((next = sep.indexOf('\\', start)) != -1);
273 
274             realSep.append(sepArray, start, len - start);
275 
276             sep = realSep.toString();
277         }
278 
279         return (sep);
280     }
281 
282     /**
283      *  open method declaration <P>
284      *
285      *  The open method creates or opens a database file.
286      *
287      * @param  readonly       Description of the Parameter
288      * @param  ignore1st      Description of the Parameter
289      * @throws  SQLException
290      */
291     void open(boolean readonly) throws SQLException {
292 
293         try {
294             rFile    = new DatabaseFile(sName, (readonly) ? "r"
295                                                           : "rw", 4096);
296             iFreePos = (int) rFile.length();
297 
298             if ((iFreePos == 0) && ignoreFirst) {
299                 rFile.write(ignoredFirst.getBytes());
300 
301                 iFreePos = ignoredFirst.length();
302             }
303         } catch (Exception e) {
304             throw Trace.error(Trace.FILE_IO_ERROR,
305                               "error " + e + " opening " + sName);
306         }
307 
308         readOnly = readonly;
309     }
310 
311     void reopen() throws SQLException {
312         open(readOnly);
313         in.reset();
314     }
315 
316     /**
317      *  flush method declaration <P>
318      *
319      *  The flush method saves all cached data to the file, saves the free
320      *  position and closes the file.
321      *
322      * @throws  SQLException
323      */
324     void flush() throws SQLException {
325 
326         if (rFile == null) {
327             return;
328         }
329 
330         try {
331             rFile.seek(0);
332             saveAll();
333 
334             boolean empty = (rFile.length() <= NL.length());
335 
336             rFile.close();
337 
338             rFile = null;
339 
340             if (empty &&!readOnly) {
341                 new File(sName).delete();
342             }
343         } catch (Exception e) {
344             throw Trace.error(Trace.FILE_IO_ERROR,
345                               "error " + e + " closing " + sName);
346         }
347     }
348 
349     void purge() throws SQLException {
350 
351         if (rFile == null) {
352             return;
353         }
354 
355         try {
356             if (readOnly) {
357                 flush();
358             } else {
359                 rFile.close();
360 
361                 rFile = null;
362 
363                 new File(sName).delete();
364             }
365         } catch (Exception e) {
366             throw Trace.error(Trace.FILE_IO_ERROR,
367                               "error " + e + " purging " + sName);
368         }
369     }
370 
371     void free(CachedRow r) throws SQLException {
372 
373         int pos    = r.iPos;
374         int length = r.storageSize;
375 
376         //-- Change to blank line:
377         StringBuffer blank = new StringBuffer(length);
378 
379         length -= NL.length();
380 
381         for (int i = 0; i < length; i++) {
382             blank.append(' ');
383         }
384 
385         blank.append(NL);
386 
387         try {
388             rFile.seek(pos);
389             rFile.writeBytes(blank.toString());
390         } catch (IOException e) {
391             throw (Trace.error(Trace.FILE_IO_ERROR, e + ""));
392         }
393 
394         remove(r);
395     }
396 
397     protected void setStorageSize(CachedRow r) throws SQLException {
398 
399         int size;
400 
401         try {
402             out.writeData(r.getData(), r.getTable());
403 
404             size = out.toByteArray().length;
405         } catch (IOException e) {
406             throw (Trace.error(Trace.FILE_IO_ERROR, e + ""));
407         }
408 
409         r.storageSize = size;
410     }
411 
412     protected CachedRow makeRow(int pos, Table t) throws SQLException {
413 
414         CachedRow r = null;
415 
416         try {
417             StringBuffer buffer   = new StringBuffer(80);
418             boolean      blank    = true;
419             boolean      complete = false;
420 
421             try {
422                 char c;
423                 int  next;
424 
425                 rFile.readSeek(pos);
426 
427                 //-- The following should work for DOS, MAC, and Unix line
428                 //-- separators regardless of host OS.
429                 while (true) {
430                     next = rFile.read();
431 
432                     if (next == -1) {
433                         break;
434                     }
435 
436                     c = (char) (next & 0xff);
437 
438                     //-- Ensure line is complete.
439                     if (c == '\n') {
440                         buffer.append('\n');
441 
442                         //-- Store first line.
443                         if (ignoreFirst && pos == 0) {
444                             ignoredFirst = buffer.toString();
445                             blank        = true;
446                         }
447 
448                         //-- Ignore blanks
449                         if (!blank) {
450                             complete = true;
451 
452                             break;
453                         } else {
454                             pos += buffer.length();
455 
456                             buffer.setLength(0);
457 
458                             blank = true;
459 
460                             in.skippedLine();
461 
462                             continue;
463                         }
464                     }
465 
466                     if (c == '\r') {
467 
468                         //-- Check for newline
469                         try {
470                             next = rFile.read();
471 
472                             if (next == -1) {
473                                 break;
474                             }
475 
476                             c = (char) (next & 0xff);
477 
478                             if (c == '\n') {
479                                 buffer.append('\n');
480                             }
481                         } catch (Exception e2) {
482                             ;
483                         }
484 
485                         buffer.append('\n');
486 
487                         //-- Store first line.
488                         if (ignoreFirst && pos == 0) {
489                             ignoredFirst = buffer.toString();
490                             blank        = true;
491                         }
492 
493                         //-- Ignore blanks.
494                         if (!blank) {
495                             complete = true;
496 
497                             break;
498                         } else {
499                             pos += buffer.length();
500 
501                             buffer.setLength(0);
502 
503                             blank = true;
504 
505                             in.skippedLine();
506 
507                             continue;
508                         }
509                     }
510 
511                     if (c != ' ') {
512                         blank = false;
513                     }
514 
515                     buffer.append(c);
516                 }
517             } catch (Exception e) {
518                 complete = false;
519             }
520 
521             if (complete) {
522                 in.setSource(buffer.toString(), pos);
523 
524                 r = new CachedRow(t, in);
525             }
526         } catch (Exception e) {
527             e.printStackTrace();
528 
529             throw Trace.error(Trace.FILE_IO_ERROR, "reading: " + e);
530         }
531 
532         return (r);
533     }
534 
535     protected void saveRow(CachedRow r) throws IOException, SQLException {
536 
537         rFile.seek(r.iPos);
538         r.write(out);
539         rFile.write(out.toByteArray());
540     }
541 }