package tap.db;
/*
* This file is part of TAPLibrary.
*
* TAPLibrary is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* TAPLibrary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see
Connection to the "database" (whatever is the type or whether it is linked to a true DBMS connection).
* *It lets executing ADQL queries and updating the TAP datamodel (with the list of schemas, tables and columns published in TAP, * or with uploaded tables).
* *IMPORTANT: * This connection aims only to provide a common and known interface for any kind of database connection. * A connection MUST be opened/created and closed/freed ONLY by the {@link TAPFactory}, which will usually merely wrap * the real database connection by a {@link DBConnection} object. That's why this interface does not provide anymore * a close() function. *
* * @author Grégory Mantelet (CDS;ARI) * @version 2.1 (04/2017) */ public interface DBConnection { /** *Get any identifier for this connection.
* *note: it is used only for logging purpose.
* * @return ID of this connection. */ public String getID(); /** *Fetch the whole content of TAP_SCHEMA.
* ** This function SHOULD be used only once: at the starting of the TAP service. It is an alternative way * to get the published schemas, tables and columns. The other way is to build a {@link TAPMetadata} object * yourself in function of the schemas/tables/columns you want to publish (i.e. which can be done by reading * metadata from a XML document - following the same schema - XSD- as for the TAP resource tables) * and then to load them in the DB (see {@link #setTAPSchema(TAPMetadata)} for more details). *
* *CAUTION: * This function MUST NOT be used if the tables to publish or the standard TAP_SCHEMA tables have names in DB different from the * ones defined by the TAP standard. So, if DB names are different from the ADQL names, you have to write yourself a way to get * the metadata from the DB. *
* *Important note: * If the schema or some standard tables or columns are missing, TAP_SCHEMA will be considered as incomplete * and an exception will be thrown. *
* *Note: * This function MUST be able to read the standard tables and columns described by the IVOA. All other tables/columns * will be merely ignored. *
* * @return Content of TAP_SCHEMA inside the DB. * * @throws DBException If TAP_SCHEMA can not be found, is incomplete or if some important metadata can not be retrieved. * * @since 2.0 */ public TAPMetadata getTAPSchema() throws DBException; /** *Empty and then fill all the TAP_SCHEMA tables with the given list of metadata.
* ** This function SHOULD be used only once: at the starting of the TAP service, * when metadata are loaded from a XML document (following the same schema - XSD- * as for the TAP resource tables). *
* ** THIS FUNCTION IS MANIPULATING THE SCHEMAS AND TABLES OF YOUR DATABASE. * SO IT SHOULD HAVE A SPECIFIC BEHAVIOR DESCRIBED BELOW. * SO PLEASE READ THE FOLLOWINGS AND TRY TO RESPECT IT AS MUCH AS POSSIBLE IN THE IMPLEMENTATIONS *
* ** This function MAY drop and then re-create the schema TAP_SCHEMA and all * its tables listed in the TAP standard (TAP_SCHEMA.schemas, .tables, .columns, .keys and .key_columns). * All other tables inside TAP_SCHEMA SHOULD NOT be modified! *
* ** The schema and the tables MUST be created using either the standard definition or the * definition provided in the {@link TAPMetadata} object (if provided). Indeed, if your definition of these TAP tables * is different from the standard (i.e. the standard + new elements), you MUST provide your modifications in parameter * through the {@link TAPMetadata} object so that they can be applied and taken into account in TAP_SCHEMA. *
* *Note: * DB names provided in the given TAPMetadata (see {@link TAPTable#getDBSchemaName()}, {@link TAPTable#getDBName()} and {@link TAPColumn#getDBName()}) * are used for the creation and filling of the tables. * * Whether these requests must be case sensitive or not SHOULD be managed by ADQLTranslator. *
* ** This object MUST contain all schemas, tables and columns that MUST be published. All its content will be * used in order to fill the TAP_SCHEMA tables. *
** Of course, TAP_SCHEMA and its tables MAY be provided in this object. But: *
*Note: By default, all implementations of this interface in the TAP library will fill only standard columns and tables of TAP_SCHEMA. * To fill your own, you MUST implement yourself this interface or to extend an existing implementation.
* *WARNING: * (b) lets consider a TAP_SCHEMA different from the standard one. BUT, these differences MUST be only additions, * NOT modifications or deletion of the standard definition! This function MUST be able to work AT LEAST on a * standard definition of TAP_SCHEMA. *
* ** The TAP_SCHEMA tables SHOULD be completely emptied (in SQL: "DELETE FROM <table_name>;" or merely "DROP TABLE <table_name>") before insertions can be processed. *
* ** If any error occurs while executing any "DB" queries (in SQL: DROP, DELETE, INSERT, CREATE, ...), all queries executed * before in this function MUST be canceled (in SQL: ROLLBACK). *
* * @param metadata List of all schemas, tables, columns and foreign keys to insert in the TAP_SCHEMA. * * @throws DBCancelledException If {@link #cancel(boolean)} has been called during the processing. * @throws DBException If any error occurs while updating the database. * * @since 2.0 */ public void setTAPSchema(final TAPMetadata metadata) throws DBCancelledException, DBException; /** * Add the defined and given table inside the TAP_UPLOAD schema. * *If the TAP_UPLOAD schema does not already exist, it will be created.
* *note: A table of TAP_UPLOAD MUST be transient and persistent only for the lifetime of the query. * So, this function should always be used with {@link #dropUploadedTable(TAPTable)}, which is called at * the end of each query execution.
* * @param tableDef Definition of the table to upload (list of all columns and of their type). * @param data Rows and columns of the table to upload. * * @return true if the given table has been successfully added, false otherwise. * * @throws DBCancelledException If {@link #cancel(boolean)} has been called during the processing. * @throws DBException If any error occurs while adding the table. * @throws DataReadException If any error occurs while reading the given data (particularly if any limit - in byte or row - set in the TableIterator is reached). * * @since 2.0 */ public boolean addUploadedTable(final TAPTable tableDef, final TableIterator data) throws DBCancelledException, DBException, DataReadException; /** *Drop the specified uploaded table from the database. * More precisely, it means dropping a table from the TAP_UPLOAD schema.
* *Note: * This function SHOULD drop only one table. So, if more than one table match in the "database" to the given one, an exception MAY be thrown. * This behavior is implementation-dependent. *
* * @param tableDef Definition of the uploaded table to drop (the whole object is needed in order to get the DB schema and tables names). * * @return true if the specified table has been successfully dropped, false otherwise. * * @throws DBException If any error occurs while dropping the specified uploaded table. * * @since 2.0 */ public boolean dropUploadedTable(final TAPTable tableDef) throws DBException; /** *Let executing the given ADQL query.
* *The result of this query must be formatted as a table, and so must be iterable using a {@link TableIterator}.
* *note: the interpretation of the ADQL query is up to the implementation. In most of the cases, it is just needed * to translate this ADQL query into an SQL query (understandable by the chosen DBMS).
* *IMPORTANT: * A {@link DBConnection} implementation may open resources to perform the query and get the result, * but it may especially KEEP them OPENED in order to let the returned {@link TableIterator} iterates on * the result set. So that closing these resources, the function {@link #endQuery()} should be called * when the result is no longer needed. A good implementation of {@link TableIterator} SHOULD call this * function when {@link TableIterator#close()} is called. So, do not forget to call {@link TableIterator#close()} * when you do not need any more the query result. *
* * @param adqlQuery ADQL query to execute. * @param jobOwner The user executing the query * * @return The table result. * * @throws DBCancelledException If {@link #cancel(boolean)} has been called (i.e. query aborted) during the processing. * @throws DBException If any errors occurs while executing the query. * * @since 2.0 * * @see #endQuery() * @see TableIterator#close() */ public TableIterator executeQuery(final ADQLQuery adqlQuery, JobOwner jobOwner) throws DBCancelledException, DBException; /** *Set the number of rows to fetch before searching/getting the following. * Thus, rows are fetched by block whose the size is set by this function.
* ** This feature may not be supported. In such case or if an exception occurs while setting the fetch size, * this function must not send any exception and the connection stays with its default fetch size. A message may be however * logged. *
* *Note: * The "fetch size" should be taken into account only for SELECT queries executed by {@link #executeQuery(ADQLQuery)}. *
* ** This feature is generally implemented by JDBC drivers using the V3 protocol. Thus, here is how the PostgreSQL JDBC documentation * (https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor) describes this feature: *
*** * @param size Blocks size (in number of rows) to fetch. * * @since 2.0 */ public void setFetchSize(final int size); /** ** By default the driver collects all the results for the query at once. This can be inconvenient for large data sets * so the JDBC driver provides a means of basing a ResultSet on a database cursor and only fetching a small number of rows. *
** A small number of rows are cached on the client side of the connection and when exhausted the next block of rows * is retrieved by repositioning the cursor. *
*
Stop the execution of the current query.
* ** If asked, a rollback of the current transaction can also be performed * before the function returns. This rollback operation is totally independent * from the cancellation. It means that the rollback is always performed whatever * is the cancellation result (or whatever the cancellation can be performed or not). *
* ** This function should never throw any kind of exception. This is particularly important * in the following cases: *
*However, if an exception occurs it should be directly logged at least as a WARNING.
* * @param rollbacktrue
to cancel the statement AND rollback the current connection transaction,
* false
to just cancel the statement.
*
* @since 2.1
*/
public void cancel(final boolean rollback);
/**
* End the last query performed by this {@link DBConnection} and free some associated resources * opened just for this last query.
* ** Originally, this function aims to be called when the result of {@link #executeQuery(ADQLQuery)} * is no longer needed, in order to clean/free what the {@link DBConnection} needed to keep this * result set open. In other words, if we take the example of a JDBC connection, this function will * close the {@link ResultSet}, the {@link Statement} and will end any transaction eventually opened * by the {@link DBConnection} (for instance if a fetchSize is set). *
* ** However, this function could also be used after any other operation performed by the {@link DBConnection}. * You should just be aware that, depending of the implementation, if a transaction has been opened, this * function may end it, which means generally that a rollback is performed. *
* ** Similarly, since it is supposed to end any query lastly performed, this function must also cancel * any processing. So, the function {@link #cancel(boolean)} should be called. *
* ** Finally, like {@link #cancel(boolean)}, this function should never throw any kind of exception. * If internally an exception occurs, it should be directly logged at least as a WARNING. *
* * @since 2.1 */ public void endQuery(); }