Skip to content
Snippets Groups Projects
Commit bd621842 authored by gmantele's avatar gmantele
Browse files

[TAP] New fix for the transaction management.

The transaction and Statement were closed too early before.
  - Fetching the row was not possible once the first bunch of fetched
rows was over.
  - The problem of "statement is aborted" preventing the re-use of
a same DB connection was apparently still there, but occurred less often.

  Now, any transaction potentially started in a DB connection is always
closed after one of the public functions of JDBCConnection is called ;
except executeQuery(ADQLQuery) whose the call MUST be wrapped inside a
try...catch block in which DBConnection.cancel(true) MUST be called
in case of error (in order to effectively end any started transaction).
parent b270eed3
No related branches found
No related tags found
No related merge requests found
......@@ -16,7 +16,7 @@ package tap;
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
......@@ -25,6 +25,10 @@ import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import adql.parser.ADQLParser;
import adql.parser.ADQLQueryFactory;
import adql.parser.ParseException;
import adql.query.ADQLQuery;
import tap.data.DataReadException;
import tap.data.TableIterator;
import tap.db.DBConnection;
......@@ -41,10 +45,6 @@ import uws.UWSToolBox;
import uws.job.JobThread;
import uws.job.Result;
import uws.service.log.UWSLog.LogLevel;
import adql.parser.ADQLParser;
import adql.parser.ADQLQueryFactory;
import adql.parser.ParseException;
import adql.query.ADQLQuery;
/**
* <p>Let process completely an ADQL query.</p>
......@@ -86,7 +86,7 @@ import adql.query.ADQLQuery;
* <p><i>Note:
* {@link #start()} is using the Template Method Design Pattern: it defines the skeleton/algorithm of the processing, and defers some steps
* to other functions.
* </i></p>
* </i></p>
*
* <p>
* So, you are able to customize almost all individual steps of the ADQL query processing: {@link #parseADQL()}, {@link #executeADQL(ADQLQuery)} and
......@@ -104,7 +104,7 @@ import adql.query.ADQLQuery;
* </p>
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 2.1 (11/2015)
* @version 2.1 (04/2016)
*/
public class ADQLExecutor {
......@@ -260,7 +260,7 @@ public class ADQLExecutor {
dbConn = service.getFactory().getConnection(jobID);
}
/**
/**
* Cancel the current SQL query execution or result set fetching if any is currently running.
* If no such process is on going, this function has no effect.
*
......@@ -324,7 +324,7 @@ public class ADQLExecutor {
* notify the user of the progression of the query execution. This parameter is removed at the end of the execution if it is successful.
* </p>
*
* <p>The "interrupted" flag of the associated thread is often tested so that stopping the execution as soon as possible.</p>
* <p>The "interrupted" flag of the associated thread is often tested so that stopping the execution as soon as possible.</p>
*
* @return The updated execution report.
*
......@@ -419,6 +419,9 @@ public class ADQLExecutor {
// Free the connection (so that giving it back to a pool, if any, otherwise, just free resources):
if (dbConn != null){
// be sure no query is still processing and that any open transaction is rollbacked and ended:
dbConn.cancel(true);
// free the connection:
service.getFactory().freeConnection(dbConn);
dbConn = null;
}
......
......@@ -49,6 +49,9 @@ import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import adql.translator.JDBCTranslator;
import adql.translator.PgSphereTranslator;
import adql.translator.PostgreSQLTranslator;
import tap.AbstractTAPFactory;
import tap.ServiceConnection;
import tap.TAPException;
......@@ -60,9 +63,6 @@ import uws.UWSException;
import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import uws.service.log.UWSLog.LogLevel;
import adql.translator.JDBCTranslator;
import adql.translator.PgSphereTranslator;
import adql.translator.PostgreSQLTranslator;
/**
* <p>Concrete implementation of a {@link TAPFactory} which is parameterized by a TAP configuration file.</p>
......@@ -74,7 +74,7 @@ import adql.translator.PostgreSQLTranslator;
* </p>
*
* @author Gr&eacute;gory Mantelet (ARI)
* @version 2.1 (02/2016)
* @version 2.1 (04/2016)
* @since 2.0
*/
public class ConfigurableTAPFactory extends AbstractTAPFactory {
......@@ -282,7 +282,7 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
public void freeConnection(DBConnection conn){
try{
// Cancel any possible query that could be running:
conn.cancel(false);
conn.cancel(true);
// Close the connection (if a connection pool is used, the connection is not really closed but is freed and kept in the pool for further usage):
((JDBCConnection)conn).getInnerConnection().close();
}catch(SQLException se){
......
......@@ -16,7 +16,7 @@ package tap.data;
* You should have received a copy of the GNU Lesser General Public License
* along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2014-2015 - Astronomisches Rechen Institut (ARI)
* Copyright 2014-2016 - Astronomisches Rechen Institut (ARI)
*/
import java.sql.ResultSet;
......@@ -26,14 +26,14 @@ import java.sql.Statement;
import java.sql.Timestamp;
import java.util.NoSuchElementException;
import tap.metadata.TAPColumn;
import uws.ISO8601Format;
import adql.db.DBColumn;
import adql.db.DBType;
import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region;
import adql.parser.ParseException;
import adql.translator.JDBCTranslator;
import tap.metadata.TAPColumn;
import uws.ISO8601Format;
/**
* <p>{@link TableIterator} which lets iterate over a SQL {@link ResultSet}.</p>
......@@ -43,7 +43,7 @@ import adql.translator.JDBCTranslator;
* </i></p>
*
* @author Gr&eacute;gory Mantelet (ARI)
* @version 2.1 (11/2015)
* @version 2.1 (04/2016)
* @since 2.0
*/
public class ResultSetTableIterator implements TableIterator {
......@@ -154,7 +154,7 @@ public class ResultSetTableIterator implements TableIterator {
* The second parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
......@@ -191,7 +191,7 @@ public class ResultSetTableIterator implements TableIterator {
* The second parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
......@@ -229,7 +229,7 @@ public class ResultSetTableIterator implements TableIterator {
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
*
* @throws NullPointerException If NULL is given in parameter.
* @throws DataReadException If the given ResultSet is closed or if the metadata (columns count and types) can not be fetched.
......@@ -261,7 +261,7 @@ public class ResultSetTableIterator implements TableIterator {
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
*
* @throws NullPointerException If NULL is given in parameter.
* @throws DataReadException If the given ResultSet is closed or if the metadata (columns count and types) can not be fetched.
......@@ -297,12 +297,12 @@ public class ResultSetTableIterator implements TableIterator {
* The third parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* @param dbms Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
*
* @throws NullPointerException If NULL is given in parameter.
......@@ -337,12 +337,12 @@ public class ResultSetTableIterator implements TableIterator {
* The third parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* @param dbms Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
*
* @throws NullPointerException If NULL is given in parameter.
......@@ -395,12 +395,12 @@ public class ResultSetTableIterator implements TableIterator {
* The third parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* @param dbms Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
* @param resultMeta List of expected columns. <i>note: these metadata are expected to be really {@link TAPColumn} objects ; MAY be NULL.</i>
*
......@@ -452,12 +452,12 @@ public class ResultSetTableIterator implements TableIterator {
* The third parameter of this constructor is given as second parameter of {@link #convertType(int, String, String)}.
* <b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
* Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* ResultSet is coming. Without this information, type guessing will be unpredictable!
* </i></p>
*
* @param dataSet Dataset over which this iterator must iterate.
* @param translator The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* JDBC types and to parse geometrical values. <i>note: MAY be NULL</i>
* @param dbms Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
* @param resultMeta List of expected columns. <i>note: these metadata are expected to be really {@link TAPColumn} objects ; MAY be NULL.</i>
*
......@@ -688,7 +688,8 @@ public class ResultSetTableIterator implements TableIterator {
return new DBType(DBDatatype.UNKNOWN);
// Extract the type prefix and lower-case it:
int startParamIndex = dbmsTypeName.indexOf('('), endParamIndex = dbmsTypeName.indexOf(')');
int startParamIndex = dbmsTypeName.indexOf('('),
endParamIndex = dbmsTypeName.indexOf(')');
String dbmsTypePrefix = (startParamIndex <= 0) ? dbmsTypeName : dbmsTypeName.substring(0, endParamIndex);
dbmsTypePrefix = dbmsTypePrefix.trim().toLowerCase();
String[] typeParams = (startParamIndex <= 0) ? null : dbmsTypeName.substring(startParamIndex + 1, endParamIndex).split(",");
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment