/** * * Insert a row. If c or v == null, insert a blank row * * @param c Ordered Vector of column names * @param v Ordered Vector (must match order of c) of values * @see tinySQLTable#InsertRow() * */ public override void InsertRow(java.util.Vector <Object> c, java.util.Vector <Object> v) {// throws tinySQLException { try { // go to the end of the file // ftbl.seek(ftbl.length()); // write out the deleted indicator // ftbl.write('N'); // write out a blank record // for (int i = 1; i < record_length; i++) { ftbl.write(' '); } ftbl.write('\n'); // reposition at start of current record // ftbl.seek(ftbl.getFilePointer() - (record_length + 1)); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } if (c != null && v != null) { UpdateCurrentRow(c, v); } }
internal override void CreateTable(String tableName, java.util.Vector <Object> v) {// throws IOException, tinySQLException { //--------------------------------------------------- // determin meta data .... int numCols = v.size(); int recordLength = 1; // 1 byte for the flag field for (int i = 0; i < numCols; i++) { TsColumn coldef = ((TsColumn)v.elementAt(i)); recordLength += coldef.size; } //--------------------------------------------------- // create the new dBase file ... DBFHeader dbfHeader = new DBFHeader(numCols, recordLength); java.io.RandomAccessFile ftbl = dbfHeader.create(dataDir, tableName); //--------------------------------------------------- // write out the rest of the columns' definition. for (int i = 0; i < v.size(); i++) { TsColumn coldef = ((TsColumn)v.elementAt(i)); Utils.log("CREATING COL=" + coldef.name); writeColdef(ftbl, coldef); } ftbl.write((byte)0x0d); // header section ends with CR (carriage return) ftbl.close(); }
/* * Rename columns * * ALTER TABLE table RENAME war TO peace */ internal override void AlterTableRenameCol(String tableName, String oldColname, String newColname) //throws tinySQLException { String fullpath = dataDir + java.io.File.separator + tableName + DBFFileTable.dbfExtension; try { java.io.RandomAccessFile ftbl = new java.io.RandomAccessFile(fullpath, "rw"); DBFHeader dbfHeader = new DBFHeader(ftbl); // read the first 32 bytes ... int locn = 0; // offset of the current column for (int iCol = 1; iCol <= dbfHeader.numFields; iCol++) { TsColumn coldef = readColdef(ftbl, tableName, iCol, locn); if (coldef.name.equals(oldColname)) { Utils.log("Replacing column name '" + oldColname + "' with '" + newColname + "'"); ftbl.seek((iCol - 1) * 32 + 32); ftbl.write(Utils.forceToSize(newColname, DBFFileTable.FIELD_TYPE_INDEX - DBFFileTable.FIELD_NAME_INDEX, (byte)0)); ftbl.close(); return; } } ftbl.close(); throw new TinySQLException("Renaming of column name '" + oldColname + "' to '" + newColname + "' failed, no column '" + oldColname + "' found"); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
public void setTimestamp(java.io.RandomAccessFile ff) //throws tinySQLException { try { java.util.Calendar cal = java.util.Calendar.getInstance(); cal.setTime(new java.util.Date()); int dd = cal.get(java.util.Calendar.DAY_OF_MONTH); int mm = cal.get(java.util.Calendar.MONTH) + 1; int yy = cal.get(java.util.Calendar.YEAR); yy = yy % 100; // Y2K problem: only 2 digits ff.seek(DATE_INDEX); ff.write(yy); ff.write(mm); ff.write(dd); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * Write bytes to output or random access file. * @param data the byte array to write * @param offset the start position to write from * @param length the number of bytes to write * @throws IOException on error */ protected void writeOut(byte[] data, int offset, int length) //throws IOException { if (raf != null) { raf.write(data, offset, length); } else { outJ.write(data, offset, length); } }
/** * Writing a column definition to file<br> * NOTE: the file pointer (seek()) must be at the correct position * @param ff file handle (correctly positioned) * @param coldef struct with column info */ void writeColdef(java.io.RandomAccessFile ff, TsColumn coldef) //throws tinySQLException { // Utils.log("Writing Field Def: coldef.name=" + coldef.name + ", coldef.type=" + coldef.type + ", cildef.size=" + coldef.size); try { ff.write(Utils.forceToSize(coldef.name, DBFFileTable.FIELD_TYPE_INDEX - DBFFileTable.FIELD_NAME_INDEX, (byte)0)); // Convert the Java.SQL.Type back to a DBase Type and write it String type = null; if (coldef.type == java.sql.Types.CHAR || coldef.type == java.sql.Types.VARCHAR || coldef.type == java.sql.Types.LONGVARCHAR) { type = "C"; } else if (coldef.type == java.sql.Types.NUMERIC || coldef.type == java.sql.Types.INTEGER || coldef.type == java.sql.Types.TINYINT || coldef.type == java.sql.Types.SMALLINT || coldef.type == java.sql.Types.BIGINT || coldef.type == java.sql.Types.FLOAT || coldef.type == java.sql.Types.DOUBLE || coldef.type == java.sql.Types.REAL) { type = "N"; } else if (coldef.type == java.sql.Types.BIT) { type = "L"; } else if (coldef.type == java.sql.Types.DATE) { type = "D"; } else { type = "M"; } ff.write(Utils.forceToSize(type, 1, (byte)0)); ff.write(Utils.forceToSize(null, 4, (byte)0)); // imu field (in memory use) 12-15 ff.write(coldef.size); // one byte ff.write(coldef.decimalPlaces); // one byte ff.write(Utils.forceToSize(null, DBFHeader.BULK_SIZE - DBFFileTable.FIELD_RESERVED_INDEX, (byte)0)); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * Update the header (index 10-11) with the length of one record * @param recordLength Length of one data record (row) */ public void setRecordLength(java.io.RandomAccessFile ff, int recordLength) //throws tinySQLException { this.recordLength = recordLength; try { ff.seek(DBFHeader.LENGTH_OF_REC_INDEX); ff.write(Utils.shortToLittleEndian((short)recordLength)); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * Update the header (index 4-7) with the new number of records <br> * This is the static variant (use it if you don't want to obtain * a DBFHeader instance * @param New number of records */ public static void writeNumRecords(java.io.RandomAccessFile ff, int numRecords) //throws tinySQLException { try { byte[] b = Utils.intToLittleEndian(numRecords); ff.seek(NUMBER_OF_REC_INDEX); ff.write(b); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/* * Insert a row. If c or v == null, insert a blank row * * @param c Ordered Vector of column names * @param v Ordered Vector (must match order of c) of values * @see tinySQLTable#InsertRow() * */ public override void InsertRow(java.util.Vector <Object> c, java.util.Vector <Object> v) //throws TinySQLException { try { /* * Go to the end of the file, then write out the not deleted indicator */ ftbl.seek(ftbl.length()); ftbl.write(RECORD_IS_NOT_DELETED); /* * Write out a blank record */ for (int i = 1; i < dbfHeader.recordLength; i++) { ftbl.write(' '); } int numRec = (int)dbfHeader.numRecords + 1; currentRecordNumber = numRec; dbfHeader.setNumRecords(ftbl, numRec); } catch (Exception e) { if (TinySQLGlobals.DEBUG) { java.lang.SystemJ.err.println(e.toString()); // e.printStackTrace(); } throw new TinySQLException(e.getMessage()); } if (c != null && v != null) { UpdateCurrentRow(c, v); } else { dbfHeader.setTimestamp(ftbl); } }
/** * Update the header (index 8-9) with the new number of records * @param numFields number of columns (used to calculate header length) */ public void setHeaderLength(java.io.RandomAccessFile ff, int numFields)// throws tinySQLException { this.numFields = numFields; try { int headerLength = (DBFHeader.BULK_SIZE + 1) + numFields * DBFHeader.BULK_SIZE; ff.seek(DBFHeader.LENGTH_OF_HEADER_INDEX); ff.write(Utils.shortToLittleEndian((short)headerLength)); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * Update the header (index 10-11) with the length of one record * @param recordLength Length of one data record (row) */ public void setReserved(java.io.RandomAccessFile ff) //throws tinySQLException { try { ff.seek(DBFHeader.RESERVED_INDEX); byte[] reserved = Utils.forceToSize(null, DBFHeader.BULK_SIZE - DBFHeader.RESERVED_INDEX, (byte)0); ff.write(reserved); // padding with \0! } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * * Deletes Columns from tableName, given a vector of * column definition (tsColumn) arrays.<br> * * ALTER TABLE table DROP [ COLUMN ] column { RESTRICT | CASCADE } * * @param tableName the name of the table * @param v a Vector containing arrays of column definitions. * @see tinySQL#AlterTableDropCol * */ internal override void AlterTableDropCol(String tableName, java.util.Vector <Object> v) {//throws IOException, tinySQLException { // rename the file ... String fullpath = dataDir + java.io.File.separator + tableName + DBFFileTable.dbfExtension; String tmppath = dataDir + java.io.File.separator + tableName + "-tmp" + DBFFileTable.dbfExtension; if (Utils.renameFile(fullpath, tmppath) == false) { throw new TinySQLException("ALTER TABLE DROP COL error in renaming " + fullpath); } try { // open the old file ... java.io.RandomAccessFile ftbl_tmp = new java.io.RandomAccessFile(tmppath, "r"); // read the first 32 bytes ... DBFHeader dbfHeader_tmp = new DBFHeader(ftbl_tmp); // read the column info ... java.util.Vector <Object> coldef_list = new java.util.Vector <Object>(dbfHeader_tmp.numFields - v.size()); int locn = 0; // offset of the current column nextCol : for (int i = 1; i <= dbfHeader_tmp.numFields; i++) { TsColumn coldef = readColdef(ftbl_tmp, tableName, i, locn); // remove the DROP columns from the existing cols ... for (int jj = 0; jj < v.size(); jj++) { String colName = (String)v.elementAt(jj); if (coldef.name.equals(colName)) { Utils.log("Dropping " + colName); goto nextCol; } } locn += coldef.size; // increment locn by the length of this field. // Utils.log("Recycling " + coldef.name); coldef_list.addElement(coldef); } // create the new table ... CreateTable(tableName, coldef_list); // copy the data from old to new // opening new created dBase file ... java.io.RandomAccessFile ftbl = new java.io.RandomAccessFile(fullpath, "rw"); ftbl.seek(ftbl.length()); // go to end of file int numRec = 0; for (int iRec = 1; iRec <= dbfHeader_tmp.numRecords; iRec++) { if (DBFFileTable.isDeleted(ftbl_tmp, dbfHeader_tmp, iRec) == true) { continue; } numRec++; ftbl.write(DBFFileTable.RECORD_IS_NOT_DELETED); // write flag // Read the whole column into the table's cache String column = DBFFileTable._GetCol(ftbl_tmp, dbfHeader_tmp, iRec); for (int iCol = 0; iCol < coldef_list.size(); iCol++) // write columns { TsColumn coldef = (TsColumn)coldef_list.elementAt(iCol); // Extract column values from cache String value = DBFFileTable.getColumn(coldef, column); java.lang.SystemJ.outJ.println("From cache column value" + value); value = Utils.forceToSize(value, coldef.size, " "); // enforce the correct column length byte[] b = value.getBytes(Utils.encode); // transform to byte and write to file ftbl.write(b); } } ftbl_tmp.close(); // remove temp file java.io.File f = new java.io.File(tmppath); if (f.exists()) { f.delete(); } DBFHeader.writeNumRecords(ftbl, numRec); ftbl.close(); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }
/** * Creates new Columns in tableName, given a vector of * column definition (tsColumn) arrays.<br> * It is necessary to copy the whole file to do this task. * * ALTER TABLE table [ * ] ADD [ COLUMN ] column type * * @param tableName the name of the table * @param v a Vector containing arrays of column definitions. * @see tinySQL#AlterTableAddCol */ internal override void AlterTableAddCol(String tableName, java.util.Vector <Object> v) {//throws IOException, tinySQLException { // rename the file ... String fullpath = dataDir + java.io.File.separator + tableName + DBFFileTable.dbfExtension; String tmppath = dataDir + java.io.File.separator + tableName + "_tmp_tmp" + DBFFileTable.dbfExtension; if (Utils.renameFile(fullpath, tmppath) == false) { throw new TinySQLException("ALTER TABLE ADD COL error in renaming " + fullpath); } try { // open the old file ... java.io.RandomAccessFile ftbl_tmp = new java.io.RandomAccessFile(tmppath, "r"); // read the first 32 bytes ... DBFHeader dbfHeader_tmp = new DBFHeader(ftbl_tmp); // read the column info ... java.util.Vector <Object> coldef_list = new java.util.Vector <Object>(dbfHeader_tmp.numFields + v.size()); int locn = 0; // offset of the current column for (int i = 1; i <= dbfHeader_tmp.numFields; i++) { TsColumn coldef = readColdef(ftbl_tmp, tableName, i, locn); locn += coldef.size; // increment locn by the length of this field. coldef_list.addElement(coldef); } // add the new column definitions to the existing ... for (int jj = 0; jj < v.size(); jj++) { coldef_list.addElement(v.elementAt(jj)); } // create the new table ... CreateTable(tableName, coldef_list); // copy the data from old to new // opening new created dBase file ... java.io.RandomAccessFile ftbl = new java.io.RandomAccessFile(fullpath, "rw"); ftbl.seek(ftbl.length()); // go to end of file int numRec = 0; for (int iRec = 1; iRec <= dbfHeader_tmp.numRecords; iRec++) { String str = GetRecord(ftbl_tmp, dbfHeader_tmp, iRec); // Utils.log("Copy of record#" + iRec + " str='" + str + "' ..."); if (str == null) { continue; // record was marked as deleted, ignore it } ftbl.write(str.getBytes(Utils.encode)); // write original record numRec++; for (int iCol = 0; iCol < v.size(); iCol++) // write added columns { TsColumn coldef = (TsColumn)v.elementAt(iCol); // enforce the correct column length String value = Utils.forceToSize(coldef.defaultVal, coldef.size, " "); // transform to byte and write to file byte[] b = value.getBytes(Utils.encode); ftbl.write(b); } } ftbl_tmp.close(); DBFHeader.writeNumRecords(ftbl, numRec); ftbl.close(); Utils.delFile(tmppath); } catch (Exception e) { throw new TinySQLException(e.getMessage()); } }