1 13 package com.sqlmagic.tinysql; 14 15 import java.util.*; 16 import java.lang.*; 17 import java.io.*; 18 import java.sql.Types ; 19 20 28 public class dbfFile extends tinySQL { 29 30 public static String dataDir; 31 public static boolean debug=false; 32 private Vector tableList=new Vector(); 33 static { 34 35 try { 36 dataDir = System.getProperty("user.home") + File.separator + ".tinySQL"; 37 } catch (Exception e) { 38 System.err.println("tinySQL: unable to get user.home property, "+ 39 "reverting to current working directory."); 40 dataDir = "." + File.separator + ".tinySQL"; 41 } 42 43 } 44 45 50 public dbfFile() { 51 52 super(); 53 if ( debug ) System.out.println("Set datadir=" + dataDir); 54 55 } 56 57 64 public dbfFile( String d ) { 65 66 super(); 67 dataDir = d; if ( debug ) System.out.println("Set datadir=" + dataDir); 69 70 } 71 72 73 83 void setDataDir( String d) 84 { 85 89 dataDir = d; 90 } 91 void CreateTable ( String tableName, Vector v ) 92 throws IOException, tinySQLException { 93 94 int numCols = v.size(); 97 int recordLength = 1; for (int i = 0; i < numCols; i++) { 99 tsColumn coldef = ((tsColumn) v.elementAt(i)); 100 recordLength += coldef.size; 101 } 102 103 DBFHeader dbfHeader = new DBFHeader(numCols, recordLength); 106 RandomAccessFile ftbl = dbfHeader.create(dataDir, tableName); 107 108 for (int i = 0; i < v.size(); i++) { 111 tsColumn coldef = ((tsColumn) v.elementAt(i)); 112 Utils.log("CREATING COL=" + coldef.name); 113 writeColdef(ftbl, coldef); 114 } 115 116 ftbl.write((byte)0x0d); 118 ftbl.close(); 119 } 120 121 122 133 void AlterTableAddCol ( String tableName, Vector v ) 134 throws IOException, tinySQLException { 135 136 String fullpath = dataDir + File.separator + tableName + dbfFileTable.dbfExtension; 138 String tmppath = dataDir + File.separator + tableName + "_tmp_tmp" + dbfFileTable.dbfExtension; 139 if (Utils.renameFile(fullpath, tmppath) == false) 140 throw new tinySQLException("ALTER TABLE ADD COL error in renaming " + fullpath); 141 142 try { 143 RandomAccessFile ftbl_tmp = new RandomAccessFile(tmppath, "r"); 145 146 DBFHeader dbfHeader_tmp = new DBFHeader(ftbl_tmp); 148 149 Vector coldef_list = new Vector(dbfHeader_tmp.numFields + v.size()); 151 int locn = 0; for (int i = 1; i <= dbfHeader_tmp.numFields; i++) { 153 tsColumn coldef = readColdef(ftbl_tmp, tableName, i, locn); 154 locn += coldef.size; coldef_list.addElement(coldef); 156 } 157 158 for (int jj = 0; jj < v.size(); jj++) 160 coldef_list.addElement(v.elementAt(jj)); 161 162 CreateTable(tableName, coldef_list); 164 165 167 RandomAccessFile ftbl = new RandomAccessFile(fullpath, "rw"); 169 ftbl.seek(ftbl.length()); 171 int numRec = 0; 172 for (int iRec=1; iRec<=dbfHeader_tmp.numRecords; iRec++) { 173 174 String str = GetRecord(ftbl_tmp, dbfHeader_tmp, iRec); 175 176 178 if (str == null) continue; 180 ftbl.write(str.getBytes(Utils.encode)); numRec++; 182 183 for (int iCol = 0; iCol < v.size(); iCol++) { 185 tsColumn coldef = (tsColumn)v.elementAt(iCol); 186 187 String value = Utils.forceToSize(coldef.defaultVal, coldef.size, " "); 189 190 byte[] b = value.getBytes(Utils.encode); 192 ftbl.write(b); 193 } 194 } 195 196 ftbl_tmp.close(); 197 198 DBFHeader.writeNumRecords(ftbl, numRec); 199 ftbl.close(); 200 201 Utils.delFile(tmppath); 202 203 } catch (Exception e) { 204 throw new tinySQLException(e.getMessage()); 205 } 206 } 207 208 209 210 218 public String GetRecord(RandomAccessFile ff, DBFHeader dbfHeader, int recordNumber) throws tinySQLException 219 { 220 if (recordNumber < 1) 221 throw new tinySQLException("Internal error - current record number < 1"); 222 223 try { 224 ff.seek(dbfHeader.headerLength + (recordNumber - 1) * dbfHeader.recordLength); 227 228 byte[] b = new byte[dbfHeader.recordLength]; 231 ff.readFully(b); 232 233 String record = new String (b, Utils.encode); 235 236 if (dbfFileTable.isDeleted(record)) 238 return null; 239 240 return record; 241 242 } catch (Exception e) { 243 throw new tinySQLException(e.getMessage()); 244 } 245 } 246 247 248 260 void AlterTableDropCol ( String tableName, Vector v ) 261 throws IOException, tinySQLException { 262 263 String fullpath = dataDir + File.separator + tableName + dbfFileTable.dbfExtension; 265 String tmppath = dataDir + File.separator + tableName + "-tmp" + dbfFileTable.dbfExtension; 266 if (Utils.renameFile(fullpath, tmppath) == false) 267 throw new tinySQLException("ALTER TABLE DROP COL error in renaming " + fullpath); 268 269 try { 270 RandomAccessFile ftbl_tmp = new RandomAccessFile(tmppath, "r"); 272 273 DBFHeader dbfHeader_tmp = new DBFHeader(ftbl_tmp); 275 276 Vector coldef_list = new Vector(dbfHeader_tmp.numFields - v.size()); 278 int locn = 0; 280 nextCol: for (int i = 1; i <= dbfHeader_tmp.numFields; i++) { 281 282 tsColumn coldef = readColdef(ftbl_tmp, tableName, i, locn); 283 284 for (int jj = 0; jj < v.size(); jj++) { 286 String colName = (String )v.elementAt(jj); 287 if (coldef.name.equals(colName)) { 288 Utils.log("Dropping " + colName); 289 continue nextCol; 290 } 291 } 292 293 locn += coldef.size; coldef_list.addElement(coldef); 296 } 297 298 CreateTable(tableName, coldef_list); 300 301 303 RandomAccessFile ftbl = new RandomAccessFile(fullpath, "rw"); 305 ftbl.seek(ftbl.length()); 307 int numRec = 0; 308 for (int iRec=1; iRec<=dbfHeader_tmp.numRecords; iRec++) { 309 310 if (dbfFileTable.isDeleted(ftbl_tmp, dbfHeader_tmp, iRec) == true) continue; 311 312 numRec++; 313 314 ftbl.write(dbfFileTable.RECORD_IS_NOT_DELETED); 316 String column = dbfFileTable._GetCol(ftbl_tmp, dbfHeader_tmp, iRec); 318 319 for (int iCol = 0; iCol < coldef_list.size(); iCol++) { 321 tsColumn coldef = (tsColumn)coldef_list.elementAt(iCol); 322 323 String value = dbfFileTable.getColumn (coldef, column); 325 326 value = Utils.forceToSize(value, coldef.size, " "); 328 byte[] b = value.getBytes(Utils.encode); ftbl.write(b); 330 } 331 } 332 333 ftbl_tmp.close(); 334 335 File f = new File(tmppath); 337 if (f.exists()) 338 f.delete(); 339 340 DBFHeader.writeNumRecords(ftbl, numRec); 341 ftbl.close(); 342 343 } catch (Exception e) { 344 throw new tinySQLException(e.getMessage()); 345 } 346 } 347 348 349 354 void AlterTableRenameCol (String tableName, String oldColname, String newColname) 355 throws IOException, tinySQLException 356 { 357 String fullpath = dataDir + File.separator + tableName + dbfFileTable.dbfExtension; 358 359 try { 360 RandomAccessFile ftbl = new RandomAccessFile(fullpath, "rw"); 361 362 DBFHeader dbfHeader = new DBFHeader(ftbl); 364 int locn = 0; for (int iCol = 1; iCol <= dbfHeader.numFields; iCol++) { 366 tsColumn coldef = readColdef(ftbl, tableName, iCol, locn); 367 if (coldef.name.equals(oldColname)) { 368 Utils.log("Replacing column name '" + oldColname + "' with '" + newColname + "'"); 369 ftbl.seek( (iCol - 1) * 32 + 32 ); 370 ftbl.write(Utils.forceToSize(newColname, 371 dbfFileTable.FIELD_TYPE_INDEX-dbfFileTable.FIELD_NAME_INDEX, 372 (byte)0)); 373 ftbl.close(); 374 return; 375 } 376 } 377 ftbl.close(); 378 throw new tinySQLException("Renaming of column name '" + oldColname + "' to '" + newColname + "' failed, no column '" + oldColname + "' found"); 379 } catch (Exception e) { 380 throw new tinySQLException(e.getMessage()); 381 } 382 383 } 384 385 393 tinySQLTable getTable (String tableName) throws tinySQLException 394 { 395 int i,tableIndex; 396 tinySQLTable nextTable; 397 tableIndex = Integer.MIN_VALUE; 398 if ( debug ) System.out.println("Trying to create table object for " 399 + tableName); 400 for ( i = 0; i < tableList.size(); i++ ) 401 { 402 nextTable = (tinySQLTable)tableList.elementAt(i); 403 if ( nextTable.table.equals(tableName) ) 404 { 405 if ( nextTable.isOpen() ) 406 { 407 if ( debug ) 408 System.out.println("Found in cache " + nextTable.toString()); 409 return nextTable; 410 } 411 tableIndex = i; 412 break; 413 } 414 } 415 if ( tableIndex == Integer.MIN_VALUE ) 416 { 417 tableList.addElement(new dbfFileTable(dataDir,tableName)); 418 nextTable = (tinySQLTable)tableList.lastElement(); 419 if ( debug ) System.out.println("Add to cache " + nextTable.toString()); 420 return (tinySQLTable)tableList.lastElement(); 421 } else { 422 tableList.setElementAt(new dbfFileTable(dataDir,tableName),tableIndex); 423 nextTable = (tinySQLTable)tableList.elementAt(tableIndex); 424 if ( debug ) System.out.println("Update in cache " + nextTable.toString()); 425 return (tinySQLTable)tableList.elementAt(tableIndex); 426 } 427 } 428 429 438 void DropTable (String fname) throws tinySQLException { 439 DBFHeader.dropTable(dataDir, fname); 440 } 441 442 443 450 static tsColumn readColdef(RandomAccessFile ff, String tableName, int iCol, int locn) throws tinySQLException 451 { 452 try { 453 ff.seek( (iCol - 1) * 32 + 32 ); 458 459 byte[] b = new byte[11]; 462 ff.readFully(b); 463 464 boolean clear = false; 470 int i = 0; 471 while ((i < 11) && (b[i] != 0)) 472 { 473 i++; 474 } 475 while (i < 11) 476 { 477 b[i] = 0; 478 i++; 479 } 480 String colName = (new String (b, Utils.encode)).trim(); 481 482 byte c[]= new byte[1]; 485 c[0]= ff.readByte(); 486 String ftyp= new String (c, Utils.encode); 487 488 ff.skipBytes(4); 491 492 short flen = Utils.fixByte(ff.readByte()); short fdec = Utils.fixByte(ff.readByte()); if ( ftyp.equals("N") & fdec == 0 ) ftyp = "I"; 498 499 501 tsColumn column = new tsColumn(colName); 505 508 column.type = typeToSQLType(ftyp); 509 column.size = flen; 510 column.decimalPlaces = fdec; 511 column.position = locn + 1; column.table = tableName; 513 return column; 514 515 } catch (Exception e) { 516 throw new tinySQLException(e.getMessage()); 517 } 518 } 519 520 526 void writeColdef(RandomAccessFile ff, tsColumn coldef) throws tinySQLException 527 { 528 530 try { 531 ff.write(Utils.forceToSize(coldef.name, 532 dbfFileTable.FIELD_TYPE_INDEX-dbfFileTable.FIELD_NAME_INDEX, 533 (byte)0)); 534 535 String type = null; 537 if (coldef.type == Types.CHAR || coldef.type == Types.VARCHAR || coldef.type == Types.LONGVARCHAR) 538 type = "C"; 539 else 540 if (coldef.type == Types.NUMERIC || coldef.type == Types.INTEGER || 541 coldef.type == Types.TINYINT || coldef.type == Types.SMALLINT || 542 coldef.type == Types.BIGINT || coldef.type == Types.FLOAT || 543 coldef.type == Types.DOUBLE || coldef.type == Types.REAL) 544 type = "N"; 545 else 546 if (coldef.type == Types.BIT) 547 type = "L"; 548 else 549 if (coldef.type == Types.DATE) 550 type = "D"; 551 else 552 type = "M"; 553 554 ff.write(Utils.forceToSize(type, 555 1, 556 (byte)0)); 557 558 ff.write(Utils.forceToSize(null, 559 4, 560 (byte)0)); 562 ff.write(coldef.size); 564 ff.write(coldef.decimalPlaces); 566 ff.write(Utils.forceToSize(null, 567 DBFHeader.BULK_SIZE-dbfFileTable.FIELD_RESERVED_INDEX, 568 (byte)0)); 569 } catch (Exception e) { 570 throw new tinySQLException(e.getMessage()); 571 } 572 } 573 574 575 584 static String typeToLiteral(int type) 585 { 586 if (type == Types.CHAR) return "CHAR"; 587 if (type == Types.VARCHAR) return "VARCHAR"; 588 if (type == Types.FLOAT) return "FLOAT"; 589 if (type == Types.NUMERIC) return "NUMERIC"; 590 if (type == Types.INTEGER) return "INT"; 591 if (type == Types.BIT) return "BIT"; 592 if (type == Types.BINARY) return "BINARY"; 593 if (type == Types.DATE) return "DATE"; 594 return "CHAR"; } 596 597 598 605 static int typeToSQLType(String type) 606 { 607 if (type.equals("C")) return java.sql.Types.CHAR; 608 if (type.equals("N")) return java.sql.Types.FLOAT; 609 if (type.equals("I")) return java.sql.Types.INTEGER; 610 if (type.equals("L")) return java.sql.Types.CHAR; 611 if (type.equals("M")) return java.sql.Types.INTEGER; 612 if (type.equals("D")) return java.sql.Types.DATE; 613 return java.sql.Types.CHAR; } 615 } 616 | Popular Tags |