/* $Id: IDBInterface.java 999670 2010-09-21 22:18:19Z kwright $ */ /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.manifoldcf.core.interfaces; import java.util.*; /** The purpose of this interface is to provide abstracted database table modification primitives, * as well as general access primitives. It is expected that the generalized database layer will * provide the underlying services. This layer should provide services roughly equivalent to * the former DBInterface bean, but be callable in a pure Java fashion. * It is furthermore intended that all abstraction database requests go through this layer. It * will therefore, over time, provide grander and grander levels of database query abstraction. * * Also note that the database parameters will be passed to the factory for this class, not * to the individual methods. * */ public interface IDBInterface { public static final String _rcsid = "@(#)$Id: IDBInterface.java 999670 2010-09-21 22:18:19Z kwright $"; public static int TRANSACTION_ENCLOSING = 0; public static int TRANSACTION_READCOMMITTED = 1; public static int TRANSACTION_SERIALIZED = 2; public static int TRANSACTION_REPEATABLEREAD = 3; /** Initialize. This method is called once per JVM instance, in order to set up * database communication. */ public void openDatabase() throws ManifoldCFException; /** Uninitialize. This method is called during JVM shutdown, in order to close * all database communication. */ public void closeDatabase() throws ManifoldCFException; /** Get the database name. *@return the database name. */ public String getDatabaseName(); /** Get the current transaction id. *@return the current transaction identifier, or null if no transaction. */ public String getTransactionID(); /** Get the database general cache key. *@return the general cache key for the database. */ public String getDatabaseCacheKey(); /** Perform an insert operation. *@param tableName is the name of the table. *@param invalidateKeys are the cache keys that should be * invalidated. *@param parameterMap is the map of column name/values to write. */ public void performInsert(String tableName, Map<String,Object> parameterMap, StringSet invalidateKeys) throws ManifoldCFException; /** Perform an update operation. *@param tableName is the name of the table. *@param invalidateKeys are the cache keys that should be invalidated. *@param parameterMap is the map of column name/values to write. *@param whereClause is the where clause describing the match (including the WHERE), or null if none. *@param whereParameters are the parameters that come with the where clause, if any. */ public void performUpdate(String tableName, Map<String,Object> parameterMap, String whereClause, List whereParameters, StringSet invalidateKeys) throws ManifoldCFException; /** Perform a delete operation. *@param tableName is the name of the table to delete from. *@param invalidateKeys are the cache keys that should be invalidated. *@param whereClause is the where clause describing the match (including the WHERE), or null if none. *@param whereParameters are the parameters that come with the where clause, if any. */ public void performDelete(String tableName, String whereClause, List whereParameters, StringSet invalidateKeys) throws ManifoldCFException; /** Perform a table creation operation. *@param tableName is the name of the table to create. *@param columnMap is the map describing the columns and types. NOTE that these are abstract * types, which will be mapped to the proper types for the actual database inside this * layer. The types are ColumnDefinition objects. *@param invalidateKeys are the cache keys that should be invalidated, if any. */ public void performCreate(String tableName, Map<String,ColumnDescription> columnMap, StringSet invalidateKeys) throws ManifoldCFException; /** Perform a table alter operation. *@param tableName is the name of the table to alter. *@param columnMap is the map describing the columns and types to add. These * are in the same form as for performCreate. *@param columnModifyMap is the map describing the columns to be changed. The key is the * existing column name, and the value is the new type of the column. Data will be copied from * the old column to the new. *@param columnDeleteList is the list of column names to delete. *@param invalidateKeys are the cache keys that should be invalidated, if any. */ public void performAlter(String tableName, Map<String,ColumnDescription> columnMap, Map<String,ColumnDescription> columnModifyMap, List<String> columnDeleteList, StringSet invalidateKeys) throws ManifoldCFException; /** Add an index to a table. *@param tableName is the name of the table to add the index for. *@param unique is a boolean that if true describes a unique index. *@param columnList is the list of columns that need to be included * in the index, in order. */ public void addTableIndex(String tableName, boolean unique, List<String> columnList) throws ManifoldCFException; /** Add an index to a table. *@param tableName is the name of the table to add the index for. *@param indexName is the optional name of the table index. If null, a name will be chosen automatically. *@param description is the index description. */ public void performAddIndex(String indexName, String tableName, IndexDescription description) throws ManifoldCFException; /** Remove an index. *@param indexName is the name of the index to remove. *@param tableName is the table the index belongs to. */ public void performRemoveIndex(String indexName, String tableName) throws ManifoldCFException; /** Analyze a table. *@param tableName is the name of the table to analyze/calculate statistics for. */ public void analyzeTable(String tableName) throws ManifoldCFException; /** Reindex a table. *@param tableName is the name of the table to rebuild indexes for. */ public void reindexTable(String tableName) throws ManifoldCFException; /** Perform a table drop operation. *@param tableName is the name of the table to drop. *@param invalidateKeys are the cache keys that should be invalidated, if any. */ public void performDrop(String tableName, StringSet invalidateKeys) throws ManifoldCFException; /** Create user and database. *@param adminUserName is the admin user name. *@param adminPassword is the admin password. *@param invalidateKeys are the cache keys that should be invalidated, if any. */ public void createUserAndDatabase(String adminUserName, String adminPassword, StringSet invalidateKeys) throws ManifoldCFException; /** Drop user and database. *@param adminUserName is the admin user name. *@param adminPassword is the admin password. *@param invalidateKeys are the cache keys that should be invalidated, if any. */ public void dropUserAndDatabase(String adminUserName, String adminPassword, StringSet invalidateKeys) throws ManifoldCFException; /** Get a table's schema. *@param tableName is the name of the table. *@param cacheKeys are the keys against which to cache the query, or null. *@param queryClass is the name of the query class, or null. *@return a map of column names and ColumnDescription objects, describing the schema. */ public Map<String,ColumnDescription> getTableSchema(String tableName, StringSet cacheKeys, String queryClass) throws ManifoldCFException; /** Get a table's indexes. *@param tableName is the name of the table. *@param cacheKeys are the keys against which to cache the query, or null. *@param queryClass is the name of the query class, or null. *@return a map of index names and IndexDescription objects, describing the indexes. */ public Map<String,IndexDescription> getTableIndexes(String tableName, StringSet cacheKeys, String queryClass) throws ManifoldCFException; /** Get a database's tables. *@param cacheKeys are the cache keys for the query, or null. *@param queryClass is the name of the query class, or null. *@return the set of tables. */ public StringSet getAllTables(StringSet cacheKeys, String queryClass) throws ManifoldCFException; /** Perform a general database modification query. *@param query is the query string. *@param params are the parameterized values, if needed. *@param invalidateKeys are the cache keys to invalidate. */ public void performModification(String query, List params, StringSet invalidateKeys) throws ManifoldCFException; /** Perform a general "data fetch" query. *@param query is the query string. *@param params are the parameterized values, if needed. *@param cacheKeys are the cache keys, if needed (null if no cache desired). *@param queryClass is the LRU class name against which this query would be cached, * or null if no LRU behavior desired. *@return a resultset. */ public IResultSet performQuery(String query, List params, StringSet cacheKeys, String queryClass) throws ManifoldCFException; /** Perform a general "data fetch" query. *@param query is the query string. *@param params are the parameterized values, if needed. *@param cacheKeys are the cache keys, if needed (null if no cache desired). *@param queryClass is the LRU class name against which this query would be cached, * or null if no LRU behavior desired. *@param maxResults is the maximum number of results returned (-1 for all). *@param returnLimit is a description of how to limit the return result, or null if no limit. *@return a resultset. */ public IResultSet performQuery(String query, List params, StringSet cacheKeys, String queryClass, int maxResults, ILimitChecker returnLimit) throws ManifoldCFException; /** Perform a general "data fetch" query. *@param query is the query string. *@param params are the parameterized values, if needed. *@param cacheKeys are the cache keys, if needed (null if no cache desired). *@param queryClass is the LRU class name against which this query would be cached, * or null if no LRU behavior desired. *@param maxResults is the maximum number of results returned (-1 for all). *@param resultSpec is a result specification, or null for the standard treatment. *@param returnLimit is a description of how to limit the return result, or null if no limit. *@return a resultset. */ public IResultSet performQuery(String query, List params, StringSet cacheKeys, String queryClass, int maxResults, ResultSpecification resultSpec, ILimitChecker returnLimit) throws ManifoldCFException; /** Construct index hint clause. * On most databases this returns an empty string, but on MySQL this returns * a USE INDEX hint. It requires the name of an index. *@param tableName is the table the index is from. *@param description is the description of an index, which is expected to exist. *@return the query chunk that should go between the table names and the WHERE * clause. */ public String constructIndexHintClause(String tableName, IndexDescription description) throws ManifoldCFException; /** Construct ORDER-BY clause meant for reading from an index. * Supply the field names belonging to the index, in order. * Also supply a corresponding boolean array, where TRUE means "ASC", and FALSE * means "DESC". *@param fieldNames are the names of the fields in the index that is to be used. *@param direction is a boolean describing the sorting order of the first term. *@return a query chunk, including "ORDER BY" text, which is appropriate for * at least ordering by the FIRST column supplied. */ public String constructIndexOrderByClause(String[] fieldNames, boolean direction); /** Construct a cast to a double value. * On most databases this cast needs to be explicit, but on some it is implicit (and cannot be in fact * specified). *@param value is the value to be cast. *@return the query chunk needed. */ public String constructDoubleCastClause(String value); /** Construct a count clause. * On most databases this will be COUNT(col), but on some the count needs to be cast to a BIGINT, so * CAST(COUNT(col) AS BIGINT) will be emitted instead. *@param column is the column string to be counted. *@return the query chunk needed. */ public String constructCountClause(String column); /** Construct a regular-expression match clause. * This method builds a regular-expression match expression. *@param column is the column specifier string. *@param regularExpression is the properly-quoted regular expression string, or "?" if a parameterized value is to be used. *@param caseInsensitive is true if the regular expression match is to be case insensitive. *@return the query chunk needed, not padded with spaces on either side. */ public String constructRegexpClause(String column, String regularExpression, boolean caseInsensitive); /** Construct a regular-expression substring clause. * This method builds an expression that extracts a specified string section from a field, based on * a regular expression. *@param column is the column specifier string. *@param regularExpression is the properly-quoted regular expression string, or "?" if a parameterized value is to be used. *@param caseInsensitive is true if the regular expression match is to be case insensitive. *@return the expression chunk needed, not padded with spaces on either side. */ public String constructSubstringClause(String column, String regularExpression, boolean caseInsensitive); /** Construct an offset/limit clause. * This method constructs an offset/limit clause in the proper manner for the database in question. *@param offset is the starting offset number. *@param limit is the limit of result rows to return. *@param afterOrderBy is true if this offset/limit comes after an ORDER BY. *@return the proper clause, with no padding spaces on either side. */ public String constructOffsetLimitClause(int offset, int limit, boolean afterOrderBy); /** Construct an offset/limit clause. * This method constructs an offset/limit clause in the proper manner for the database in question. *@param offset is the starting offset number. *@param limit is the limit of result rows to return. *@return the proper clause, with no padding spaces on either side. */ public String constructOffsetLimitClause(int offset, int limit); /** Construct a 'distinct on (x)' filter. * This filter wraps a query and returns a new query whose results are similar to POSTGRESQL's DISTINCT-ON feature. * Specifically, for each combination of the specified distinct fields in the result, only the first such row is included in the final * result. *@param outputParameters is a blank list into which to put parameters. Null may be used if the baseParameters parameter is null. *@param baseQuery is the base query, which is another SELECT statement, without parens, * e.g. "SELECT ..." *@param baseParameters are the parameters corresponding to the baseQuery. *@param distinctFields are the fields to consider to be distinct. These should all be keys in otherFields below. *@param orderFields are the otherfield keys that determine the ordering. *@param orderFieldsAscending are true for orderFields that are ordered as ASC, false for DESC. *@param otherFields are the rest of the fields to return, keyed by the AS name, value being the base query column value, e.g. "value AS key" *@return a revised query that performs the necessary DISTINCT ON operation. The list outputParameters will also be appropriately filled in. */ public String constructDistinctOnClause(List outputParameters, String baseQuery, List baseParameters, String[] distinctFields, String[] orderFields, boolean[] orderFieldsAscending, Map<String,String> otherFields); /* Calculate the number of values a particular clause can have, given the values for all the other clauses. * For example, if in the expression x AND y AND z, x has 2 values and z has 1, find out how many values x can legally have * when using the buildConjunctionClause() method below. */ public int findConjunctionClauseMax(ClauseDescription[] otherClauseDescriptions); /* Construct a conjunction clause, e.g. x AND y AND z, where there is expected to be an index (x,y,z,...), and where x, y, or z * can have multiple distinct values, The proper implementation of this method differs from database to database, because some databases * only permit index operations when there are OR's between clauses, such as x1 AND y1 AND z1 OR x2 AND y2 AND z2 ..., where others * only recognize index operations when there are lists specified for each, such as x IN (x1,x2) AND y IN (y1,y2) AND z IN (z1,z2). */ public String buildConjunctionClause(List outputParameters, ClauseDescription[] clauseDescriptions); /** Obtain the maximum number of individual items that should be * present in an IN clause. Exceeding this amount will potentially cause the query performance * to drop. *@return the maximum number of IN clause members. */ public int getMaxInClause(); /** Obtain the maximum number of individual clauses that should be * present in a sequence of OR clauses. Exceeding this amount will potentially cause the query performance * to drop. *@return the maximum number of OR clause members. */ public int getMaxOrClause(); /** For windowed report queries, e.g. maxActivity or maxBandwidth, obtain the maximum number of rows * that can reasonably be expected to complete in an acceptable time. *@return the maximum number of rows. */ public int getWindowedReportMaxRows(); /** Begin a database transaction. This method call MUST be paired with an endTransaction() call, * or database handles will be lost. If the transaction should be rolled back, then signalRollback() should * be called before the transaction is ended. * It is strongly recommended that the code that uses transactions be structured so that a try block * starts immediately after this method call. The body of the try block will contain all direct or indirect * calls to executeQuery(). After this should be a catch for every exception type, including Error, which should call the * signalRollback() method, and rethrow the exception. Then, after that a finally{} block which calls endTransaction(). * (The kind of transaction started by this method is the current default transaction type, which is "read committed" * if not otherwise determined). */ public void beginTransaction() throws ManifoldCFException; /** Begin a database transaction. This method call MUST be paired with an endTransaction() call, * or database handles will be lost. If the transaction should be rolled back, then signalRollback() should * be called before the transaction is ended. * It is strongly recommended that the code that uses transactions be structured so that a try block * starts immediately after this method call. The body of the try block will contain all direct or indirect * calls to executeQuery(). After this should be a catch for every exception type, including Error, which should call the * signalRollback() method, and rethrow the exception. Then, after that a finally{} block which calls endTransaction(). *@param transactionType is the kind of transaction desired. */ public void beginTransaction(int transactionType) throws ManifoldCFException; /** Perform the transaction commit. * Calling this method does not relieve the coder of the responsibility of calling endTransaction(), * as listed below. The purpose of a separate commit operation is to allow handling of situations where the * commit generates a TRANSACTION_ABORT signal. */ public void performCommit() throws ManifoldCFException; /** Signal that a rollback should occur on the next endTransaction(). */ public void signalRollback(); /** End a database transaction, either performing a commit or a rollback or nothing (depending on whether * signalRollback() was called within the transaction or performCommit() or none of the above). */ public void endTransaction() throws ManifoldCFException; /** Note a number of inserts, modifications, or deletions to a specific table. This is so we can decide when to do appropriate maintenance. *@param tableName is the name of the table being modified. *@param insertCount is the number of inserts. *@param modifyCount is the number of updates. *@param deleteCount is the number of deletions. */ public void noteModifications(String tableName, int insertCount, int modifyCount, int deleteCount) throws ManifoldCFException; /** Get a random time, in milliseconds, for backoff from deadlock. *@return the random time. */ public long getSleepAmt(); /** Sleep for a specified time, as part of backoff from deadlock. *@param time is the amount to sleep. */ public void sleepFor(long time) throws ManifoldCFException; }