001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.db.table;
031:
032: import com.caucho.db.index.BTree;
033: import com.caucho.db.sql.QueryContext;
034: import com.caucho.db.store.Store;
035: import com.caucho.db.store.Transaction;
036: import com.caucho.sql.SQLExceptionWrapper;
037: import com.caucho.util.L10N;
038:
039: import java.io.IOException;
040: import java.sql.SQLException;
041:
042: /**
043: * Validity constraints.
044: */
045: public class UniqueSingleColumnConstraint extends Constraint {
046: private final static L10N L = new L10N(
047: UniqueSingleColumnConstraint.class);
048: private final Column _uniqueColumn;
049:
050: /**
051: * Creates a uniqueness constraint.
052: */
053: public UniqueSingleColumnConstraint(Column column) {
054: _uniqueColumn = column;
055: }
056:
057: /**
058: * validate the constraint.
059: */
060: public void validate(TableIterator[] sourceRows,
061: QueryContext queryContext, Transaction xa)
062: throws SQLException {
063: Column column = _uniqueColumn;
064: int columnOffset = column.getColumnOffset();
065:
066: BTree index = column.getIndex();
067:
068: if (index != null) {
069: validateIndex(sourceRows, queryContext, xa);
070: return;
071: }
072:
073: TableIterator sourceRow = sourceRows[0];
074: String value = null;
075:
076: Table table = sourceRow.getTable();
077: TableIterator iter = table.createTableIterator();
078:
079: try {
080: byte[] sourceBuffer = sourceRow.getBuffer();
081: int sourceOffset = sourceRow.getRowOffset();
082:
083: iter.init(queryContext);
084:
085: while (iter.next()) {
086: byte[] iterBuffer = iter.getBuffer();
087:
088: iter.prevRow();
089:
090: while (iter.nextRow()) {
091: int iterOffset = iter.getRowOffset();
092:
093: if (iterBuffer == sourceBuffer
094: && iterOffset == sourceOffset)
095: continue;
096:
097: if (column.isEqual(iterBuffer, iterOffset,
098: sourceBuffer, sourceOffset))
099: throw new SQLException(
100: L
101: .l(
102: "`{0}' in {1}.{2} fails uniqueness constraint.",
103: column.getString(
104: iterBuffer,
105: iterOffset),
106: table.getName(), column
107: .getName()));
108: }
109: }
110: } catch (IOException e) {
111: throw new SQLExceptionWrapper(e);
112: } finally {
113: iter.free();
114: }
115: }
116:
117: /**
118: * validate the constraint.
119: */
120: private void validateIndex(TableIterator[] sourceRows,
121: QueryContext context, Transaction xa) throws SQLException {
122: try {
123: Column column = _uniqueColumn;
124: TableIterator sourceRow = sourceRows[0];
125:
126: byte[] sourceBuffer = sourceRow.getBuffer();
127: int sourceOffset = sourceRow.getRowOffset();
128:
129: byte[] buffer = context.getBuffer();
130:
131: BTree index = column.getIndex();
132:
133: /*
134: int length = column.evalToBuffer(sourceBuffer, sourceOffset,
135: buffer, 0);
136:
137: if (length <= 0)
138: return;
139:
140: long value = index.lookup(buffer, 0, length,
141: context.getTransaction());
142:
143: */
144:
145: // currently this is a static length. See StringColumn.
146: int length = column.getLength();
147: int offset = sourceOffset + _uniqueColumn.getColumnOffset();
148: long value = index.lookup(sourceBuffer, offset, length,
149: context.getTransaction());
150:
151: if (value != 0) {
152: Table table = sourceRow.getTable();
153:
154: throw new SQLException(
155: L
156: .l(
157: "'{0}' in {1}.{2} fails uniqueness constraint with block address {3}.",
158: column.getString(sourceBuffer,
159: sourceOffset),
160: table.getName(),
161: column.getName(),
162: (""
163: + (value / Store.BLOCK_SIZE)
164: + "." + (value % Store.BLOCK_SIZE))));
165: }
166: } catch (IOException e) {
167: throw new SQLExceptionWrapper(e);
168: }
169: }
170: }
|