EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.table]

COVERAGE SUMMARY FOR SOURCE FILE [Table.java]

nameclass, %method, %block, %line, %
Table.java100% (1/1)90%  (61/68)99%  (1317/1335)97%  (326/335)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Table100% (1/1)90%  (61/68)99%  (1317/1335)97%  (326/335)
canTruncate (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
checkDeadlock (Session, Session, Set): ArrayList 0%   (0/1)0%   (0/2)0%   (0/1)
getCreateSQLForCopy (Table, String): String 0%   (0/1)0%   (0/2)0%   (0/1)
getRow (Session, long): Row 0%   (0/1)0%   (0/2)0%   (0/1)
getRowIdColumn (): Column 0%   (0/1)0%   (0/2)0%   (0/1)
isLockedExclusivelyBy (Session): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
setHidden (boolean): void 0%   (0/1)0%   (0/4)0%   (0/2)
hasSelectTrigger (): boolean 100% (1/1)91%  (20/22)83%  (5/6)
Table (Schema, int, String, boolean, boolean): void 100% (1/1)100% (28/28)100% (8/8)
add (ArrayList, Object): ArrayList 100% (1/1)100% (10/10)100% (4/4)
addConstraint (Constraint): void 100% (1/1)100% (15/15)100% (3/3)
addDependencies (HashSet): void 100% (1/1)100% (72/72)100% (15/15)
addSequence (Sequence): void 100% (1/1)100% (7/7)100% (2/2)
addTrigger (TriggerObject): void 100% (1/1)100% (7/7)100% (2/2)
addView (TableView): void 100% (1/1)100% (7/7)100% (2/2)
canReference (): boolean 100% (1/1)100% (2/2)100% (1/1)
checkWritingAllowed (): void 100% (1/1)100% (4/4)100% (2/2)
commit (short, Row): void 100% (1/1)100% (1/1)100% (1/1)
compareTypeSave (Value, Value): int 100% (1/1)100% (25/25)100% (6/6)
doesColumnExist (String): boolean 100% (1/1)100% (5/5)100% (1/1)
dropSingleColumnConstraintsAndIndexes (Session, Column): void 100% (1/1)100% (129/129)100% (30/30)
findPrimaryKey (): Index 100% (1/1)100% (28/28)100% (7/7)
fire (Session, int, boolean): void 100% (1/1)100% (21/21)100% (5/5)
fireAfterRow (Session, Row, Row, boolean): void 100% (1/1)100% (17/17)100% (4/4)
fireBeforeRow (Session, Row, Row): boolean 100% (1/1)100% (16/16)100% (3/3)
fireConstraints (Session, Row, Row, boolean): void 100% (1/1)100% (31/31)100% (6/6)
fireRow (): boolean 100% (1/1)100% (18/18)100% (1/1)
fireRow (Session, Row, Row, boolean, boolean): boolean 100% (1/1)100% (29/29)100% (7/7)
getBestPlanItem (Session, int [], TableFilter, SortOrder): PlanItem 100% (1/1)100% (60/60)100% (12/12)
getCheckForeignKeyConstraints (): boolean 100% (1/1)100% (3/3)100% (1/1)
getChildren (): ArrayList 100% (1/1)100% (68/68)100% (18/18)
getColumn (String): Column 100% (1/1)100% (14/14)100% (4/4)
getColumn (int): Column 100% (1/1)100% (5/5)100% (1/1)
getColumns (): Column [] 100% (1/1)100% (3/3)100% (1/1)
getCompareMode (): CompareMode 100% (1/1)100% (3/3)100% (1/1)
getConstraints (): ArrayList 100% (1/1)100% (3/3)100% (1/1)
getDefaultValue (Session, Column): Value 100% (1/1)100% (19/19)100% (5/5)
getIndexForColumn (Column): Index 100% (1/1)100% (33/33)100% (9/9)
getNullRow (): Row 100% (1/1)100% (30/30)100% (5/5)
getOnCommitDrop (): boolean 100% (1/1)100% (3/3)100% (1/1)
getOnCommitTruncate (): boolean 100% (1/1)100% (3/3)100% (1/1)
getPrimaryKey (): Index 100% (1/1)100% (11/11)100% (4/4)
getTemplateRow (): Row 100% (1/1)100% (9/9)100% (1/1)
getTemplateSimpleRow (boolean): SearchRow 100% (1/1)100% (17/17)100% (3/3)
getType (): int 100% (1/1)100% (2/2)100% (1/1)
getViews (): ArrayList 100% (1/1)100% (3/3)100% (1/1)
isGlobalTemporary (): boolean 100% (1/1)100% (2/2)100% (1/1)
isHidden (): boolean 100% (1/1)100% (3/3)100% (1/1)
isMVStore (): boolean 100% (1/1)100% (2/2)100% (1/1)
isPersistData (): boolean 100% (1/1)100% (3/3)100% (1/1)
isPersistIndexes (): boolean 100% (1/1)100% (3/3)100% (1/1)
isQueryComparable (): boolean 100% (1/1)100% (2/2)100% (1/1)
remove (ArrayList, DbObject): void 100% (1/1)100% (13/13)100% (5/5)
removeChildrenAndResources (Session): void 100% (1/1)100% (134/134)100% (28/28)
removeConstraint (Constraint): void 100% (1/1)100% (5/5)100% (2/2)
removeIndex (Index): void 100% (1/1)100% (33/33)100% (7/7)
removeIndexOrTransferOwnership (Session, Index): void 100% (1/1)100% (39/39)100% (11/11)
removeSequence (Sequence): void 100% (1/1)100% (5/5)100% (2/2)
removeTrigger (TriggerObject): void 100% (1/1)100% (5/5)100% (2/2)
removeView (TableView): void 100% (1/1)100% (5/5)100% (2/2)
rename (String): void 100% (1/1)100% (26/26)100% (6/6)
renameColumn (Column, String): void 100% (1/1)100% (46/46)100% (9/9)
setCheckForeignKeyConstraints (Session, boolean, boolean): void 100% (1/1)100% (26/26)100% (7/7)
setColumns (Column []): void 100% (1/1)100% (56/56)100% (14/14)
setOnCommitDrop (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setOnCommitTruncate (boolean): void 100% (1/1)100% (4/4)100% (2/2)
updateRows (Prepared, Session, RowList): void 100% (1/1)100% (79/79)100% (26/26)
validateConvertUpdateSequence (Session, Row): void 100% (1/1)100% (41/41)100% (10/10)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.table;
7 
8import java.util.ArrayList;
9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.Set;
12 
13import org.h2.api.ErrorCode;
14import org.h2.command.Prepared;
15import org.h2.constraint.Constraint;
16import org.h2.engine.Constants;
17import org.h2.engine.DbObject;
18import org.h2.engine.Right;
19import org.h2.engine.Session;
20import org.h2.engine.UndoLogRecord;
21import org.h2.expression.Expression;
22import org.h2.expression.ExpressionVisitor;
23import org.h2.index.Index;
24import org.h2.index.IndexType;
25import org.h2.message.DbException;
26import org.h2.message.Trace;
27import org.h2.result.Row;
28import org.h2.result.RowList;
29import org.h2.result.SearchRow;
30import org.h2.result.SimpleRow;
31import org.h2.result.SimpleRowValue;
32import org.h2.result.SortOrder;
33import org.h2.schema.Schema;
34import org.h2.schema.SchemaObjectBase;
35import org.h2.schema.Sequence;
36import org.h2.schema.TriggerObject;
37import org.h2.util.New;
38import org.h2.value.CompareMode;
39import org.h2.value.Value;
40import org.h2.value.ValueNull;
41 
42/**
43 * This is the base class for most tables.
44 * A table contains a list of columns and a list of rows.
45 */
46public abstract class Table extends SchemaObjectBase {
47 
48    /**
49     * The table type that means this table is a regular persistent table.
50     */
51    public static final int TYPE_CACHED = 0;
52 
53    /**
54     * The table type that means this table is a regular persistent table.
55     */
56    public static final int TYPE_MEMORY = 1;
57 
58    /**
59     * The table type name for linked tables.
60     */
61    public static final String TABLE_LINK = "TABLE LINK";
62 
63    /**
64     * The table type name for system tables.
65     */
66    public static final String SYSTEM_TABLE = "SYSTEM TABLE";
67 
68    /**
69     * The table type name for regular data tables.
70     */
71    public static final String TABLE = "TABLE";
72 
73    /**
74     * The table type name for views.
75     */
76    public static final String VIEW = "VIEW";
77 
78    /**
79     * The table type name for external table engines.
80     */
81    public static final String EXTERNAL_TABLE_ENGINE = "EXTERNAL";
82 
83    /**
84     * The columns of this table.
85     */
86    protected Column[] columns;
87 
88    /**
89     * The compare mode used for this table.
90     */
91    protected CompareMode compareMode;
92 
93    /**
94     * Protected tables are not listed in the meta data and are excluded when
95     * using the SCRIPT command.
96     */
97    protected boolean isHidden;
98 
99    private final HashMap<String, Column> columnMap;
100    private final boolean persistIndexes;
101    private final boolean persistData;
102    private ArrayList<TriggerObject> triggers;
103    private ArrayList<Constraint> constraints;
104    private ArrayList<Sequence> sequences;
105    private ArrayList<TableView> views;
106    private boolean checkForeignKeyConstraints = true;
107    private boolean onCommitDrop, onCommitTruncate;
108    private Row nullRow;
109 
110    public Table(Schema schema, int id, String name, boolean persistIndexes,
111            boolean persistData) {
112        columnMap = schema.getDatabase().newStringMap();
113        initSchemaObjectBase(schema, id, name, Trace.TABLE);
114        this.persistIndexes = persistIndexes;
115        this.persistData = persistData;
116        compareMode = schema.getDatabase().getCompareMode();
117    }
118 
119    @Override
120    public void rename(String newName) {
121        super.rename(newName);
122        if (constraints != null) {
123            for (int i = 0, size = constraints.size(); i < size; i++) {
124                Constraint constraint = constraints.get(i);
125                constraint.rebuild();
126            }
127        }
128    }
129 
130    /**
131     * Lock the table for the given session.
132     * This method waits until the lock is granted.
133     *
134     * @param session the session
135     * @param exclusive true for write locks, false for read locks
136     * @param forceLockEvenInMvcc lock even in the MVCC mode
137     * @return true if the table was already exclusively locked by this session.
138     * @throws DbException if a lock timeout occurred
139     */
140    public abstract boolean lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc);
141 
142    /**
143     * Close the table object and flush changes.
144     *
145     * @param session the session
146     */
147    public abstract void close(Session session);
148 
149    /**
150     * Release the lock for this session.
151     *
152     * @param s the session
153     */
154    public abstract void unlock(Session s);
155 
156    /**
157     * Create an index for this table
158     *
159     * @param session the session
160     * @param indexName the name of the index
161     * @param indexId the id
162     * @param cols the index columns
163     * @param indexType the index type
164     * @param create whether this is a new index
165     * @param indexComment the comment
166     * @return the index
167     */
168    public abstract Index addIndex(Session session, String indexName,
169            int indexId, IndexColumn[] cols, IndexType indexType,
170            boolean create, String indexComment);
171 
172    /**
173     * Get the given row.
174     *
175     * @param session the session
176     * @param key the primary key
177     * @return the row
178     */
179    public Row getRow(Session session, long key) {
180        return null;
181    }
182 
183    /**
184     * Remove a row from the table and all indexes.
185     *
186     * @param session the session
187     * @param row the row
188     */
189    public abstract void removeRow(Session session, Row row);
190 
191    /**
192     * Remove all rows from the table and indexes.
193     *
194     * @param session the session
195     */
196    public abstract void truncate(Session session);
197 
198    /**
199     * Add a row to the table and all indexes.
200     *
201     * @param session the session
202     * @param row the row
203     * @throws DbException if a constraint was violated
204     */
205    public abstract void addRow(Session session, Row row);
206 
207    /**
208     * Commit an operation (when using multi-version concurrency).
209     *
210     * @param operation the operation
211     * @param row the row
212     */
213    public void commit(short operation, Row row) {
214        // nothing to do
215    }
216 
217    /**
218     * Check if this table supports ALTER TABLE.
219     *
220     * @throws DbException if it is not supported
221     */
222    public abstract void checkSupportAlter();
223 
224    /**
225     * Get the table type name
226     *
227     * @return the table type name
228     */
229    public abstract String getTableType();
230 
231    /**
232     * Get the scan index to iterate through all rows.
233     *
234     * @param session the session
235     * @return the index
236     */
237    public abstract Index getScanIndex(Session session);
238 
239    /**
240     * Get any unique index for this table if one exists.
241     *
242     * @return a unique index
243     */
244    public abstract Index getUniqueIndex();
245 
246    /**
247     * Get all indexes for this table.
248     *
249     * @return the list of indexes
250     */
251    public abstract ArrayList<Index> getIndexes();
252 
253    /**
254     * Check if this table is locked exclusively.
255     *
256     * @return true if it is.
257     */
258    public abstract boolean isLockedExclusively();
259 
260    /**
261     * Get the last data modification id.
262     *
263     * @return the modification id
264     */
265    public abstract long getMaxDataModificationId();
266 
267    /**
268     * Check if the table is deterministic.
269     *
270     * @return true if it is
271     */
272    public abstract boolean isDeterministic();
273 
274    /**
275     * Check if the row count can be retrieved quickly.
276     *
277     * @return true if it can
278     */
279    public abstract boolean canGetRowCount();
280 
281    /**
282     * Check if this table can be referenced.
283     *
284     * @return true if it can
285     */
286    public boolean canReference() {
287        return true;
288    }
289 
290    /**
291     * Check if this table can be dropped.
292     *
293     * @return true if it can
294     */
295    public abstract boolean canDrop();
296 
297    /**
298     * Get the row count for this table.
299     *
300     * @param session the session
301     * @return the row count
302     */
303    public abstract long getRowCount(Session session);
304 
305    /**
306     * Get the approximated row count for this table.
307     *
308     * @return the approximated row count
309     */
310    public abstract long getRowCountApproximation();
311 
312    public abstract long getDiskSpaceUsed();
313 
314    /**
315     * Get the row id column if this table has one.
316     *
317     * @return the row id column, or null
318     */
319    public Column getRowIdColumn() {
320        return null;
321    }
322 
323    @Override
324    public String getCreateSQLForCopy(Table table, String quotedName) {
325        throw DbException.throwInternalError();
326    }
327 
328    /**
329     * Check whether the table (or view) contains no columns that prevent index
330     * conditions to be used. For example, a view that contains the ROWNUM()
331     * pseudo-column prevents this.
332     *
333     * @return true if the table contains no query-comparable column
334     */
335    public boolean isQueryComparable() {
336        return true;
337    }
338 
339    /**
340     * Add all objects that this table depends on to the hash set.
341     *
342     * @param dependencies the current set of dependencies
343     */
344    public void addDependencies(HashSet<DbObject> dependencies) {
345        if (dependencies.contains(this)) {
346            // avoid endless recursion
347            return;
348        }
349        if (sequences != null) {
350            for (Sequence s : sequences) {
351                dependencies.add(s);
352            }
353        }
354        ExpressionVisitor visitor = ExpressionVisitor.getDependenciesVisitor(
355                dependencies);
356        for (Column col : columns) {
357            col.isEverything(visitor);
358        }
359        if (constraints != null) {
360            for (Constraint c : constraints) {
361                c.isEverything(visitor);
362            }
363        }
364        dependencies.add(this);
365    }
366 
367    @Override
368    public ArrayList<DbObject> getChildren() {
369        ArrayList<DbObject> children = New.arrayList();
370        ArrayList<Index> indexes = getIndexes();
371        if (indexes != null) {
372            children.addAll(indexes);
373        }
374        if (constraints != null) {
375            children.addAll(constraints);
376        }
377        if (triggers != null) {
378            children.addAll(triggers);
379        }
380        if (sequences != null) {
381            children.addAll(sequences);
382        }
383        if (views != null) {
384            children.addAll(views);
385        }
386        ArrayList<Right> rights = database.getAllRights();
387        for (Right right : rights) {
388            if (right.getGrantedTable() == this) {
389                children.add(right);
390            }
391        }
392        return children;
393    }
394 
395    protected void setColumns(Column[] columns) {
396        this.columns = columns;
397        if (columnMap.size() > 0) {
398            columnMap.clear();
399        }
400        for (int i = 0; i < columns.length; i++) {
401            Column col = columns[i];
402            int dataType = col.getType();
403            if (dataType == Value.UNKNOWN) {
404                throw DbException.get(
405                        ErrorCode.UNKNOWN_DATA_TYPE_1, col.getSQL());
406            }
407            col.setTable(this, i);
408            String columnName = col.getName();
409            if (columnMap.get(columnName) != null) {
410                throw DbException.get(
411                        ErrorCode.DUPLICATE_COLUMN_NAME_1, columnName);
412            }
413            columnMap.put(columnName, col);
414        }
415    }
416 
417    /**
418     * Rename a column of this table.
419     *
420     * @param column the column to rename
421     * @param newName the new column name
422     */
423    public void renameColumn(Column column, String newName) {
424        for (Column c : columns) {
425            if (c == column) {
426                continue;
427            }
428            if (c.getName().equals(newName)) {
429                throw DbException.get(
430                        ErrorCode.DUPLICATE_COLUMN_NAME_1, newName);
431            }
432        }
433        columnMap.remove(column.getName());
434        column.rename(newName);
435        columnMap.put(newName, column);
436    }
437 
438    /**
439     * Check if the table is exclusively locked by this session.
440     *
441     * @param session the session
442     * @return true if it is
443     */
444    public boolean isLockedExclusivelyBy(Session session) {
445        return false;
446    }
447 
448    /**
449     * Update a list of rows in this table.
450     *
451     * @param prepared the prepared statement
452     * @param session the session
453     * @param rows a list of row pairs of the form old row, new row, old row,
454     *            new row,...
455     */
456    public void updateRows(Prepared prepared, Session session, RowList rows) {
457        // in case we need to undo the update
458        Session.Savepoint rollback = session.setSavepoint();
459        // remove the old rows
460        int rowScanCount = 0;
461        for (rows.reset(); rows.hasNext();) {
462            if ((++rowScanCount & 127) == 0) {
463                prepared.checkCanceled();
464            }
465            Row o = rows.next();
466            rows.next();
467            removeRow(session, o);
468            session.log(this, UndoLogRecord.DELETE, o);
469        }
470        // add the new rows
471        for (rows.reset(); rows.hasNext();) {
472            if ((++rowScanCount & 127) == 0) {
473                prepared.checkCanceled();
474            }
475            rows.next();
476            Row n = rows.next();
477            try {
478                addRow(session, n);
479            } catch (DbException e) {
480                if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1) {
481                    session.rollbackTo(rollback, false);
482                    session.startStatementWithinTransaction();
483                    rollback = session.setSavepoint();
484                }
485                throw e;
486            }
487            session.log(this, UndoLogRecord.INSERT, n);
488        }
489    }
490 
491    public ArrayList<TableView> getViews() {
492        return views;
493    }
494 
495    @Override
496    public void removeChildrenAndResources(Session session) {
497        while (views != null && views.size() > 0) {
498            TableView view = views.get(0);
499            views.remove(0);
500            database.removeSchemaObject(session, view);
501        }
502        while (triggers != null && triggers.size() > 0) {
503            TriggerObject trigger = triggers.get(0);
504            triggers.remove(0);
505            database.removeSchemaObject(session, trigger);
506        }
507        while (constraints != null && constraints.size() > 0) {
508            Constraint constraint = constraints.get(0);
509            constraints.remove(0);
510            database.removeSchemaObject(session, constraint);
511        }
512        for (Right right : database.getAllRights()) {
513            if (right.getGrantedTable() == this) {
514                database.removeDatabaseObject(session, right);
515            }
516        }
517        database.removeMeta(session, getId());
518        // must delete sequences later (in case there is a power failure
519        // before removing the table object)
520        while (sequences != null && sequences.size() > 0) {
521            Sequence sequence = sequences.get(0);
522            sequences.remove(0);
523            if (!isTemporary()) {
524                // only remove if no other table depends on this sequence
525                // this is possible when calling ALTER TABLE ALTER COLUMN
526                if (database.getDependentTable(sequence, this) == null) {
527                    database.removeSchemaObject(session, sequence);
528                }
529            }
530        }
531    }
532 
533    /**
534     * Check that this column is not referenced by a multi-column constraint or
535     * multi-column index. If it is, an exception is thrown. Single-column
536     * references and indexes are dropped.
537     *
538     * @param session the session
539     * @param col the column
540     * @throws DbException if the column is referenced by multi-column
541     *             constraints or indexes
542     */
543    public void dropSingleColumnConstraintsAndIndexes(Session session,
544            Column col) {
545        ArrayList<Constraint> constraintsToDrop = New.arrayList();
546        if (constraints != null) {
547            for (int i = 0, size = constraints.size(); i < size; i++) {
548                Constraint constraint = constraints.get(i);
549                HashSet<Column> columns = constraint.getReferencedColumns(this);
550                if (!columns.contains(col)) {
551                    continue;
552                }
553                if (columns.size() == 1) {
554                    constraintsToDrop.add(constraint);
555                } else {
556                    throw DbException.get(
557                            ErrorCode.COLUMN_IS_REFERENCED_1, constraint.getSQL());
558                }
559            }
560        }
561        ArrayList<Index> indexesToDrop = New.arrayList();
562        ArrayList<Index> indexes = getIndexes();
563        if (indexes != null) {
564            for (int i = 0, size = indexes.size(); i < size; i++) {
565                Index index = indexes.get(i);
566                if (index.getCreateSQL() == null) {
567                    continue;
568                }
569                if (index.getColumnIndex(col) < 0) {
570                    continue;
571                }
572                if (index.getColumns().length == 1) {
573                    indexesToDrop.add(index);
574                } else {
575                    throw DbException.get(
576                            ErrorCode.COLUMN_IS_REFERENCED_1, index.getSQL());
577                }
578            }
579        }
580        for (Constraint c : constraintsToDrop) {
581            session.getDatabase().removeSchemaObject(session, c);
582        }
583        for (Index i : indexesToDrop) {
584            // the index may already have been dropped when dropping the
585            // constraint
586            if (getIndexes().contains(i)) {
587                session.getDatabase().removeSchemaObject(session, i);
588            }
589        }
590    }
591 
592    public Row getTemplateRow() {
593        return new Row(new Value[columns.length], Row.MEMORY_CALCULATE);
594    }
595 
596    /**
597     * Get a new simple row object.
598     *
599     * @param singleColumn if only one value need to be stored
600     * @return the simple row object
601     */
602    public SearchRow getTemplateSimpleRow(boolean singleColumn) {
603        if (singleColumn) {
604            return new SimpleRowValue(columns.length);
605        }
606        return new SimpleRow(new Value[columns.length]);
607    }
608 
609    synchronized Row getNullRow() {
610        if (nullRow == null) {
611            nullRow = new Row(new Value[columns.length], 1);
612            for (int i = 0; i < columns.length; i++) {
613                nullRow.setValue(i, ValueNull.INSTANCE);
614            }
615        }
616        return nullRow;
617    }
618 
619    public Column[] getColumns() {
620        return columns;
621    }
622 
623    @Override
624    public int getType() {
625        return DbObject.TABLE_OR_VIEW;
626    }
627 
628    /**
629     * Get the column at the given index.
630     *
631     * @param index the column index (0, 1,...)
632     * @return the column
633     */
634    public Column getColumn(int index) {
635        return columns[index];
636    }
637 
638    /**
639     * Get the column with the given name.
640     *
641     * @param columnName the column name
642     * @return the column
643     * @throws DbException if the column was not found
644     */
645    public Column getColumn(String columnName) {
646        Column column = columnMap.get(columnName);
647        if (column == null) {
648            throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1, columnName);
649        }
650        return column;
651    }
652 
653    /**
654     * Does the column with the given name exist?
655     *
656     * @param columnName the column name
657     * @return true if the column exists
658     */
659    public boolean doesColumnExist(String columnName) {
660        return columnMap.containsKey(columnName);
661    }
662 
663    /**
664     * Get the best plan for the given search mask.
665     *
666     * @param session the session
667     * @param masks per-column comparison bit masks, null means 'always false',
668     *              see constants in IndexCondition
669     * @param filter the table filter
670     * @param sortOrder the sort order
671     * @return the plan item
672     */
673    public PlanItem getBestPlanItem(Session session, int[] masks,
674            TableFilter filter, SortOrder sortOrder) {
675        PlanItem item = new PlanItem();
676        item.setIndex(getScanIndex(session));
677        item.cost = item.getIndex().getCost(session, null, null, null);
678        ArrayList<Index> indexes = getIndexes();
679        if (indexes != null && masks != null) {
680            for (int i = 1, size = indexes.size(); i < size; i++) {
681                Index index = indexes.get(i);
682                double cost = index.getCost(session, masks, filter, sortOrder);
683                if (cost < item.cost) {
684                    item.cost = cost;
685                    item.setIndex(index);
686                }
687            }
688        }
689        return item;
690    }
691 
692    /**
693     * Get the primary key index if there is one, or null if there is none.
694     *
695     * @return the primary key index or null
696     */
697    public Index findPrimaryKey() {
698        ArrayList<Index> indexes = getIndexes();
699        if (indexes != null) {
700            for (int i = 0, size = indexes.size(); i < size; i++) {
701                Index idx = indexes.get(i);
702                if (idx.getIndexType().isPrimaryKey()) {
703                    return idx;
704                }
705            }
706        }
707        return null;
708    }
709 
710    public Index getPrimaryKey() {
711        Index index = findPrimaryKey();
712        if (index != null) {
713            return index;
714        }
715        throw DbException.get(ErrorCode.INDEX_NOT_FOUND_1,
716                Constants.PREFIX_PRIMARY_KEY);
717    }
718 
719    /**
720     * Validate all values in this row, convert the values if required, and
721     * update the sequence values if required. This call will also set the
722     * default values if required and set the computed column if there are any.
723     *
724     * @param session the session
725     * @param row the row
726     */
727    public void validateConvertUpdateSequence(Session session, Row row) {
728        for (int i = 0; i < columns.length; i++) {
729            Value value = row.getValue(i);
730            Column column = columns[i];
731            Value v2;
732            if (column.getComputed()) {
733                // force updating the value
734                value = null;
735                v2 = column.computeValue(session, row);
736            }
737            v2 = column.validateConvertUpdateSequence(session, value);
738            if (v2 != value) {
739                row.setValue(i, v2);
740            }
741        }
742    }
743 
744    private static void remove(ArrayList<? extends DbObject> list, DbObject obj) {
745        if (list != null) {
746            int i = list.indexOf(obj);
747            if (i >= 0) {
748                list.remove(i);
749            }
750        }
751    }
752 
753    /**
754     * Remove the given index from the list.
755     *
756     * @param index the index to remove
757     */
758    public void removeIndex(Index index) {
759        ArrayList<Index> indexes = getIndexes();
760        if (indexes != null) {
761            remove(indexes, index);
762            if (index.getIndexType().isPrimaryKey()) {
763                for (Column col : index.getColumns()) {
764                    col.setPrimaryKey(false);
765                }
766            }
767        }
768    }
769 
770    /**
771     * Remove the given view from the list.
772     *
773     * @param view the view to remove
774     */
775    public void removeView(TableView view) {
776        remove(views, view);
777    }
778 
779    /**
780     * Remove the given constraint from the list.
781     *
782     * @param constraint the constraint to remove
783     */
784    public void removeConstraint(Constraint constraint) {
785        remove(constraints, constraint);
786    }
787 
788    /**
789     * Remove a sequence from the table. Sequences are used as identity columns.
790     *
791     * @param sequence the sequence to remove
792     */
793    public final void removeSequence(Sequence sequence) {
794        remove(sequences, sequence);
795    }
796 
797    /**
798     * Remove the given trigger from the list.
799     *
800     * @param trigger the trigger to remove
801     */
802    public void removeTrigger(TriggerObject trigger) {
803        remove(triggers, trigger);
804    }
805 
806    /**
807     * Add a view to this table.
808     *
809     * @param view the view to add
810     */
811    public void addView(TableView view) {
812        views = add(views, view);
813    }
814 
815    /**
816     * Add a constraint to the table.
817     *
818     * @param constraint the constraint to add
819     */
820    public void addConstraint(Constraint constraint) {
821        if (constraints == null || constraints.indexOf(constraint) < 0) {
822            constraints = add(constraints, constraint);
823        }
824    }
825 
826    public ArrayList<Constraint> getConstraints() {
827        return constraints;
828    }
829 
830    /**
831     * Add a sequence to this table.
832     *
833     * @param sequence the sequence to add
834     */
835    public void addSequence(Sequence sequence) {
836        sequences = add(sequences, sequence);
837    }
838 
839    /**
840     * Add a trigger to this table.
841     *
842     * @param trigger the trigger to add
843     */
844    public void addTrigger(TriggerObject trigger) {
845        triggers = add(triggers, trigger);
846    }
847 
848    private static <T> ArrayList<T> add(ArrayList<T> list, T obj) {
849        if (list == null) {
850            list = New.arrayList();
851        }
852        // self constraints are two entries in the list
853        list.add(obj);
854        return list;
855    }
856 
857    /**
858     * Fire the triggers for this table.
859     *
860     * @param session the session
861     * @param type the trigger type
862     * @param beforeAction whether 'before' triggers should be called
863     */
864    public void fire(Session session, int type, boolean beforeAction) {
865        if (triggers != null) {
866            for (TriggerObject trigger : triggers) {
867                trigger.fire(session, type, beforeAction);
868            }
869        }
870    }
871 
872    /**
873     * Check whether this table has a select trigger.
874     *
875     * @return true if it has
876     */
877    public boolean hasSelectTrigger() {
878        if (triggers != null) {
879            for (TriggerObject trigger : triggers) {
880                if (trigger.isSelectTrigger()) {
881                    return true;
882                }
883            }
884        }
885        return false;
886    }
887 
888    /**
889     * Check if row based triggers or constraints are defined.
890     * In this case the fire after and before row methods need to be called.
891     *
892     *  @return if there are any triggers or rows defined
893     */
894    public boolean fireRow() {
895        return (constraints != null && constraints.size() > 0) ||
896                (triggers != null && triggers.size() > 0);
897    }
898 
899    /**
900     * Fire all triggers that need to be called before a row is updated.
901     *
902     * @param session the session
903     * @param oldRow the old data or null for an insert
904     * @param newRow the new data or null for a delete
905     * @return true if no further action is required (for 'instead of' triggers)
906     */
907    public boolean fireBeforeRow(Session session, Row oldRow, Row newRow) {
908        boolean done = fireRow(session, oldRow, newRow, true, false);
909        fireConstraints(session, oldRow, newRow, true);
910        return done;
911    }
912 
913    private void fireConstraints(Session session, Row oldRow, Row newRow,
914            boolean before) {
915        if (constraints != null) {
916            // don't use enhanced for loop to avoid creating objects
917            for (int i = 0, size = constraints.size(); i < size; i++) {
918                Constraint constraint = constraints.get(i);
919                if (constraint.isBefore() == before) {
920                    constraint.checkRow(session, this, oldRow, newRow);
921                }
922            }
923        }
924    }
925 
926    /**
927     * Fire all triggers that need to be called after a row is updated.
928     *
929     *  @param session the session
930     *  @param oldRow the old data or null for an insert
931     *  @param newRow the new data or null for a delete
932     *  @param rollback when the operation occurred within a rollback
933     */
934    public void fireAfterRow(Session session, Row oldRow, Row newRow,
935            boolean rollback) {
936        fireRow(session, oldRow, newRow, false, rollback);
937        if (!rollback) {
938            fireConstraints(session, oldRow, newRow, false);
939        }
940    }
941 
942    private boolean fireRow(Session session, Row oldRow, Row newRow,
943            boolean beforeAction, boolean rollback) {
944        if (triggers != null) {
945            for (TriggerObject trigger : triggers) {
946                boolean done = trigger.fireRow(session, oldRow, newRow, beforeAction, rollback);
947                if (done) {
948                    return true;
949                }
950            }
951        }
952        return false;
953    }
954 
955    public boolean isGlobalTemporary() {
956        return false;
957    }
958 
959    /**
960     * Check if this table can be truncated.
961     *
962     * @return true if it can
963     */
964    public boolean canTruncate() {
965        return false;
966    }
967 
968    /**
969     * Enable or disable foreign key constraint checking for this table.
970     *
971     * @param session the session
972     * @param enabled true if checking should be enabled
973     * @param checkExisting true if existing rows must be checked during this
974     *            call
975     */
976    public void setCheckForeignKeyConstraints(Session session, boolean enabled,
977            boolean checkExisting) {
978        if (enabled && checkExisting) {
979            if (constraints != null) {
980                for (Constraint c : constraints) {
981                    c.checkExistingData(session);
982                }
983            }
984        }
985        checkForeignKeyConstraints = enabled;
986    }
987 
988    public boolean getCheckForeignKeyConstraints() {
989        return checkForeignKeyConstraints;
990    }
991 
992    /**
993     * Get the index that has the given column as the first element.
994     * This method returns null if no matching index is found.
995     *
996     * @param column the column
997     * @return the index or null
998     */
999    public Index getIndexForColumn(Column column) {
1000        ArrayList<Index> indexes = getIndexes();
1001        if (indexes != null) {
1002            for (int i = 1, size = indexes.size(); i < size; i++) {
1003                Index index = indexes.get(i);
1004                if (index.canGetFirstOrLast()) {
1005                    int idx = index.getColumnIndex(column);
1006                    if (idx == 0) {
1007                        return index;
1008                    }
1009                }
1010            }
1011        }
1012        return null;
1013    }
1014 
1015    public boolean getOnCommitDrop() {
1016        return onCommitDrop;
1017    }
1018 
1019    public void setOnCommitDrop(boolean onCommitDrop) {
1020        this.onCommitDrop = onCommitDrop;
1021    }
1022 
1023    public boolean getOnCommitTruncate() {
1024        return onCommitTruncate;
1025    }
1026 
1027    public void setOnCommitTruncate(boolean onCommitTruncate) {
1028        this.onCommitTruncate = onCommitTruncate;
1029    }
1030 
1031    /**
1032     * If the index is still required by a constraint, transfer the ownership to
1033     * it. Otherwise, the index is removed.
1034     *
1035     * @param session the session
1036     * @param index the index that is no longer required
1037     */
1038    public void removeIndexOrTransferOwnership(Session session, Index index) {
1039        boolean stillNeeded = false;
1040        if (constraints != null) {
1041            for (Constraint cons : constraints) {
1042                if (cons.usesIndex(index)) {
1043                    cons.setIndexOwner(index);
1044                    database.updateMeta(session, cons);
1045                    stillNeeded = true;
1046                }
1047            }
1048        }
1049        if (!stillNeeded) {
1050            database.removeSchemaObject(session, index);
1051        }
1052    }
1053 
1054    /**
1055     * Check if a deadlock occurred. This method is called recursively. There is
1056     * a circle if the session to be tested has already being visited. If this
1057     * session is part of the circle (if it is the clash session), the method
1058     * must return an empty object array. Once a deadlock has been detected, the
1059     * methods must add the session to the list. If this session is not part of
1060     * the circle, or if no deadlock is detected, this method returns null.
1061     *
1062     * @param session the session to be tested for
1063     * @param clash set with sessions already visited, and null when starting
1064     *            verification
1065     * @param visited set with sessions already visited, and null when starting
1066     *            verification
1067     * @return an object array with the sessions involved in the deadlock, or
1068     *         null
1069     */
1070    public ArrayList<Session> checkDeadlock(Session session, Session clash,
1071            Set<Session> visited) {
1072        return null;
1073    }
1074 
1075    public boolean isPersistIndexes() {
1076        return persistIndexes;
1077    }
1078 
1079    public boolean isPersistData() {
1080        return persistData;
1081    }
1082 
1083    /**
1084     * Compare two values with the current comparison mode. The values may be of
1085     * different type.
1086     *
1087     * @param a the first value
1088     * @param b the second value
1089     * @return 0 if both values are equal, -1 if the first value is smaller, and
1090     *         1 otherwise
1091     */
1092    public int compareTypeSave(Value a, Value b) {
1093        if (a == b) {
1094            return 0;
1095        }
1096        int dataType = Value.getHigherOrder(a.getType(), b.getType());
1097        a = a.convertTo(dataType);
1098        b = b.convertTo(dataType);
1099        return a.compareTypeSave(b, compareMode);
1100    }
1101 
1102    public CompareMode getCompareMode() {
1103        return compareMode;
1104    }
1105 
1106    /**
1107     * Tests if the table can be written. Usually, this depends on the
1108     * database.checkWritingAllowed method, but some tables (eg. TableLink)
1109     * overwrite this default behaviour.
1110     */
1111    public void checkWritingAllowed() {
1112        database.checkWritingAllowed();
1113    }
1114 
1115    /**
1116     * Get or generate a default value for the given column.
1117     *
1118     * @param session the session
1119     * @param column the column
1120     * @return the value
1121     */
1122    public Value getDefaultValue(Session session, Column column) {
1123        Expression defaultExpr = column.getDefaultExpression();
1124        Value v;
1125        if (defaultExpr == null) {
1126            v = column.validateConvertUpdateSequence(session, null);
1127        } else {
1128            v = defaultExpr.getValue(session);
1129        }
1130        return column.convert(v);
1131    }
1132 
1133    @Override
1134    public boolean isHidden() {
1135        return isHidden;
1136    }
1137 
1138    public void setHidden(boolean hidden) {
1139        this.isHidden = hidden;
1140    }
1141 
1142    public boolean isMVStore() {
1143        return false;
1144    }
1145 
1146}

[all classes][org.h2.table]
EMMA 2.0.5312 (C) Vladimir Roubtsov