Commit c3e97e6e authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[TAP] Add an optional feature to enable quick fix of input ADQL query on error:

`fix_on_fail` in the configuration file. By default, this feature is disabled.

_With 15cd5944, this commit finishes the resolution of the GitHub issue #104 ._
parent 15cd5944
Loading
Loading
Loading
Loading
+101 −78
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@ package tap;
 * You should have received a copy of the GNU Lesser General Public License
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 *                       Astronomisches Rechen Institut (ARI)
 */
 */


@@ -105,7 +105,7 @@ import uws.service.log.UWSLog.LogLevel;
 * </p>
 * </p>
 *
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.1 (04/2017)
 * @version 2.3 (03/2019)
 */
 */
public class ADQLExecutor {
public class ADQLExecutor {


@@ -551,7 +551,30 @@ public class ADQLExecutor {
			parser.setQueryChecker(service.getFactory().createQueryChecker(uploadSchema));
			parser.setQueryChecker(service.getFactory().createQueryChecker(uploadSchema));


		// Parse the ADQL query:
		// Parse the ADQL query:
		ADQLQuery query = parser.parseQuery(tapParams.getQuery());
		ADQLQuery query = null;
		// if the fixOnFail option is enabled...
		if (service.fixOnFailEnabled()){
			try{
				// try parsing the query:
				query = parser.parseQuery(tapParams.getQuery());
			}catch(ParseException pe){
				// if it fails...
				// ...log the auto fix attempt:
				logger.logTAP(LogLevel.INFO, report, "PARSING", "Parse attempt of the original input query failed! Trying auto-fix...", null);
				// ...try fixing the query:
				String fixedQuery = parser.tryQuickFix(tapParams.getQuery());
				// ...log the auto fixed query, if successful:
				logger.logTAP(LogLevel.INFO, report, "PARSING", "Auto-fixed query: " + fixedQuery.replaceAll("(\t|\r?\n)+", " "), null);
				// ...keep this fixed query in the exec report:
				report.fixedQuery = fixedQuery;
				// ...and finally try parsing it a last time:
				query = parser.parseQuery(fixedQuery);
			}
		}
		// if not enabled, parse immediately the query:
		else{
			query = parser.parseQuery(tapParams.getQuery());
		}


		// Set or check the row limit:
		// Set or check the row limit:
		final int limit = query.getSelect().getLimit();
		final int limit = query.getSelect().getLimit();
+15 −2
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@ package tap;
 * You should have received a copy of the GNU Lesser General Public License
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 *                       Astronomisches Rechen Institut (ARI)
 */
 */


@@ -44,7 +44,7 @@ import uws.service.file.UWSFileManager;
 * </p>
 * </p>
 *
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.3 (09/2018)
 * @version 2.3 (03/2019)
 */
 */
public interface ServiceConnection {
public interface ServiceConnection {


@@ -744,4 +744,17 @@ public interface ServiceConnection {
	 */
	 */
	public int[] getFetchSize();
	public int[] getFetchSize();


	/**
	 * <i><b>[MANDATORY]</b></i>
	 * <p>This function tells whether TAP-Lib should automatically try to fix a
	 * query whose parsing failed because of a token error. After this fix
	 * attempt the query is parsed again for a last time.</p>
	 *
	 * @return	<i>true</i> to allow automatic fix attempt in case of error,
	 *        	<i>false</i> to disable this option.
	 *
	 * @since 2.3
	 */
	public boolean fixOnFailEnabled();

}
}
+62 −33
Original line number Original line Diff line number Diff line
package tap;
package tap;


import adql.db.DBColumn;

/*
/*
 * This file is part of TAPLibrary.
 * This file is part of TAPLibrary.
 *
 *
@@ -16,34 +18,49 @@ package tap;
 * You should have received a copy of the GNU Lesser General Public License
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 * 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-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 *                       Astronomisches Rechen Institut (ARI)
 */
 */


import tap.parameters.TAPParameters;
import tap.parameters.TAPParameters;
import adql.db.DBColumn;


/**
/**
 * <p>Report the execution (including the parsing and the output writing) of an ADQL query.
 * Report the execution (including the parsing and the output writing) of an
 * It gives information on the job parameters, the job ID, whether it is a synchronous task or not, times of each execution step (uploading, parsing, executing and writing),
 * ADQL query.
 * the resulting columns and the success or not of the execution.</p>
 *
 *
 * <p>This report is completely filled by {@link ADQLExecutor}, and aims to be used/read only at the end of the job or when it is definitely finished.</p>
 * <p>
 * 	It gives information on the job parameters, the job ID, whether it is a
 * 	synchronous task or not, times of each execution step (uploading, parsing,
 * 	executing and writing), the resulting columns and the success or not of the
 * 	execution.
 * </p>
 *
 * <p>
 * 	This report is completely filled by {@link ADQLExecutor}, and aims to be
 * 	used/read only at the end of the job or when it is definitely finished.
 * </p>
 *
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (04/2015)
 * @version 2.3 (03/2019)
 */
 */
public class TAPExecutionReport {
public class TAPExecutionReport {


	/** ID of the job whose the execution is reported here. */
	/** ID of the job whose the execution is reported here. */
	public final String jobID;
	public final String jobID;


	/** Indicate whether this execution is done in a synchronous or asynchronous job. */
	/** Indicate whether this execution is done in a synchronous or asynchronous
	 * job. */
	public final boolean synchronous;
	public final boolean synchronous;


	/** List of all parameters provided in the user request. */
	/** List of all parameters provided in the user request. */
	public final TAPParameters parameters;
	public final TAPParameters parameters;


	/** Input ADQL query after an automatic fix by TAP-Lib.
	 * <p>This field is set only if the option fix_on_fail is enabled in the TAP
	 * configuration and that a query has been fixed.</p>
	 * @since 2.3 */
	public String fixedQuery = null;

	/** List of all resulting columns. <i>Empty array, if not yet known.</i> */
	/** List of all resulting columns. <i>Empty array, if not yet known.</i> */
	public DBColumn[] resultingColumns = new DBColumn[0];
	public DBColumn[] resultingColumns = new DBColumn[0];


@@ -51,21 +68,26 @@ public class TAPExecutionReport {
	 * @since 2.0 */
	 * @since 2.0 */
	public long nbRows = -1;
	public long nbRows = -1;


	/** Duration of all execution steps. <i>For the moment only 4 steps (in the order): uploading, parsing, executing and writing.</i> */
	/** Duration of all execution steps. <i>For the moment only 4 steps (in the
	 * order): uploading, parsing, executing and writing.</i> */
	protected final long[] durations = new long[]{ -1, -1, -1, -1 };
	protected final long[] durations = new long[]{ -1, -1, -1, -1 };


	/** Total duration of the job execution. */
	/** Total duration of the job execution. */
	protected long totalDuration = -1;
	protected long totalDuration = -1;


	/** Indicate whether this job has ended successfully or not. <i>At the beginning or while executing, this field is always FALSE.</i> */
	/** Indicate whether this job has ended successfully or not.
	 * <i>At the beginning or while executing, this field is always FALSE.</i> */
	public boolean success = false;
	public boolean success = false;


	/**
	/**
	 * Build an empty execution report.
	 * Build an empty execution report.
	 *
	 *
	 * @param jobID			ID of the job whose the execution must be described here.
	 * @param jobID			ID of the job whose the execution must be described
	 * @param synchronous	<i>true</i> if the job is synchronous, <i>false</i> otherwise.
	 *             			here.
	 * @param params		List of all parameters provided by the user for the execution.
	 * @param synchronous	<i>true</i> if the job is synchronous,
	 *                   	<i>false</i> otherwise.
	 * @param params		List of all parameters provided by the user for the
	 *              		execution.
	 */
	 */
	public TAPExecutionReport(final String jobID, final boolean synchronous, final TAPParameters params){
	public TAPExecutionReport(final String jobID, final boolean synchronous, final TAPParameters params){
		this.jobID = jobID;
		this.jobID = jobID;
@@ -74,14 +96,20 @@ public class TAPExecutionReport {
	}
	}


	/**
	/**
	 * <p>Map the execution progression with an index inside the {@link #durations} array.</p>
	 * Map the execution progression with an index inside the {@link #durations}
	 * array.
	 *
	 *
	 * <p><i><b>Warning:</b> for the moment, only {@link ExecutionProgression#UPLOADING}, {@link ExecutionProgression#PARSING},
	 * <p><i><b>Warning:</b>
	 * {@link ExecutionProgression#EXECUTING_ADQL} and {@link ExecutionProgression#WRITING_RESULT} are managed.</i></p>
	 * 	for the moment, only {@link ExecutionProgression#UPLOADING},
	 * 	{@link ExecutionProgression#PARSING},
	 * 	{@link ExecutionProgression#EXECUTING_ADQL} and
	 * 	{@link ExecutionProgression#WRITING_RESULT} are managed.
	 * </i></p>
	 *
	 *
	 * @param tapProgression	Execution progression.
	 * @param tapProgression	Execution progression.
	 *
	 *
	 * @return	Index in the array {@link #durations}, or -1 if the given execution progression is not managed.
	 * @return	Index in the array {@link #durations},
	 *        	or -1 if the given execution progression is not managed.
	 */
	 */
	protected int getIndexDuration(final ExecutionProgression tapProgression){
	protected int getIndexDuration(final ExecutionProgression tapProgression){
		switch(tapProgression){
		switch(tapProgression){
@@ -103,7 +131,8 @@ public class TAPExecutionReport {
	 *
	 *
	 * @param tapStep	Job execution step.
	 * @param tapStep	Job execution step.
	 *
	 *
	 * @return	The corresponding duration (in ms), or -1 if this step has not been (yet) processed.
	 * @return	The corresponding duration (in ms), or -1 if this step has not
	 *        	been (yet) processed.
	 *
	 *
	 * @see #getIndexDuration(ExecutionProgression)
	 * @see #getIndexDuration(ExecutionProgression)
	 */
	 */
+45 −17
Original line number Original line Diff line number Diff line
@@ -16,13 +16,14 @@ package tap.config;
 * You should have received a copy of the GNU Lesser General Public License
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Copyright 2016-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2016-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 *                       Astronomisches Rechen Institut (ARI)
 */
 */


import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE;
import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE;
import static tap.config.TAPConfiguration.DEFAULT_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.DEFAULT_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.DEFAULT_EXECUTION_DURATION;
import static tap.config.TAPConfiguration.DEFAULT_EXECUTION_DURATION;
import static tap.config.TAPConfiguration.DEFAULT_FIX_ON_FAIL;
import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.DEFAULT_LOGGER;
import static tap.config.TAPConfiguration.DEFAULT_LOGGER;
import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS;
import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS;
@@ -39,6 +40,7 @@ import static tap.config.TAPConfiguration.KEY_DEFAULT_UPLOAD_LIMIT;
import static tap.config.TAPConfiguration.KEY_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.KEY_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.KEY_FILE_MANAGER;
import static tap.config.TAPConfiguration.KEY_FILE_MANAGER;
import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH;
import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH;
import static tap.config.TAPConfiguration.KEY_FIX_ON_FAIL;
import static tap.config.TAPConfiguration.KEY_GEOMETRIES;
import static tap.config.TAPConfiguration.KEY_GEOMETRIES;
import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.KEY_LOGGER;
import static tap.config.TAPConfiguration.KEY_LOGGER;
@@ -126,15 +128,17 @@ import uws.service.file.UWSFileManager;
import uws.service.log.UWSLog.LogLevel;
import uws.service.log.UWSLog.LogLevel;


/**
/**
 * <p>Concrete implementation of {@link ServiceConnection}, fully parameterized with a TAP configuration file.</p>
 * Concrete implementation of {@link ServiceConnection}, fully parameterized
 * with a TAP configuration file.
 *
 *
 * <p>
 * <p>
 * 	Every aspects of the TAP service are configured here. This instance is also creating the {@link TAPFactory} using the
 * 	Every aspects of the TAP service are configured here. This instance is also
 * 	TAP configuration file thanks to the implementation {@link ConfigurableTAPFactory}.
 * 	creating the {@link TAPFactory} using the TAP configuration file thanks to
 * 	the implementation {@link ConfigurableTAPFactory}.
 * </p>
 * </p>
 *
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.3 (11/2018)
 * @version 2.3 (03/2019)
 * @since 2.0
 * @since 2.0
 */
 */
public final class ConfigurableServiceConnection implements ServiceConnection {
public final class ConfigurableServiceConnection implements ServiceConnection {
@@ -142,10 +146,12 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
	/** File manager to use in the TAP service. */
	/** File manager to use in the TAP service. */
	private UWSFileManager fileManager;
	private UWSFileManager fileManager;


	/** Object to use in the TAP service in order to log different types of messages (e.g. DEBUG, INFO, WARNING, ERROR, FATAL). */
	/** Object to use in the TAP service in order to log different types of
	 * messages (e.g. DEBUG, INFO, WARNING, ERROR, FATAL). */
	private TAPLog logger;
	private TAPLog logger;


	/** Factory which can create different types of objects for the TAP service (e.g. database connection). */
	/** Factory which can create different types of objects for the TAP service
	 * (e.g. database connection). */
	private TAPFactory tapFactory;
	private TAPFactory tapFactory;


	/** Object gathering all metadata of this TAP service. */
	/** Object gathering all metadata of this TAP service. */
@@ -175,9 +181,11 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
	private final ArrayList<OutputFormat> outputFormats;
	private final ArrayList<OutputFormat> outputFormats;


	/** Array of 2 integers: resp. default and maximum output limit.
	/** Array of 2 integers: resp. default and maximum output limit.
	 * <em>Each limit is expressed in a unit specified in the array {@link #outputLimitTypes}.</em> */
	 * <em>Each limit is expressed in a unit specified in the array
	 * {@link #outputLimitTypes}.</em> */
	private int[] outputLimits = new int[]{ -1, -1 };
	private int[] outputLimits = new int[]{ -1, -1 };
	/** Array of 2 limit units: resp. unit of the default output limit and unit of the maximum output limit. */
	/** Array of 2 limit units: resp. unit of the default output limit and unit
	 * of the maximum output limit. */
	private LimitUnit[] outputLimitTypes = new LimitUnit[2];
	private LimitUnit[] outputLimitTypes = new LimitUnit[2];


	/** Indicate whether the UPLOAD feature is enabled or not. */
	/** Indicate whether the UPLOAD feature is enabled or not. */
@@ -201,20 +209,31 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
	private UserIdentifier userIdentifier = null;
	private UserIdentifier userIdentifier = null;


	/** List of all allowed coordinate systems.
	/** List of all allowed coordinate systems.
	 * <em>If NULL, all coord. sys. are allowed. If empty list, none is allowed.</em> */
	 * <em>
	 * 	If NULL, all coord. sys. are allowed. If empty list, none is allowed.
	 * </em> */
	private ArrayList<String> lstCoordSys = null;
	private ArrayList<String> lstCoordSys = null;


	/** List of all allowed ADQL geometrical functions.
	/** List of all allowed ADQL geometrical functions.
	 * <em>If NULL, all geometries are allowed. If empty list, none is allowed.</em> */
	 * <em>
	 * 	If NULL, all geometries are allowed. If empty list, none is allowed.
	 * </em> */
	private ArrayList<String> geometries = null;
	private ArrayList<String> geometries = null;
	private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)";
	private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)";


	/** List of all known and allowed User Defined Functions.
	/** List of all known and allowed User Defined Functions.
	 * <em>If NULL, any unknown function is allowed. If empty list, none is allowed.</em> */
	 * <em>If NULL, any unknown function is allowed. If empty list, none is
	 * allowed.</em> */
	private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0);
	private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0);


	/** Indicate whether the input ADQL query should be automatically fixed
	 * if its parsing fails because of an incorrect tokenization.
	 * @since 2.3 */
	private boolean isFixOnFailEnabled = DEFAULT_FIX_ON_FAIL;

	/**
	/**
	 * Create a TAP service description thanks to the given TAP configuration file.
	 * Create a TAP service description thanks to the given TAP configuration
	 * file.
	 *
	 *
	 * @param tapConfig	The content of the TAP configuration file.
	 * @param tapConfig	The content of the TAP configuration file.
	 *
	 *
@@ -226,12 +245,15 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
	}
	}


	/**
	/**
	 * Create a TAP service description thanks to the given TAP configuration file.
	 * Create a TAP service description thanks to the given TAP configuration
	 * file.
	 *
	 *
	 * @param tapConfig		The content of the TAP configuration file.
	 * @param tapConfig		The content of the TAP configuration file.
	 * @param webAppRootDir	The directory of the Web Application running this TAP service.
	 * @param webAppRootDir	The directory of the Web Application running this
	 *                     	<em>In this directory another directory may be created in order to store all TAP service files
	 *                     	TAP service. <em>In this directory another directory
	 *                     	if none is specified in the given TAP configuration file.</em>
	 *                     	may be created in order to store all TAP service
	 *                     	files if none is specified in the given TAP
	 *                     	configuration file.</em>
	 *
	 *
	 * @throws NullPointerException	If the given properties set is NULL.
	 * @throws NullPointerException	If the given properties set is NULL.
	 * @throws TAPException			If a property is wrong or missing.
	 * @throws TAPException			If a property is wrong or missing.
@@ -284,6 +306,7 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		initCoordSys(tapConfig);
		initCoordSys(tapConfig);
		initADQLGeometries(tapConfig);
		initADQLGeometries(tapConfig);
		initUDFs(tapConfig);
		initUDFs(tapConfig);
		isFixOnFailEnabled = Boolean.parseBoolean(getProperty(tapConfig, KEY_FIX_ON_FAIL));
	}
	}


	/**
	/**
@@ -1735,4 +1758,9 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		return fetchSize;
		return fetchSize;
	}
	}


	@Override
	public boolean fixOnFailEnabled(){
		return isFixOnFailEnabled;
	}

}
}
+11 −2
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@ package tap.config;
 * You should have received a copy of the GNU Lesser General Public License
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Copyright 2015-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 * Copyright 2015-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 *                       Astronomisches Rechen Institut (ARI)
 */
 */


@@ -41,7 +41,7 @@ import tap.backup.DefaultTAPBackupManager;
 * </i></p>
 * </i></p>
 *
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.3 (11/2018)
 * @version 2.3 (03/2019)
 * @since 2.0
 * @since 2.0
 */
 */
public final class TAPConfiguration {
public final class TAPConfiguration {
@@ -172,6 +172,15 @@ public final class TAPConfiguration {
	public final static String KEY_ASYNC_FETCH_SIZE = "async_fetch_size";
	public final static String KEY_ASYNC_FETCH_SIZE = "async_fetch_size";
	/** Default value of the property {@link #KEY_ASYNC_FETCH_SIZE}: {@value #DEFAULT_ASYNC_FETCH_SIZE}. */
	/** Default value of the property {@link #KEY_ASYNC_FETCH_SIZE}: {@value #DEFAULT_ASYNC_FETCH_SIZE}. */
	public final static int DEFAULT_ASYNC_FETCH_SIZE = 10000;
	public final static int DEFAULT_ASYNC_FETCH_SIZE = 10000;
	/** Name/Key of the property specifying whether the fixOnFail option is
	 * enabled or not. This option lets automatically fix the input ADQL query
	 * if its tokenization fails.
	 * @since 2.3  */
	public final static String KEY_FIX_ON_FAIL = "fix_on_fail";
	/** Default value of the property {@link #KEY_FIX_ON_FAIL}:
	 * {@value #DEFAULT_FIX_ON_FAIL}.
	 * @since 2.3  */
	public final static boolean DEFAULT_FIX_ON_FAIL = false;
	/** Name/Key of the property specifying the name of the DataSource into the JDNI. */
	/** Name/Key of the property specifying the name of the DataSource into the JDNI. */
	public final static String KEY_DATASOURCE_JNDI_NAME = "datasource_jndi_name";
	public final static String KEY_DATASOURCE_JNDI_NAME = "datasource_jndi_name";
	/** Name/Key of the property specifying the full class name of the JDBC driver.
	/** Name/Key of the property specifying the full class name of the JDBC driver.
Loading