UpdateRow.java :  » Database-DBMS » Quadcap-Embeddable-Database » com » quadcap » sql » Java Open Source

Java Open Source » Database DBMS » Quadcap Embeddable Database 
Quadcap Embeddable Database » com » quadcap » sql » UpdateRow.java
package com.quadcap.sql;

/* Copyright 1999 - 2003 Quadcap Software.  All rights reserved.
 *
 * This software is distributed under the Quadcap Free Software License.
 * This software may be used or modified for any purpose, personal or
 * commercial.  Open Source redistributions are permitted.  Commercial
 * redistribution of larger works derived from, or works which bundle
 * this software requires a "Commercial Redistribution License"; see
 * http://www.quadcap.com/purchase.
 *
 * Redistributions qualify as "Open Source" under  one of the following terms:
 *   
 *    Redistributions are made at no charge beyond the reasonable cost of
 *    materials and delivery.
 *
 *    Redistributions are accompanied by a copy of the Source Code or by an
 *    irrevocable offer to provide a copy of the Source Code for up to three
 *    years at the cost of materials and delivery.  Such redistributions
 *    must allow further use, modification, and redistribution of the Source
 *    Code under substantially the same terms as this license.
 *
 * Redistributions of source code must retain the copyright notices as they
 * appear in each source code file, these license terms, and the
 * disclaimer/limitation of liability set forth as paragraph 6 below.
 *
 * Redistributions in binary form must reproduce this Copyright Notice,
 * these license terms, and the disclaimer/limitation of liability set
 * forth as paragraph 6 below, in the documentation and/or other materials
 * provided with the distribution.
 *
 * The Software is provided on an "AS IS" basis.  No warranty is
 * provided that the Software is free of defects, or fit for a
 * particular purpose.  
 *
 * Limitation of Liability. Quadcap Software shall not be liable
 * for any damages suffered by the Licensee or any third party resulting
 * from use of the Software.
 */

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.OutputStream;

import java.util.Vector;

import java.sql.SQLException;

import com.quadcap.sql.io.Arrays;
import com.quadcap.sql.io.ObjectInputStream;
import com.quadcap.sql.io.ObjectOutputStream;
import com.quadcap.sql.io.Extern;

import com.quadcap.sql.file.BlockFile;
import com.quadcap.sql.file.Datafile;
import com.quadcap.sql.file.Log;
import com.quadcap.sql.file.PageManager;
import com.quadcap.sql.file.SubPageManager;

import com.quadcap.sql.index.Btree;

import com.quadcap.sql.types.Value;
import com.quadcap.sql.types.ValueBlob;

import com.quadcap.util.Debug;
import com.quadcap.util.Util;

/**
 * Log step to update one or more values in a table row.
 *
 * @author Stan Bailes
 */
public class UpdateRow extends LogStep implements Externalizable {
    transient Table    table      = null;

    String       tableName    = null;
    Row                         memRow;
    Row                         oldRow;
    byte[]      rowBytes    = null;
    byte[]      oldRowBytes    = null;
    long      rowId      = -1;

    /**
     * Default Constructor
     */
    public UpdateRow() {}

    /**
     * Construct update for specified table row
     */
    public UpdateRow(Session session, Table table, long rowId, Row row)
  throws IOException, SQLException
    {
        super(session);
        init(session, table, rowId, row);
    }

    /**
     * Construct update where both old and new rows are already prepared.
     */
    public UpdateRow(Session session, long rowId, Row orow,
                     Row nrow)
  throws IOException, SQLException
    {
        super(session);
        init(session, null, rowId, nrow);
        oldRow = orow;
    }

    /**
     * Construct update for specified table row
     */
    public UpdateRow(Session session, Table table, long rowId,
                     byte[] oldRowBytes, byte[] rowBytes)
  throws IOException, SQLException
    {
        super(session);
        if (session.getDatabase().inMemory()) {
            throw new SQLException("in Memory Database: internal error");
        }
        initx(table, rowId, oldRowBytes, rowBytes);
    }

    /**
     * Special re=init for add/drop column
     */
    public void initx(Table table, long rowId, byte[] oldRowBytes,
                     byte[] rowBytes) {
  this.table = table;
  this.tableName = table.getName();
  this.rowBytes = copy(rowBytes);
        this.oldRowBytes = copy(oldRowBytes);
  this.rowId = rowId;
    }

    final byte[] copy(byte[] b) {
        byte[] r = new byte[b.length];
        System.arraycopy(b, 0, r, 0, b.length);
        return r;
    }
    
