KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > tools > Recover


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.tools;
6
7 import java.io.BufferedInputStream JavaDoc;
8 import java.io.BufferedWriter JavaDoc;
9 import java.io.ByteArrayInputStream JavaDoc;
10 import java.io.DataInputStream JavaDoc;
11 import java.io.FileOutputStream JavaDoc;
12 import java.io.FileWriter JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.io.PrintWriter JavaDoc;
16 import java.sql.SQLException JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.HashSet JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.Map.Entry;
23
24 import org.h2.command.Parser;
25 import org.h2.engine.Constants;
26 import org.h2.engine.Database;
27 import org.h2.engine.DbObject;
28 import org.h2.engine.MetaRecord;
29 import org.h2.message.Message;
30 import org.h2.result.SimpleRow;
31 import org.h2.security.SHA256;
32 import org.h2.store.DataHandler;
33 import org.h2.store.DataPage;
34 import org.h2.store.DiskFile;
35 import org.h2.store.FileStore;
36 import org.h2.store.FileStoreInputStream;
37 import org.h2.store.LogFile;
38 import org.h2.util.ByteUtils;
39 import org.h2.util.FileUtils;
40 import org.h2.util.IOUtils;
41 import org.h2.util.ObjectArray;
42 import org.h2.util.RandomUtils;
43 import org.h2.value.Value;
44
45 /**
46  * Dumps the contents of a database file to a human readable text file.
47  * This text file can be used to recover most of the data.
48  * This tool does not open the database and can be used even if the database files are corrupted.
49  * A database can get corrupted if there is a bug in the database engine or file system software,
50  * or if an application writes into the database file that doesn't understand the the file format,
51  * or if there is a hardware problem.
52  *
53  * @author Thomas
54  *
55  */

