001: package com.quadcap.sql;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.Externalizable;
042: import java.io.IOException;
043: import java.io.ObjectInput;
044: import java.io.ObjectOutput;
045:
046: import java.sql.SQLException;
047:
048: import com.quadcap.sql.types.TypeBigInt;
049: import com.quadcap.sql.types.Value;
050: import com.quadcap.sql.types.ValueLong;
051:
052: import com.quadcap.util.Debug;
053:
054: /**
055: * Constraint class for SQL <b>AUTO_NUMBER</b> constraints.
056: *
057: * @author Stan Bailes
058: */
059: public class AutoNumberConstraint extends Constraint implements
060: Externalizable {
061: transient AutoNumberStep step;
062:
063: long current = -1;
064:
065: /**
066: * Default constructor
067: */
068: public AutoNumberConstraint() {
069: }
070:
071: /**
072: * Explicit name constructor
073: */
074: public AutoNumberConstraint(String name) {
075: super (name);
076: }
077:
078: /**
079: * When added, I need to number all rows which already exist in the
080: * table
081: */
082: public void add(Session session) throws SQLException {
083: if (!table.isUnderConstruction()) {
084: try {
085: Column col = getColumn();
086: col.isAutoIncr = true;
087: session.getDatabase().updateRelation(table);
088: } catch (IOException e) {
089: throw DbException.wrapThrowable(e);
090: }
091: }
092: }
093:
094: /**
095: * My column is no longer an auto-incrementer
096: */
097: public void delete(Session session) throws SQLException,
098: IOException {
099: Column col = getColumn();
100: col.isAutoIncr = false;
101: session.getDatabase().updateRelation(table);
102: }
103:
104: /**
105: * Our work is already done. (We gave out the number in checkInsert())
106: */
107: public void applyInsert(Session session, Row row, long rowId,
108: Constraint activeIndex) throws SQLException, IOException {
109: }
110:
111: /**
112: * We don't care about deletes.
113: */
114: public void checkDelete(Session session, Row row, long rowId)
115: throws SQLException, IOException {
116: }
117:
118: /**
119: * We don't care about deletes.
120: */
121: public void applyDelete(Session session, Row row, long rowId,
122: Constraint activeIndex) throws SQLException, IOException {
123: }
124:
125: static Object stepLock = new Object();
126:
127: /**
128: * If the 'with identity' field is null or not an integer
129: * we assign the number before the insert operation and increment
130: * our little counter.
131: */
132: public void checkInsert(Session session, Row row)
133: throws SQLException, IOException {
134: Column c = getColumn();
135: int col = c.getColumn();
136: boolean incr = false;
137: Value v = row.item(col);
138: Database db = session.getDatabase();
139:
140: if (Value.isNull(v)) {
141: incr = true;
142: } else {
143: Value t = v.convert(TypeBigInt.typeBigInt);
144: if (!(t instanceof ValueLong)) {
145: incr = true;
146: } else {
147: ValueLong l = (ValueLong) t;
148: current = db.getTableIdentity(table.getName());
149: if (l.longValue() >= current) {
150: current = l.longValue() + 1;
151: synchronized (stepLock) {
152: if (step == null) {
153: step = new AutoNumberStep(session, table,
154: current);
155: } else {
156: step.setCurrentId(current);
157: }
158: session.doStep(step); // go ahead and do it...
159: }
160: }
161: }
162: }
163:
164: if (incr) {
165: if (true || current < 0) {
166: // XXX We can't optimize this away in all cases, because
167: // XXX the value of 'current' that's stored locally may
168: // XXX be wrong. This can happen if the table containing
169: // XXX this constraint isn't updated properly.
170: current = db.getTableIdentity(table.getName());
171: }
172: session.setLastInsertId(current);
173: row.set(col, new ValueLong(current++));
174: // we avoid an allocation per step by doing a static allocation,
175: // but then we need to protect the shared resource from contention
176: synchronized (stepLock) {
177: if (step == null) {
178: step = new AutoNumberStep(session, table, current);
179: } else {
180: step.setCurrentId(current);
181: }
182: session.doStep(step); // go ahead and do it...
183: }
184: }
185: }
186:
187: /**
188: * We only operate during INSERT, basically.
189: */
190: public void checkUpdate(Session session, byte[] oldKey, Row row,
191: Row oldRow, long rowId, Constraint activeIndex)
192: throws SQLException, IOException {
193: }
194:
195: /**
196: * 's cool.
197: */
198: public void applyUpdate(Session session, byte[] oldKey, Row row,
199: Row oldRow, long rowId, Constraint activeIndex)
200: throws SQLException, IOException {
201: }
202:
203: /**
204: * Where did I leave off?
205: */
206: public void readExternal(ObjectInput in) throws IOException,
207: ClassNotFoundException {
208: super .readExternal(in);
209: current = in.readLong();
210: }
211:
212: /**
213: * Remember where we were.
214: */
215: public void writeExternal(ObjectOutput out) throws IOException {
216: super .writeExternal(out);
217: out.writeLong(current);
218: }
219:
220: /**
221: * Do me first.
222: */
223: public int getPriority() {
224: return 0;
225: }
226: }
|