    /**
     * Explicit init/reinit
     */
    public void init(Session session, Table table, long rowId, Row row)
  throws IOException, SQLException
    {
  this.table = table;
  this.tableName = table == null ? null : table.getName();
        if (session.getDatabase().inMemory()) {
            this.memRow = row;
        } else {
            this.rowBytes = LazyRow.writeRow(session, table, row);
        }
  this.rowId = rowId;
    }

    /**
     * Lazy table accessor
     */
    Table getTable(Database db) throws IOException {
  if (table == null && tableName != null) {
      table = (Table)db.getRelation(tableName);
  }
  return table;
    }

    /**
     * Instantiate the row from the serialized byte array (if necessary)
     */
    final LazyRow getRow(Datafile db) throws IOException, SQLException {
        LazyRow r = new LazyRow(table.getColumnCount());
        r.reset(rowBytes, db);
  return r;
    }

    /**
     * LogStep.redo(): blob accounting if necessary, then update the
     * row in the database
     */
    public void redo(Session session) throws IOException, SQLException {
  Database db = session.getDatabase();
  BlockFile file = db.getFile();

        if (session.getConnection().inRecovery()) {
            Log log = session.getLog();
            getTable(db);
            
            // The row may contain blobs which have been mapped.
            if (table.hasBlobs()) {
                boolean anyChanged = false;
                Row row = getRow(db);
                for (int i = 1; i <= row.size(); i++) {
                    Value v = row.item(i);
                    if (v instanceof ValueBlob) {
                        ValueBlob vb = (ValueBlob)v;
                        long blk = vb.getPermBlock();
                        long blk2 = log.getRowMap(blk);
                        if (blk != blk2) {
                            vb.setPermBlock(blk2);
                            anyChanged = true;
                        }
                    }
                }
                if (anyChanged) {
                    row.set(1, row.item(1));
                    if (!db.inMemory()) {
                        this.rowBytes = LazyRow.writeRow(session, table, row);
                    }
                }
            }
            rowId = log.getRowMap(rowId);
        }
        if (db.inMemory()) {
            db.putRow(session, getTable(db), rowId, memRow);
        } else {
            file.updateBytes(rowId, rowBytes);
        }
        session.incrUpdateCount();
    }

    /**
     * LogStep.do(): blob accounting if necessary, then restore the
     * old row in the database
     */
    public void undo(Session session) throws IOException, SQLException {
        Database db = session.getDatabase();
  BlockFile file = db.getFile();
  Log log = session.getLog();

        long actualRowId = log.getRowMap(rowId);
        if (db.inMemory()) {
            db.putRow(session, getTable(db), rowId, oldRow);
        } else {
            file.updateBytes(actualRowId, oldRowBytes);
        }
        session.decrUpdateCount();
    }

    /**
     * Get ready...
     */
    public void prepare(Session session) throws SQLException, IOException {
        if (session.getDatabase().inMemory()) {
            if (oldRow == null) {
                oldRow = table.getRow(session.getDatabase(), rowId);
            }
        } else {
            if (oldRowBytes == null) {
                oldRowBytes = session.getFile().getBytes(rowId);
            }
        }
    }

    /**
     * Read me from a stream
     */
    public void readExternal(ObjectInput in)
  throws IOException, ClassNotFoundException
    {
  super.readExternal(in);
  tableName = (String)in.readObject();
  rowId = in.readLong();
  
  rowBytes = Arrays.readBytes(in);
  oldRowBytes = Arrays.readBytes(in);

    }

    /**
     * Write me to a stream
     */
    public void writeExternal(ObjectOutput out) throws IOException {
  super.writeExternal(out);
  out.writeObject(tableName);
  out.writeLong(rowId);

  Arrays.writeBytes(out, rowBytes);
  Arrays.writeBytes(out, oldRowBytes);

    }

    //#ifdef DEBUG
    /**
     * Return a string representation for debugging
     */
    public String toString() {
  StringBuffer sb = new StringBuffer(super.toString());
        sb.append(" UpdateRow(");
  sb.append(SubPageManager.toString(rowId));
        if (true) {
            sb.append(",[");
            sb.append(Util.hexBytes(oldRowBytes));
            sb.append("] -> [");
            sb.append(Util.hexBytes(rowBytes));
            sb.append("]");
        }
  sb.append(')');
  return sb.toString();
    }
    //#endif

    /**
     * My class's Extern object
     */
    static Extern extern;
    public void setExtern(Extern extern) { UpdateRow.extern = extern; }
    public Extern getExtern() { return extern; }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.