56 public class Recover implements DataHandler {
57     
58     private String JavaDoc databaseName;
59     private boolean textStorage;
60     private int block;
61     private int blockCount;
62     private int storageId;
63     private int recordLength;
64     private int valueId;
65     private boolean log;
66
67     private void showUsage() {
68         System.out.println("java "+getClass().getName()+" [-dir <dir>] [-db <database>] [-log true]");
69     }
70     
71     /**
72      * The command line interface for this tool.
73      * The options must be split into strings like this: "-db", "test",...
74      * The following options are supported:
75      * <ul>
76      * <li>-help or -? (print the list of options)
77      * <li>-dir directory (the default is the current directory)
78      * <li>-db databaseName (all databases if no name is specified)
79      * <li>-log {true|false} (log additional messages)
80      * </ul>
81      *
82      * @param args the command line arguments
83      * @throws SQLException
84      */

85     public static void main(String JavaDoc[] args) throws SQLException JavaDoc {
86         new Recover().run(args);
87     }
88     
89     private void run(String JavaDoc[] args) throws SQLException JavaDoc {
90         String JavaDoc dir = ".";
91         String JavaDoc db = null;
92         boolean removePassword = false;
93         for(int i=0; args != null && i<args.length; i++) {
94             if("-dir".equals(args[i])) {
95                 dir = args[++i];
96             } else if("-db".equals(args[i])) {
97                 db = args[++i];
98             } else if("-removePassword".equals(args[i])) {
99                 removePassword = true;
100             } else if("-log".equals(args[i])) {
101                 log = Boolean.valueOf(args[++i]).booleanValue();
102             } else {
103                 showUsage();
104                 return;
105             }
106         }
107         if(removePassword) {
108             removePassword(dir, db);
109         } else {
110             process(dir, db);
111         }
112     }
113     
114     private void removePassword(String JavaDoc dir, String JavaDoc db) throws SQLException JavaDoc {
115         ArrayList JavaDoc list = FileBase.getDatabaseFiles(dir, db, true);
116         for(int i=0; i<list.size(); i++) {
117             String JavaDoc fileName = (String JavaDoc) list.get(i);
118             if(fileName.endsWith(Constants.SUFFIX_DATA_FILE)) {
119                 removePassword(fileName);
120             }
121         }
122     }
123     
124     private void logError(String JavaDoc message, Throwable JavaDoc t) {
125         System.out.println(message + ": " + t.toString());
126         if(log) {
127             t.printStackTrace();
128         }
129     }
130
131     private void removePassword(String JavaDoc fileName) throws SQLException JavaDoc {
132         databaseName = fileName.substring(fileName.length() - Constants.SUFFIX_DATA_FILE.length());
133         textStorage = Database.isTextStorage(fileName, false);
134         byte[] magic = Database.getMagic(textStorage);
135         FileStore store = FileStore.open(null, fileName, magic);
136         long length = store.length();
137         int offset = FileStore.HEADER_LENGTH;
138         int blockSize = DiskFile.BLOCK_SIZE;
139         int blocks = (int)(length / blockSize);
140         blockCount = 1;
141         for(int block=0; block<blocks; block += blockCount) {
142             store.seek(offset + (long)block*blockSize);
143             byte[] bytes = new byte[blockSize];
144             DataPage s = DataPage.create(this, bytes);
145             long start = store.getFilePointer();
146             store.readFully(bytes, 0, blockSize);
147             blockCount = s.readInt();
148             storageId = -1;
149             recordLength = -1;
150             valueId = -1;
151             if(blockCount == 0) {
152                 // free block
153
blockCount = 1;
154                 continue;
155             } else if(blockCount < 0) {
156                 blockCount = 1;
157                 continue;
158             }
159             try {
160                 s.checkCapacity(blockCount * blockSize);
161             } catch(OutOfMemoryError JavaDoc e) {
162                 blockCount = 1;
163                 continue;
164             }
165             if(blockCount > 1) {
166                 store.readFully(s.getBytes(), blockSize, blockCount * blockSize - blockSize);
167             }
168             try {
169                 s.check(blockCount * blockSize);
170             } catch(SQLException JavaDoc e) {
171                 blockCount = 1;
172                 continue;
173             }
174             storageId = s.readInt();
175             if(storageId != 0) {
176                 continue;
177             }
178             recordLength = s.readInt();
179             if(recordLength <= 0) {
180                 continue;
181             }
182             Value[] data;
183             try {
184                 data = new Value[recordLength];
185             } catch(Throwable JavaDoc e) {
186                 continue;
187             }
188             for(valueId=0; valueId<recordLength; valueId++) {
189                 try {
190                     data[valueId] = s.readValue();
191                 } catch(Throwable JavaDoc e) {
192                     continue;
193                 }
194             }
195             if(storageId == 0) {
196                 try {
197                     String JavaDoc sql = data[3].getString();
198                     if(!sql.startsWith("CREATE USER ")) {
199                         continue;
200                     }
201                     int idx = sql.indexOf("SALT");
202                     if(idx < 0) {
203                         continue;
204                     }
205                     String JavaDoc userName = sql.substring("CREATE USER ".length(), idx-1);
206                     if(userName.startsWith("\"")) {
207                         // TODO doesn't work for all cases ("" inside user name)
208
userName = userName.substring(1, userName.length()-1);
209                     }
210                     SHA256 sha = new SHA256();
211                     byte[] userPasswordHash = sha.getKeyPasswordHash(userName, "".toCharArray());
212                     byte[] salt = RandomUtils.getSecureBytes(Constants.SALT_LEN);
213                     byte[] passwordHash = sha.getHashWithSalt(userPasswordHash, salt);
214                     boolean admin = sql.indexOf("ADMIN") >= 0;
215                     StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
216                     buff.append("CREATE USER ");
217                     buff.append(Parser.quoteIdentifier(userName));
218                     buff.append(" SALT '");
219                     buff.append(ByteUtils.convertBytesToString(salt));
220                     buff.append("' HASH '");
221                     buff.append(ByteUtils.convertBytesToString(passwordHash));
222                     buff.append("'");
223                     if(admin) {
224                         buff.append(" ADMIN");
225                     }
226                     byte[] replacement = buff.toString().getBytes();
227                     int at = ByteUtils.indexOf(s.getBytes(), "CREATE USER ".getBytes(), 0);
228                     System.arraycopy(replacement, 0, s.getBytes(), at, replacement.length);
229                     s.fill(blockCount * blockSize);
230                     s.updateChecksum();
231                     store.seek(start);
232                     store.write(s.getBytes(), 0, s.length());
233                     System.out.println("User: " + userName);
234                     break;
235                 } catch(Throwable JavaDoc e) {
236                     e.printStackTrace();
237                 }
238             }
239         }
240         closeSilently(store);
241     }
242
243     /**
244      * Dumps the database.
245      *
246      * @param dir the directory
247      * @param db the database name (null for all databases)
248      * @throws SQLException
249      */

250     public static void execute(String JavaDoc dir, String JavaDoc db) throws SQLException JavaDoc {
251         new Recover().process(dir, db);
252     }
253     
254     private void process(String JavaDoc dir, String JavaDoc db) throws SQLException JavaDoc {
255         ArrayList JavaDoc list = FileBase.getDatabaseFiles(dir, db, true);
256         for(int i=0; i<list.size(); i++) {
257             String JavaDoc fileName = (String JavaDoc) list.get(i);
258             // TODO recover: should create a working SQL script if possible (2 passes)
259
if(fileName.endsWith(Constants.SUFFIX_DATA_FILE)) {
260                 dumpData(fileName);
261             } else if(fileName.endsWith(Constants.SUFFIX_INDEX_FILE)) {
262                 dumpIndex(fileName);
263             } else if(fileName.endsWith(Constants.SUFFIX_LOG_FILE)) {
264                 dumpLog(fileName);
265             } else if(fileName.endsWith(Constants.SUFFIX_LOB_FILE)) {
266                 dumpLob(fileName, true);
267                 dumpLob(fileName, false);
268             }
269         }
270     }
271     
272     private static PrintWriter JavaDoc getWriter(String JavaDoc fileName, String JavaDoc suffix) throws IOException JavaDoc {
273         fileName = fileName.substring(0, fileName.length()-3);
274         String JavaDoc outputFile = fileName + suffix;
275         System.out.println("Created file: " + outputFile);
276         return new PrintWriter JavaDoc(new BufferedWriter JavaDoc(new FileWriter JavaDoc(outputFile)));
277     }
278     
279     private void writeDataError(PrintWriter JavaDoc writer, String JavaDoc error, byte[] data, int dumpBlocks) throws IOException JavaDoc {
280         writer.println("-- ERROR:" + error + " block:"+block+" blockCount:"+blockCount+" storageId:" + storageId+" recordLength: " + recordLength+" valudId:" + valueId);
281         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
282         for(int i=0; i<dumpBlocks * DiskFile.BLOCK_SIZE; i++) {
283             int x = (data[i] & 0xff);
284             if(x >= ' ' && x < 128) {
285                 sb.append((char)x);
286             } else {
287                 sb.append('?');
288             }
289         }
290         writer.println("-- dump: " + sb.toString());
291         sb = new StringBuffer JavaDoc();
292         for(int i=0; i<dumpBlocks * DiskFile.BLOCK_SIZE; i++) {
293             int x = (data[i] & 0xff);
294             sb.append(' ');
295             if(x < 16) {
296                 sb.append('0');
297             }
298             sb.append(Integer.toHexString(x));
299         }
300         writer.println("-- dump: " + sb.toString());
301     }
302     
303     private void dumpLob(String JavaDoc fileName, boolean lobCompression) {
304         FileOutputStream JavaDoc out = null;
305         FileStore store = null;
306         int size = 0;
307         String JavaDoc n = fileName + (lobCompression ? ".comp" : "") + ".txt";
308         InputStream JavaDoc in = null;
309         try {
310             out = new FileOutputStream JavaDoc(n);
311             textStorage = Database.isTextStorage(fileName, false);
312             byte[] magic = Database.getMagic(textStorage);
313             store = FileStore.open(null, fileName, magic);
314             store.init();
315             in = new BufferedInputStream JavaDoc(new FileStoreInputStream(store, this, lobCompression));
316             byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
317             while(true) {
318                 int l = in.read(buffer);
319                 if(l<0) {
320                     break;
321                 }
322                 out.write(buffer, 0, l);
323                 size += l;
324             }
325         } catch(Throwable JavaDoc e) {
326             // this is usually not a problem, because we try both compressed and uncompressed
327
if(log) {
328                 logError(fileName, e);
329             }
330         } finally {
331             IOUtils.closeSilently(out);
332             IOUtils.closeSilently(in);
333             closeSilently(store);
334         }
335         if(size == 0) {
336             try {
337                 FileUtils.delete(n);
338             } catch (SQLException JavaDoc e) {
339                 logError(n, e);
340             }
341         }
342     }
343     
344     private void dumpLog(String JavaDoc fileName) throws SQLException JavaDoc {
345         PrintWriter JavaDoc writer = null;
346         FileStore store = null;
347         try {
348             databaseName = fileName.substring(fileName.length() - Constants.SUFFIX_LOG_FILE.length());
349             writer = getWriter(fileName, ".txt");
350             textStorage = Database.isTextStorage(fileName, false);
351             byte[] magic = Database.getMagic(textStorage);
352             store = FileStore.open(null, fileName, magic);
353             long length = store.length();
354             writer.println("// length: " + length);
355             int offset = FileStore.HEADER_LENGTH;
356             int blockSize = LogFile.BLOCK_SIZE;
357             int blocks = (int)(length / blockSize);
358             byte[] buff = new byte[blockSize];
359             DataPage s = DataPage.create(this, buff);
360             s.fill(3*blockSize);
361             int len = s.length();
362             s.reset();
363             if(length < FileStore.HEADER_LENGTH + len) {
364                 // this is an empty file
365
writer.println("// empty file");
366                 return;
367             }
368             store.seek(offset);
369             store.readFully(s.getBytes(), 0, len);
370             int id = s.readInt();
371             int firstUncommittedPos = s.readInt();
372             int firstUnwrittenPos = s.readInt();
373             writer.println("// id:" + id);
374             writer.println("// firstUncommittedPos:" + firstUncommittedPos);
375             writer.println("// firstUnwrittenPos:" + firstUnwrittenPos);
376             int max = (int)(length / blockSize);
377             writer.println("// max:" + max);
378             while(true) {
379                 int pos = (int)(store.getFilePointer() / blockSize);
380                 if((long)pos * blockSize >= length) {
381                     break;
382                 }
383                 buff = new byte[blockSize];
384                 store.readFully(buff, 0, blockSize);
385                 s = DataPage.create(this, buff);
386                 blocks = Math.abs(s.readInt());
387                 if(blocks > 1) {
388                     byte[] b2 = new byte[blocks * blockSize];
389                     System.arraycopy(buff, 0, b2, 0, blockSize);
390                     buff = b2;
391                     try {
392                         store.readFully(buff, blockSize, blocks * blockSize - blockSize);
393                     } catch(SQLException JavaDoc e) {
394                         break;
395                     }
396                     s = DataPage.create(this, buff);
397                     s.check(blocks * blockSize);
398                 }
399                 s.reset();
400                 blocks = Math.abs(s.readInt());
401                 if(blocks==0) {
402                     writer.println("// [" + pos+"] blocks: "+blocks+" (end)");
403                     break;
404                 } else {
405                     char type = (char)s.readByte();
406                     int sessionId = s.readInt();
407                     if(type == 'P') {
408                         String JavaDoc transaction = s.readString();
409                         writer.println("// prepared session:"+sessionId+" tx:" + transaction);
410                     } else if(type == 'C') {
411                         writer.println("// commit session:" + sessionId);
412                     } else {
413                         int storageId = s.readInt();
414                         int recId = s.readInt();
415                         int blockCount = s.readInt();
416                         if(type != 'T') {
417                             s.readDataPageNoSize();
418                         }
419                         switch(type) {
420                         case 'S': {
421                             char fileType = (char) s.readByte();
422                             int sumLength= s.readInt();
423                             byte[] summary = new byte[sumLength];
424                             if(sumLength > 0) {
425                                 s.read(summary, 0, sumLength);
426                             }
427                             writer.println("// summary session:"+sessionId+" fileType:" + fileType + " sumLength:" + sumLength);
428                             dumpSummary(writer, summary);
429                             break;
430                         }
431                         case 'T':
432                             writer.println("// truncate session:"+sessionId+" storage:" + storageId + " pos:" + recId + " blockCount:"+blockCount);
433                             break;
434                         case 'I':
435                             writer.println("// insert session:"+sessionId+" storage:" + storageId + " pos:" + recId + " blockCount:"+blockCount);
436                             break;
437                         case 'D':
438                             writer.println("// delete session:"+sessionId+" storage:" + storageId + " pos:" + recId + " blockCount:"+blockCount);
439                             break;
440                         default:
441                             writer.println("// type?:"+type+" session:"+sessionId+" storage:" + storageId + " pos:" + recId + " blockCount:"+blockCount);
442                             break;
443                         }
444                     }
445                 }
446             }
447         } catch(Throwable JavaDoc e) {
448             writeError(writer, e);
449         } finally {
450             IOUtils.closeSilently(writer);
451             closeSilently(store);
452         }
453     }
454     
455     private void dumpSummary(PrintWriter JavaDoc writer, byte[] summary) throws SQLException JavaDoc {
456         if(summary == null || summary.length==0) {
457             writer.println("// summary is empty");
458             return;
459         }
460         try {
461             DataInputStream JavaDoc in = new DataInputStream JavaDoc(new ByteArrayInputStream JavaDoc(summary));
462             int b2 = in.readInt();
463             for(int i=0; i<b2 / 8; i++) {
464                 int x = in.read();
465                 if((i % 8) == 0) {
466                     writer.print("// ");
467                 }
468                 writer.print(" " + Long.toString(i * 8) + ":");
469                 for(int j=0; j<8; j++) {
470                     writer.print(((x & 1) == 1) ? "1" : "0");
471                     x >>>= 1;
472                 }
473                 if((i % 8) == 7) {
474                     writer.println("");
475                 }
476             }
477             writer.println("//");
478             int len = in.readInt();
479             for(int i=0; i<len; i++) {
480                 int storageId = in.readInt();
481                 if(storageId != -1) {
482                     writer.println("// pos:"+(i*DiskFile.BLOCKS_PER_PAGE)+" storage:" + storageId);
483                 }
484             }
485             while(true) {
486                 int s = in.readInt();
487                 if(s < 0) {
488                     break;
489                 }
490                 int recordCount = in.readInt();
491                 writer.println("// storage:"+s+" recordCount:" + recordCount);
492             }
493         } catch(Throwable JavaDoc e) {
494             writeError(writer, e);
495         }
496     }
497
498     private void dumpIndex(String JavaDoc fileName) throws SQLException JavaDoc {
499         PrintWriter JavaDoc writer = null;
500         FileStore store = null;
501         try {
502             databaseName = fileName.substring(fileName.length() - Constants.SUFFIX_INDEX_FILE.length());
503             writer = getWriter(fileName, ".txt");
504             textStorage = Database.isTextStorage(fileName, false);
505             byte[] magic = Database.getMagic(textStorage);
506             store = FileStore.open(null, fileName, magic);
507             long length = store.length();
508             int offset = FileStore.HEADER_LENGTH;
509             int blockSize = DiskFile.BLOCK_SIZE;
510             int blocks = (int)(length / blockSize);
511             blockCount = 1;
512             int[] pageOwners = new int[blocks / DiskFile.BLOCKS_PER_PAGE];
513             for(int block=0; block<blocks; block += blockCount) {
514                 store.seek(offset + (long)block*blockSize);
515                 byte[] buff = new byte[blockSize];
516                 DataPage s = DataPage.create(this, buff);
517                 store.readFully(buff, 0, blockSize);
518                 blockCount = s.readInt();
519                 storageId = -1;
520                 recordLength = -1;
521                 valueId = -1;
522                 if(blockCount == 0) {
523                     // free block
524
blockCount = 1;
525                     continue;
526                 } else if(blockCount < 0) {
527                     writeDataError(writer, "blockCount<0", s.getBytes(), 1);
528                     blockCount = 1;
529                     continue;
530                 } else if((blockCount * blockSize) >= Integer.MAX_VALUE / 4) {
531                     writeDataError(writer, "blockCount=" + blockCount, s.getBytes(), 1);
532                     blockCount = 1;
533                     continue;
534                 }
535                 try {
536                     s.checkCapacity(blockCount * blockSize);
537                 } catch(OutOfMemoryError JavaDoc e) {
538                     writeDataError(writer, "out of memory", s.getBytes(), 1);
539                     blockCount = 1;
540                     continue;
541                 }
542                 if(blockCount > 1) {
543                     store.readFully(s.getBytes(), blockSize, blockCount * blockSize - blockSize);
544                 }
545                 try {
546                     s.check(blockCount * blockSize);
547                 } catch(SQLException JavaDoc e) {
548                     writeDataError(writer, "wrong checksum", s.getBytes(), 1);
549                     blockCount = 1;
550                     continue;
551                 }
552                 storageId = s.readInt();
553                 if(storageId < 0) {
554                     writeDataError(writer, "storageId<0", s.getBytes(), blockCount);
555                     continue;
556                 }
557                 int page = block / DiskFile.BLOCKS_PER_PAGE;
558                 if(pageOwners[page] != 0 && pageOwners[page] != storageId) {
559                     writeDataError(writer, "double allocation, previous="+pageOwners[page]+" now="+storageId, s.getBytes(), blockCount);
560                 } else {
561                     pageOwners[page] = storageId;
562                 }
563                 writer.println("// [" + block + "] page:"+page+" blocks:"+blockCount+" storage:"+storageId);
564             }
565         } catch(Throwable JavaDoc e) {
566             writeError(writer, e);
567         } finally {
568             IOUtils.closeSilently(writer);
569             closeSilently(store);
570         }
571     }
572
573     private void dumpData(String JavaDoc fileName) throws SQLException JavaDoc {
574         PrintWriter JavaDoc writer = null;
575         FileStore store = null;
576         try {
577             databaseName = fileName.substring(0, fileName.length() - Constants.SUFFIX_DATA_FILE.length());
578             writer = getWriter(fileName, ".sql");
579             ObjectArray schema = new ObjectArray();
580             HashSet JavaDoc objectIdSet = new HashSet JavaDoc();
581             HashMap JavaDoc tableMap = new HashMap JavaDoc();
582             textStorage = Database.isTextStorage(fileName, false);
583             byte[] magic = Database.getMagic(textStorage);
584             store = FileStore.open(null, fileName, magic);
585             long length = store.length();
586             int offset = FileStore.HEADER_LENGTH;
587             int blockSize = DiskFile.BLOCK_SIZE;
588             int blocks = (int)(length / blockSize);
589             blockCount = 1;
590             int[] pageOwners = new int[blocks / DiskFile.BLOCKS_PER_PAGE];
591             for(int block=0; block<blocks; block += blockCount) {
592                 store.seek(offset + (long)block*blockSize);
593                 byte[] buff = new byte[blockSize];
594                 DataPage s = DataPage.create(this, buff);
595                 store.readFully(buff, 0, blockSize);
596                 blockCount = s.readInt();
597                 storageId = -1;
598                 recordLength = -1;
599                 valueId = -1;
600                 if(blockCount == 0) {
601                     // free block
602
blockCount = 1;
603                     continue;
604                 } else if(blockCount < 0) {
605                     writeDataError(writer, "blockCount<0", s.getBytes(), 1);
606                     blockCount = 1;
607                     continue;
608                 } else if((blockCount * blockSize) >= Integer.MAX_VALUE / 4) {
609                     writeDataError(writer, "blockCount=" + blockCount, s.getBytes(), 1);
610                     blockCount = 1;
611                     continue;
612                 }
613                 writer.println("-- block " + block + " - " + (block + blockCount-1));
614                 try {
615                     s.checkCapacity(blockCount * blockSize);
616                 } catch(OutOfMemoryError JavaDoc e) {
617                     writeDataError(writer, "out of memory", s.getBytes(), 1);
618                     blockCount = 1;
619                     continue;
620                 }
621                 if(blockCount > 1) {
622                     if((blockCount * blockSize) < 0) {
623                         writeDataError(writer, "wrong blockCount", s.getBytes(), 1);
624                         blockCount = 1;
625                     } else {
626                         store.readFully(s.getBytes(), blockSize, blockCount * blockSize - blockSize);
627                     }
628                 }
629                 try {
630                     s.check(blockCount * blockSize);
631                 } catch(SQLException JavaDoc e) {
632                     writeDataError(writer, "wrong checksum", s.getBytes(), 1);
633                     blockCount = 1;
634                     continue;
635                 }
636                 storageId = s.readInt();
637                 if(storageId < 0) {
638                     writeDataError(writer, "storageId<0", s.getBytes(), blockCount);
639                     continue;
640                 }
641                 int page = block / DiskFile.BLOCKS_PER_PAGE;
642                 if(pageOwners[page] != 0 && pageOwners[page] != storageId) {
643                     writeDataError(writer, "double allocation, previous="+pageOwners[page]+" now="+storageId, s.getBytes(), blockCount);
644                 } else {
645                     pageOwners[page] = storageId;
646                 }
647                 recordLength = s.readInt();
648                 if(recordLength <= 0) {
649                     writeDataError(writer, "recordLength<0", s.getBytes(), blockCount);
650                     continue;
651                 }
652                 Value[] data;
653                 try {
654                     data = new Value[recordLength];
655                 } catch(OutOfMemoryError JavaDoc e) {
656                     writeDataError(writer, "out of memory", s.getBytes(), blockCount);
657                     continue;
658                 }
659                 if(!objectIdSet.contains(new Integer JavaDoc(storageId))) {
660                     objectIdSet.add(new Integer JavaDoc(storageId));
661                     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
662                     sb.append("CREATE TABLE O_" + storageId + "(");
663                     for(int i=0; i<recordLength; i++) {
664                         if(i>0) {
665                             sb.append(", ");
666                         }
667                         sb.append("C");
668                         sb.append(i);
669                         sb.append(" VARCHAR");
670                     }
671                     sb.append(");");
672                     writer.println(sb.toString());
673                     writer.flush();
674                 }
675                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
676                 sb.append("INSERT INTO O_" + storageId + " VALUES(");
677                 for(valueId=0; valueId<recordLength; valueId++) {
678                     try {
679                         Value v = s.readValue();
680                         data[valueId] = v;
681                         if(valueId>0) {
682                             sb.append(", ");
683                         }
684                         sb.append(v.getSQL());
685                     } catch(Exception JavaDoc e) {
686                         writeDataError(writer, "exception " + e, s.getBytes(), blockCount);
687                         continue;
688                     } catch(OutOfMemoryError JavaDoc e) {
689                         writeDataError(writer, "out of memory", s.getBytes(), blockCount);
690                         continue;
691                     }
692                 }
693                 sb.append(");");
694                 writer.println(sb.toString());
695                 writer.flush();
696                 if(storageId == 0) {
697                     try {
698                         SimpleRow r = new SimpleRow(data);
699                         MetaRecord meta = new MetaRecord(r);
700                         schema.add(meta);
701                         if(meta.getObjectType() == DbObject.TABLE_OR_VIEW) {
702                             String JavaDoc sql = data[3].getString();
703                             int end = sql.indexOf('(');
704                             if(end >= 0) {
705                                 int start = sql.lastIndexOf(' ', end);
706                                 String JavaDoc name = sql.substring(start, end).trim();
707                                 tableMap.put(new Integer JavaDoc(meta.getId()), name);
708                             }
709                         }
710                     } catch(Throwable JavaDoc t) {
711                         writeError(writer, t);
712                     }
713                 }
714             }
715             MetaRecord.sort(schema);
716             for(int i=0; i<schema.size(); i++) {
717                 MetaRecord m = (MetaRecord) schema.get(i);
718                 writer.println(m.getSQL() + ";");
719             }
720             for(Iterator JavaDoc it = tableMap.entrySet().iterator(); it.hasNext(); ) {
721                 Map.Entry JavaDoc entry = (Entry) it.next();
722                 Integer JavaDoc objectId = (Integer JavaDoc) entry.getKey();
723                 String JavaDoc name = (String JavaDoc) entry.getValue();
724                 writer.println("INSERT INTO " + name +" SELECT * FROM O_" + objectId + ";");
725             }
726             for(Iterator JavaDoc it = objectIdSet.iterator(); it.hasNext(); ) {
727                 Integer JavaDoc objectId = (Integer JavaDoc) it.next();
728                 writer.println("DROP TABLE O_" + objectId + ";");
729             }
730         } catch(Throwable JavaDoc e) {
731             writeError(writer, e);
732         } finally {
733             IOUtils.closeSilently(writer);
734             closeSilently(store);
735         }
736     }
737
738     private void closeSilently(FileStore store) {
739         if(store != null) {
740             store.closeSilently();
741             store = null;
742         }
743     }
744     
745     private void writeError(PrintWriter JavaDoc writer, Throwable JavaDoc e) {
746         if(writer != null) {
747             writer.println("// error: "+ e);
748         }
749         logError("Error", e);
750     }
751
752     /**
753      * INTERNAL
754      */

755     public boolean getTextStorage() {
756         return textStorage;
757     }
758
759     /**
760      * INTERNAL
761      */

762     public String JavaDoc getDatabasePath() {
763         return databaseName;
764     }
765
766     /**
767      * INTERNAL
768      */

769     public FileStore openFile(String JavaDoc name, boolean mustExist) throws SQLException JavaDoc {
770         return null;
771     }
772
773     /**
774      * INTERNAL
775      */

776     public int getChecksum(byte[] data, int start, int end) {
777         int x = 0;
778         while(start < end) {
779             x += data[start++];
780         }
781         return x;
782     }
783
784     /**
785      * INTERNAL
786      */

787     public void checkPowerOff() throws SQLException JavaDoc {
788     }
789
790     /**
791      * INTERNAL
792      */

793     public void checkWritingAllowed() throws SQLException JavaDoc {
794     }
795
796     /**
797      * INTERNAL
798      */

799     public void freeUpDiskSpace() throws SQLException JavaDoc {
800     }
801
802     /**
803      * INTERNAL
804      */

805     public void handleInvalidChecksum() throws SQLException JavaDoc {
806     }
807
808     /**
809      * INTERNAL
810      */

811     public int compareTypeSave(Value a, Value b) throws SQLException JavaDoc {
812         throw Message.getInternalError();
813     }
814
815     /**
816      * INTERNAL
817      */

818     public int getMaxLengthInplaceLob() {
819         throw Message.getInternalError();
820     }
821
822     /**
823      * INTERNAL
824      */

825     public int allocateObjectId(boolean b, boolean c) {
826         throw Message.getInternalError();
827     }
828
829     /**
830      * INTERNAL
831      */

832     public String JavaDoc createTempFile() throws SQLException JavaDoc {
833         throw Message.getInternalError();
834     }
835
836     /**
837      * INTERNAL
838      */

839     public String JavaDoc getLobCompressionAlgorithm(int type) {
840         return null;
841     }
842
843 }
844
Popular Tags