/*
 * JBoss, Home of Professional Open Source.
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * 
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 * Modified by
 * @author  Data Virtuality GmbH
 * @date    $Date$
 *  
 */
// https://issues.jboss.org/browse/TEIID-2153
// https://issues.jboss.org/browse/TEIID-2171
// https://issues.jboss.org/browse/TEIID-2359
// https://issues.jboss.org/browse/TEIID-2149
// https://issues.jboss.org/browse/TEIID-2358
// https://issues.jboss.org/browse/TEIID-2410
// https://issues.jboss.org/browse/TEIID-2271
// https://issues.jboss.org/browse/TEIID-2467
// https://issues.jboss.org/browse/TEIID-2429
// https://issues.jboss.org/browse/TEIID-2363
// https://issues.jboss.org/browse/TEIID-2160
// https://issues.jboss.org/browse/TEIID-2461
// https://issues.jboss.org/browse/TEIID-2797
// https://issues.jboss.org/browse/TEIID-2326
// https://issues.jboss.org/browse/TEIID-1557
// https://issues.jboss.org/browse/TEIID-2453
// https://issues.jboss.org/browse/TEIID-3526
// https://issues.jboss.org/browse/TEIID-2619
// https://issues.jboss.org/browse/TEIID-4130
// https://issues.jboss.org/browse/TEIID-2327
// https://issues.jboss.org/browse/TEIID-3046
// https://issues.jboss.org/browse/TEIID-4076
// https://issues.jboss.org/browse/TEIID-2904
// https://issues.jboss.org/browse/TEIID-5462
// https://issues.jboss.org/browse/TEIID-5327
// https://issues.jboss.org/browse/TEIID-3630
// https://issues.jboss.org/browse/TEIID-3437
// https://issues.jboss.org/browse/TEIID-2559
// https://issues.jboss.org/browse/TEIID-2555
// https://issues.jboss.org/browse/TEIID-3530
// https://issues.redhat.com/browse/TEIID-3156
// https://issues.redhat.com/browse/TEIID-4202
// https://issues.redhat.com/browse/TEIID-5480
// https://issues.redhat.com/browse/TEIID-5499
package org.teiid.translator;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;

import org.teiid.connector.DataPlugin;
import org.teiid.core.TeiidException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.core.util.ReflectionHelper;
import org.teiid.language.*;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.metadata.FunctionMethod;
import org.teiid.metadata.FunctionParameter;
import org.teiid.metadata.MetadataFactory;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.translator.CacheDirective.Scope;
import org.teiid.translator.TypeFacility.RUNTIME_CODES;
import org.teiid.translator.TypeFacility.RUNTIME_NAMES;

import com.datavirtuality.dv.core.interfaces.DVCaller;


/**
 * <p>The primary entry point for a Translator.  This class should be extended by the custom translator writer.</p>
 * 
 * The deployer instantiates this class through reflection. So it is important to have no-arg constructor. Once constructed
 * the "start" method is called. This class represents the basic capabilities of the translator.
 */
public class ExecutionFactory<F, C> {
	public enum TransactionSupport {
		XA, 
		LOCAL, 
		NONE
	}
	
	// EXTENSION
	// ISSUE: DVCORE-591
	// FIXED BY: Salvatore Raunich
	// DATE: 2014.10.16
	private int maxTableNameLength = -1;
	/**
	 * Defines the max length allowed for a table name 
	 * @return
	 */
	@TranslatorProperty(display="Max Table Name Length",description="The maximum allowed length for a table name.",advanced=true)
	public int getMaxTableNameLength() {
		return maxTableNameLength;
	}
	
	public void setMaxTableNameLength(int arg0) {
		this.maxTableNameLength = arg0;
	}
	// END EXTENSION
	
	// EXTENSION
	// ISSUE: DVCORE-2926
	// FIXED BY: Salvatore Raunich
	// DATE: 2015.06.10
	private int maxColumnNameLength = -1;
	/**
	 * Defines the max length allowed for a column name 
	 * @return
	 */
	@TranslatorProperty(display="Max Column Name Length",description="The maximum allowed length for a column name.",advanced=true)
	public int getMaxColumnNameLength() {
		return maxColumnNameLength;
	}
	
	public void setMaxColumnNameLength(int arg0) {
		this.maxColumnNameLength = arg0;
	}
	// END EXTENSION
		
	private boolean createStringsAsClobs = false;
    @TranslatorProperty(display="Create string columns as clobs", description="True, if this connector creates string columns as clobs", advanced=true)
    public boolean isCreateStringsAsClobs() {
    	return createStringsAsClobs;
    }
    
    public void setCreateStringsAsClobs(boolean createStringsAsClobs) {
    	this.createStringsAsClobs = createStringsAsClobs;
    }

	private int stringClobsLengthThreshold = 64;
	@TranslatorProperty(display="String length Threshold when creating string columns as clobs", description="When createStringsAsClobs=true, string columns with length greater than this value are created as clobs; default is 64", advanced=true)
	public int getStringClobsLengthThreshold() {
		return stringClobsLengthThreshold;
	}

	public void setStringClobsLengthThreshold(int stringClobsLengthThreshold) {
		this.stringClobsLengthThreshold = stringClobsLengthThreshold;
	}

	protected Boolean allowsSpecialCharsInColumnName = null;

	@TranslatorProperty(display="Allows the handling and mapping of column names with special chars", description="Default is false. Extra chars accepted are whitespace, -, (, ) and *", advanced=true)
	public boolean allowsSpecialCharsInColumnName() {
		return allowsSpecialCharsInColumnName != null ? allowsSpecialCharsInColumnName : false;
	}

	public void setAllowsSpecialCharsInColumnName(boolean allowsSpecialCharsInColumnName) {
		this.allowsSpecialCharsInColumnName = allowsSpecialCharsInColumnName;
	}

	public enum SupportedJoinCriteria {
		/**
		 * Indicates that any supported criteria is allowed.
		 */
		ANY, 
		/**
		 * Indicates that any simple comparison of elements is allowed. 
		 */
		THETA,
		/**
		 * Indicates that only equality predicates of elements are allowed.
		 */
		EQUI,
		/**
		 * Indicates that only equality predicates between
		 * exactly one primary and foreign key is allowed per join.
		 */
		KEY
	}
	
	public enum NullOrder {
		HIGH,
		LOW,
		FIRST,
		LAST,
		UNKNOWN
	}

	public static final int DEFAULT_MAX_FROM_GROUPS = -1;
	public static final int DEFAULT_MAX_IN_CRITERIA_SIZE = -1;

	// the following variables are used to hold cost estimates (roughly in milliseconds)
	public final static float DEFAULT_SOURCE_COMPARE_TIME = .0001f;
	public final static float DEFAULT_SOURCE_READ_TIME = .001f;
	public final static float DEFAULT_SOURCE_NEW_REQUEST_TIME = 100;

	private static final TypeFacility TYPE_FACILITY = new TypeFacility();
	
	/*
	 * Managed execution properties
	 */
	private boolean immutable;
	private boolean sourceRequired = true;
	private Boolean sourceRequiredForMetadata;
	private boolean threadBound;
	
	/*
	 * Support properties
	 */
	private boolean supportsSelectDistinct;
	private boolean supportsOuterJoins;
	private SupportedJoinCriteria supportedJoinCriteria = SupportedJoinCriteria.ANY;
	private boolean supportsOrderBy;
	private boolean supportsInnerJoins;
	private boolean supportsFullOuterJoins;
	private boolean requiresCriteria;
	private int maxInSize = DEFAULT_MAX_IN_CRITERIA_SIZE;
	private float newRequestTime = DEFAULT_SOURCE_NEW_REQUEST_TIME;
	private float readTime = DEFAULT_SOURCE_READ_TIME;
	private float compareTime = DEFAULT_SOURCE_COMPARE_TIME;
	private int maxDependentInPredicates = DEFAULT_MAX_IN_CRITERIA_SIZE;
	private boolean copyLobs;
	// EXTENSION
	// ISSUE: DVCORE-2440
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.18
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177
	private boolean supportsNativeQueries;
	// END EXTENSION
	private LinkedList<FunctionMethod> pushdownFunctions = new LinkedList<FunctionMethod>();
	// EXTENSION
	// ISSUE: DVCORE-2440
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.18
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177
	private String nativeProcedureName = "native"; //$NON-NLS-1$
	// END EXTENSION
	private String collationLocale;

	private TransactionSupport transactionSupport = TransactionSupport.XA;
	
	/**
	 * Initialize the connector with supplied configuration
	 */
	@SuppressWarnings("unused")
	public void start() throws TranslatorException {
	}
	    
	/**
	 * Defines if the Connector is read-only connector 
	 * @return
	 */
	@TranslatorProperty(display="Is Immutable",description="Is Immutable, True if the source never changes.",advanced=true)
	public boolean isImmutable() {
		return immutable;
	}
	
	public void setImmutable(boolean arg0) {
		this.immutable = arg0;
	}

	@TranslatorProperty(display="Copy LOBs",description="If true, returned LOBs will be copied, rather than streamed from the source",advanced=true)
	public boolean isCopyLobs() {
		return copyLobs;
	}
	
	public void setCopyLobs(boolean copyLobs) {
		this.copyLobs = copyLobs;
	}
	
	// EXTENSION
	// ISSUE: DVCORE-968,DVCORE-980
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.02.03,2014.02.13
	public String getOrderByStringConversionDefault() {
		return (String) DVCaller.call(40, this.getClass());
	}
	private String orderByStringConversion = null;
	@TranslatorProperty(display="OrderBy String Conversion Template",description="Set a template to convert ORDERBY clauses on strings, like this: \"cast((%s) as varchar(2000) ccsid 1208)\"", advanced=true)
	public String getOrderByStringConversion() {
		return orderByStringConversion != null ? orderByStringConversion : getOrderByStringConversionDefault();
	}
	public void setOrderByStringConversion(String orderByStringConversion) {
		this.orderByStringConversion = orderByStringConversion;
	}
	// END EXTENSION

	public String getComparisonStringConversionDefault() {
		return (String) DVCaller.call(160, this.getClass());
	}
	private String comparisonStringConversion = null;
	@TranslatorProperty(display="String Conversion Template",description="Set a template to convert WHERE clauses on strings, like this: \"cast((%s) as varchar(2000) ccsid 1208)\"", advanced=true)
	public String getComparisonStringConversion() {
		return comparisonStringConversion != null ? comparisonStringConversion : getComparisonStringConversionDefault();
	}
	public void setComparisonStringConversion(String comparisonStringConversion) {
		this.comparisonStringConversion = comparisonStringConversion;
	}

	// EXTENSION
	// ISSUE: DVCORE-1121
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.03.31
	public boolean getOrderByStringConversionToProjectionDefault() {
		final Boolean var = (Boolean) DVCaller.call(44, this.getClass());
		return var == null ? true : var;
	}
	private Boolean orderByStringConversionToProjection = null;
	@TranslatorProperty(display="OrderBy String Conversion To Projection",description="Whether to apply ORDERBY string conversion to SELECT clause projection symbols", advanced=true)
	public boolean getOrderByStringConversionToProjection() {
		return orderByStringConversionToProjection != null ? orderByStringConversionToProjection : getOrderByStringConversionToProjectionDefault();
	}
	public void setOrderByStringConversionToProjection(boolean orderByStringConversionToProjection) {
		this.orderByStringConversionToProjection = orderByStringConversionToProjection;
	}
	// END EXTENSION

	/**
	 * Return a connection object from the given connection factory.
	 * 
	 * The default implementation assumes a JCA {@link ConnectionFactory}.  Subclasses should override, if they use 
	 * another type of connection factory.
	 * 
	 * @deprecated
	 * @see #getConnection(Object, ExecutionContext)
	 * @param factory
	 * @return a connection
	 * @throws TranslatorException
	 */
	@Deprecated
	@SuppressWarnings("unchecked")
	public C getConnection(F factory) throws TranslatorException {

		if (factory == null) {
			return null;
		}
		if (factory instanceof ConnectionFactory) {
			try {
				return (C) ((ConnectionFactory)factory).getConnection();
			} catch (ResourceException e) {
				// EXTENSION
				// ISSUE: DVCORE-782
				// FIXED BY: Roman Pedchenko
				// DATE: 2013.11.11
				StringBuilder msg = new StringBuilder();
				Throwable e1 = e;
				while (e1 != null) {
					String msg1 = e1.getMessage();
					e1 = e1.getCause();
					if (msg1 == null)
						continue;
					if (msg.length() > 1)
						msg.append(": ");
					msg.append(msg1);
				}
				// END EXTENSION
				 throw new TranslatorException(DataPlugin.Event.TEIID60000, e);
			}
		}
		throw new TranslatorException(DataPlugin.Event.TEIID70000, DataPlugin.Util.gs(DataPlugin.Event.TEIID70000, factory.getClass().getName()));
	}
	
	/**
	 * Return a connection object from the given connection factory.
	 * 
	 * The default implementation assumes a JCA {@link ConnectionFactory}.  Subclasses should override, if they use 
	 * another type of connection factory or wish to use the {@link ExecutionContext}.  By default calls {@link #getConnection(Object)}
	 * 
	 * @param factory
	 * @param executionContext null if this is a system request for a connection
	 * @return a connection
	 * @throws TranslatorException
	 */
	public C getConnection(F factory,
			ExecutionContext executionContext) throws TranslatorException {
		return getConnection(factory);
	}

	/**
	 * Closes a connection object from the given connection factory.
	 * 
	 * The default implementation assumes a JCA {@link Connection}.  Subclasses should override, if they use 
	 * another type of connection.
	 * 
	 * @param connection
	 * @param factory
	 */
	public void closeConnection(C connection, F factory) {
		if (connection == null) {
			return;
		}
		if (connection instanceof Connection) {
			try {
				((Connection)connection).close();
			} catch (ResourceException e) {
				LogManager.logDetail(LogConstants.CTX_CONNECTOR, e, "Error closing"); //$NON-NLS-1$
			}
			return;
		}
		throw new AssertionError(DataPlugin.Util.gs(DataPlugin.Event.DVCORE94027)); 
	}
	
    /**
     * Flag that indicates if a underlying source connection required for this execution factory to work 
     * @return
     */
	public boolean isSourceRequired() {
		return sourceRequired;
	}	
	
	public void setSourceRequired(boolean value) {
		this.sourceRequired = value;
	}
	
	/**
     * Flag that indicates if a underlying source connection required for this execution factory to return metadata 
     * @return {@link Boolean#TRUE} if required, null if possibly required, or {@link Boolean#FALSE} if not required
     */
	public boolean isSourceRequiredForMetadata() {
		if (sourceRequiredForMetadata == null) {
			//matches pre 8.1 behavior
			return sourceRequired; 
		}
		//TODO we could also consider making this an annotation of the getMetadata call
		return sourceRequiredForMetadata;
	}
	
	public void setSourceRequiredForMetadata(boolean sourceRequiredForMetadata) {
		this.sourceRequiredForMetadata = sourceRequiredForMetadata;
	}
	
	// EXTENSION
	// ISSUE: DV-99
	// FIXED BY: Salvatore Raunich
	// Applied solution from TEIID-2344
	// DATE: 2013.11.08
	/**
      * If true, the {@link #initCapabilities(Object)} method will be consulted prior
      * to deteremining the capabilites
      * @return
      */
     public boolean isSourceRequiredForCapabilities() {
    	return false;
    }
    
     protected Boolean supportsStringAgg=null;

     @TranslatorProperty(display="Supports STRING_AGG", description="True, if this connector supports STRING_AGG function", advanced=true)
     public Boolean supportsStringAgg() {
 		if (supportsStringAgg == null)
 			return false;
     	return supportsStringAgg;
     }
     
 	public void setSupportsStringAgg(Boolean supportsStringAgg) {
 		this.supportsStringAgg = supportsStringAgg;
 	}
     
 	protected Boolean supportsDistinctInStringAgg=null;
 	
 	@TranslatorProperty(display="Supports DISTINCT in STRING_AGG", description="True, if this connector supports DISTINCT in STRING_AGG function", advanced=true)
 	public Boolean supportsDistinctInStringAgg() {
 		if (supportsDistinctInStringAgg == null)
 			return true;
 		return supportsDistinctInStringAgg;
 	}
 	
 	public void setSupportsDistinctInStringAgg(Boolean supportsDistinctInStringAgg) {
 		this.supportsDistinctInStringAgg = supportsDistinctInStringAgg;
 	}
 	
    /** 
      * Invoked if {@link #isSourceRequiredForCapabilities()} returns true
      * @param connection
      * @throws TranslatorException
      */
     public void initCapabilities(C connection) throws TranslatorException {
             
     }
     // END EXTENSION
	
    /**
     * Obtain a reference to the default LanguageFactory that can be used to construct
     * new language interface objects.  This is typically needed when modifying the language
     * objects passed to the connector or for testing when objects need to be created. 
     */
    public LanguageFactory getLanguageFactory()  {
		return LanguageFactory.INSTANCE;
	}
    
    /**
     * Obtain a reference to the type facility, which can be used to perform many type 
     * conversions supplied by the Connector API.
     */
    public TypeFacility getTypeFacility() {
		return TYPE_FACILITY;
	}
    
    /**
     * Create an execution object for the specified command  
     * @param command the command
     * @param executionContext Provides information about the context that this command is
     * executing within, such as the identifiers for the command being executed
     * @param metadata Access to runtime metadata if needed to translate the command
     * @param connection connection factory object to the data source
     * @return An execution object that can use to execute the command
     */
	public Execution createExecution(Command command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
		// EXTENSION
		// ISSUE: DVCORE-2440
		// FIXED BY: Roman Pedchenko
		// DATE: 2014.10.18
		// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177
		if (command instanceof Call) {
			Call obj = (Call)command;
			//TODO: our extension property support in designer makes ad-hoc properties impossible, so
			//we just match based upon name.  it would be better to have the metadatarepository/tooling add a teiid property
			//to explicitly set this proc as direct.
			//the other approach would be to addd a native system stored procedure, but that would require
			//special security semantics, whereas this proc can be secured on a schema basis
			if (supportsNativeQueries() && obj.getMetadataObject().getName().equals(getNativeQueryProcedureName())) {
				List<Argument> arguments = obj.getArguments();
	    		return createDirectExecution(arguments, command, executionContext, metadata, connection);
			}
		}
		// END EXTENSION
		if (command instanceof QueryExpression) {
			return createResultSetExecution((QueryExpression)command, executionContext, metadata, connection);
		}
		if (command instanceof Call) {
			return createProcedureExecution((Call)command, executionContext, metadata, connection);
		}
		return createUpdateExecution(command, executionContext, metadata, connection);
	}

	@SuppressWarnings("unused")
	public ResultSetExecution createResultSetExecution(QueryExpression command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
		 throw new TranslatorException(DataPlugin.Event.TEIID60001, DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createResultSetExecution")); //$NON-NLS-1$
	}

	@SuppressWarnings("unused")
	public ProcedureExecution createProcedureExecution(Call command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
		 throw new TranslatorException(DataPlugin.Event.TEIID60001,  DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createProcedureExecution")); //$NON-NLS-1$
	}

	@SuppressWarnings("unused")
	public UpdateExecution createUpdateExecution(Command command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
		 throw new TranslatorException(DataPlugin.Event.TEIID60001,  DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createUpdateExecution")); //$NON-NLS-1$
	}   
	
	// EXTENSION
	// ISSUE: DVCORE-2440
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.18
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177
	@SuppressWarnings("unused")
	public ProcedureExecution createDirectExecution(List<Argument> arguments, Command command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
		 throw new TranslatorException(DataPlugin.Event.TEIID60001, DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createDirectExecution")); //$NON-NLS-1$
	}	
	
	// END EXTENSION

	/**
	 * Get Metadata Processor for the translator to read the metadata
	 * @return
	 */
 	public MetadataProcessor<C> getMetadataProcessor() {
		return null;
 	}

    /**
     * Support indicates connector can accept queries with SELECT DISTINCT
     * @since 3.1 SP2 
     */
	@TranslatorProperty(display="Supports Select Distinct", description="True, if this connector supports SELECT DISTINCT", advanced=true)
    public boolean supportsSelectDistinct() {
    	return supportsSelectDistinct;
    }
	
	public void setSupportsSelectDistinct(boolean supportsSelectDistinct) {
		this.supportsSelectDistinct = supportsSelectDistinct;
	}

	private boolean supportsSelectExpression=false;
    /** 
     * Support indicates connector can accept expressions other than element
     * symbols in the SELECT clause.  Specific supports for the expression
     * type are still checked.
     * @since 6.1.0
     */
	@TranslatorProperty(display="Supports Select Expression", description="True, if this connector supports expressions in SELECT clause", advanced=true)
    public boolean supportsSelectExpression() {
    	return supportsSelectExpression;
    }

	public void setSupportsSelectExpression(boolean supportsSelectExpression) {
		this.supportsSelectExpression = supportsSelectExpression;
	}

	private boolean supportsAliasedTable=false;
    /**
     * Support indicates connector can accept groups with aliases  
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aliased Table", description="True, if this connector supports groups with aliases", advanced=true)
    public boolean supportsAliasedTable() {
    	return supportsAliasedTable;
    }
    
    public void setSupportsAliasedTable(boolean supportsAliasedTable) {
    	this.supportsAliasedTable = supportsAliasedTable;
    }

    /** 
     * Get the supported join criteria. A null return value will be treated
     * as {@link SupportedJoinCriteria#ANY}  
     * @since 6.1.0
     */
	@TranslatorProperty(display="Supported Join Criteria", description="Returns one of any, theta, equi, or key", advanced=true)
    public SupportedJoinCriteria getSupportedJoinCriteria() {
    	return supportedJoinCriteria;
    }
	
	public void setSupportedJoinCriteria(
			SupportedJoinCriteria supportedJoinCriteria) {
		this.supportedJoinCriteria = supportedJoinCriteria;
	}
    
    /** 
     * Support indicates connector can accept inner or cross joins
     * @since 6.1.0
     */
	@TranslatorProperty(display="Supports Inner Joins", description="True, if this connector supports inner joins", advanced=true)
    public boolean supportsInnerJoins() {
    	return supportsInnerJoins;
    }
	
	public void setSupportsInnerJoins(boolean supportsInnerJoins) {
		this.supportsInnerJoins = supportsInnerJoins;
	}
    
	private boolean supportsSelfJoins=false;
    /** 
     * Support indicates connector can accept self-joins where a 
     * group is joined to itself with aliases.  Connector must also support
     * {@link #supportsAliasedTable()}. 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Self Joins", description="True, if this connector supports self joins", advanced=true)
    public boolean supportsSelfJoins() {
    	return supportsSelfJoins;
    }
	
	public void setSupportsSelfJoins(boolean supportsSelfJoins) {
		this.supportsSelfJoins = supportsSelfJoins;
	}

	/** 
     * Support indicates connector can accept left outer joins 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Outer Joins", description="True, if this connector supports outer joins", advanced=true)
    public boolean supportsOuterJoins() {
    	return supportsOuterJoins;
    }
	
	public void setSupportsOuterJoins(boolean supportsOuterJoins) {
		this.supportsOuterJoins = supportsOuterJoins;
	}
    
    /** 
     * Support indicates connector can accept full outer joins
     * @since 3.1 SP2 
     */
	@TranslatorProperty(display="Supports Full Outer Joins", description="True, if this connector supports full outer joins", advanced=true)
    public boolean supportsFullOuterJoins() {
    	return supportsFullOuterJoins;
    }
	
	public void setSupportsFullOuterJoins(boolean supportsFullOuterJoins) {
		this.supportsFullOuterJoins = supportsFullOuterJoins;
	}

	private boolean supportsInlineViews=false;
    /** 
     * Support indicates connector can accept inline views (subqueries
     * in the FROM clause).  
     * @since 4.1 
     */
	@TranslatorProperty(display="Supports Inline Views", description="True, if this connector supports inline views (subqueries in the FROM clause)", advanced=true)
    public boolean supportsInlineViews() {
    	return supportsInlineViews;
    }

	public void setSupportsInlineViews(boolean supportsInlineViews) {
		this.supportsInlineViews = supportsInlineViews;
	}

	private boolean supportsWhereColumnEqualsColumn = true;

	@TranslatorProperty(display="Supports column equals another column", description="True, if this connector supports criteria of form (column1 = column2)", advanced=true)
	public boolean supportsWhereColumnEqualsColumn() {
		return supportsWhereColumnEqualsColumn;
	}

	public void setSupportsWhereColumnEqualsColumn(boolean supportsWhereColumnEqualsColumn) {
		this.supportsWhereColumnEqualsColumn = supportsWhereColumnEqualsColumn;
	}

	private boolean supportsCompareCriteriaEquals=false;
	/** 
     * Support indicates connector accepts criteria of form (element = constant) 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Compare Criteria Equals", description="True, if this connector supports criteria of form (element = constant)", advanced=true)
    public boolean supportsCompareCriteriaEquals() {
    	return supportsCompareCriteriaEquals;
    }

	public void setSupportsCompareCriteriaEquals(boolean supportsCompareCriteriaEquals) {
		this.supportsCompareCriteriaEquals = supportsCompareCriteriaEquals;
	}

	private boolean supportsCompareCriteriaOrdered=false;
	/** 
     * Support indicates connector accepts criteria of form (element &lt;=|&gt;= constant)
     * <br>The query engine will may pushdown queries containing &lt; or &gt; if NOT is also
     * supported.  
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Compare Criteria Ordered", description="True, if this connector supports criteria of form (element <=|>= constant)", advanced=true)
    public boolean supportsCompareCriteriaOrdered() {
    	return supportsCompareCriteriaOrdered;
    }

	public void setSupportsCompareCriteriaOrdered(boolean supportsCompareCriteriaOrdered) {
		this.supportsCompareCriteriaOrdered = supportsCompareCriteriaOrdered;
	}

	private boolean supportsLikeCriteria=false;
	/** 
     * Support indicates connector accepts criteria of form (element LIKE constant) 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Like Criteria", description="True, if this connector supports criteria of form (element LIKE constant)", advanced=true)
    public boolean supportsLikeCriteria() {
    	return supportsLikeCriteria;
    }
        
	public void setSupportsLikeCriteria(boolean supportsLikeCriteria) {
		this.supportsLikeCriteria = supportsLikeCriteria;
	}

	private boolean supportsLikeCriteriaEscapeCharacter=false;
	/** 
     * Support indicates connector accepts criteria of form (element LIKE constant ESCAPE char)
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Like Criteria Escape Character", description="True, if this connector supports criteria of form (element LIKE constant ESCAPE char)", advanced=true)
    public boolean supportsLikeCriteriaEscapeCharacter() {
    	return supportsLikeCriteriaEscapeCharacter;
    }

	public void setSupportsLikeCriteriaEscapeCharacter(boolean supportsLikeCriteriaEscapeCharacter) {
		this.supportsLikeCriteriaEscapeCharacter = supportsLikeCriteriaEscapeCharacter;
	}

	private boolean supportsInCriteria=false;
	/** 
     * Support indicates connector accepts criteria of form (element IN set) 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports In Criteria", description="True, if this connector supports criteria of form (element IN set)", advanced=true)
    public boolean supportsInCriteria() {
    	return supportsInCriteria;
    }

	public void setSupportsInCriteria(boolean supportsInCriteria) {
		this.supportsInCriteria = supportsInCriteria;
	}

	private boolean supportsInCriteriaSubquery=false;
	/** 
     * Support indicates connector accepts IN criteria with a subquery on the right side 
     * @since 4.0
     */
	@TranslatorProperty(display="Supports In Criteria Subquery", description="True, if this connector supports IN criteria with a subquery on the right side", advanced=true)
    public boolean supportsInCriteriaSubquery() {
    	return supportsInCriteriaSubquery;
    }

	public void setSupportsInCriteriaSubquery(boolean supportsInCriteriaSubquery) {
		this.supportsInCriteriaSubquery = supportsInCriteriaSubquery;
	}

	private boolean supportsIsNullCriteria=false;
	/** 
     * Support indicates connector accepts criteria of form (element IS NULL) 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Is Null Criteria", description="True, if this connector supports criteria of form (element IS NULL)", advanced=true)
    public boolean supportsIsNullCriteria() {
    	return supportsIsNullCriteria;
    }

	public void setSupportsIsNullCriteria(boolean supportsIsNullCriteria) {
		this.supportsIsNullCriteria = supportsIsNullCriteria;
	}

	private boolean supportsOrCriteria=false;
	/** 
     * Support indicates connector accepts logical criteria connected by OR 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Or Criteria", description="True, if this connector supports logical criteria connected by OR", advanced=true)
    public boolean supportsOrCriteria() {
    	return supportsOrCriteria;
    }

	public void setSupportsOrCriteria(boolean supportsOrCriteria) {
		this.supportsOrCriteria = supportsOrCriteria;
	}

	private boolean supportsNotCriteria=false;
	/** 
     * Support indicates connector accepts logical criteria NOT 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Not Criteria", description="True, if this connector supports logical criteria NOT", advanced=true)
    public boolean supportsNotCriteria() {
    	return supportsNotCriteria;
    }

	public void setSupportsNotCriteria(boolean supportsNotCriteria) {
		this.supportsNotCriteria = supportsNotCriteria;
	}

	private boolean supportsExistsCriteria=false;
	/** 
     * Support indicates connector accepts the EXISTS criteria 
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Exists Criteria", description="True, if this connector supports the EXISTS criteria", advanced=true)
    public boolean supportsExistsCriteria() {
    	return supportsExistsCriteria;
    }

	public void setSupportsExistsCriteria(boolean supportsExistsCriteria) {
		this.supportsExistsCriteria = supportsExistsCriteria;
	}

	private boolean supportsQuantifiedCompareCriteriaSome=false;
	/** 
     * Support indicates connector accepts the quantified comparison criteria that 
     * use SOME
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Quantified Compare Criteria Some", description="True, if this connector supports the quantified comparison criteria that use SOME", advanced=true)
    public boolean supportsQuantifiedCompareCriteriaSome() {
    	return supportsQuantifiedCompareCriteriaSome;
    }

	public void setSupportsQuantifiedCompareCriteriaSome(boolean supportsQuantifiedCompareCriteriaSome) {
		this.supportsQuantifiedCompareCriteriaSome = supportsQuantifiedCompareCriteriaSome;
	}

	private boolean supportsQuantifiedCompareCriteriaAll=false;
	/** 
     * Support indicates connector accepts the quantified comparison criteria that 
     * use ALL
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Quantified Compare Criteria All", description="True, if this connector supports the quantified comparison criteria that use ALL", advanced=true)
    public boolean supportsQuantifiedCompareCriteriaAll() {
    	return supportsQuantifiedCompareCriteriaAll;
    }

	public void setSupportsQuantifiedCompareCriteriaAll(boolean supportsQuantifiedCompareCriteriaAll) {
		this.supportsQuantifiedCompareCriteriaAll = supportsQuantifiedCompareCriteriaAll;
	}

	/** 
     * Support indicates connector accepts ORDER BY clause, including multiple elements
     * and ascending and descending sorts.    
     * @since 3.1 SP2
     */
    @TranslatorProperty(display="Supports ORDER BY", description="True, if this connector supports ORDER BY", advanced=true)
    public boolean supportsOrderBy() {
    	return supportsOrderBy;
    }
    
    public void setSupportsOrderBy(boolean supportsOrderBy) {
		this.supportsOrderBy = supportsOrderBy;
	}

	/**
	 * Indicates the collation used for sorting
	 */
	@TranslatorProperty(display="Collation Locale", description="The collation locale used by default for sorting.", advanced=true)
	public String getCollationLocale() {
		return collationLocale;
	}

	public void setCollationLocale(String collation) {
		this.collationLocale = collation;
	}


	private boolean supportsOrderByUnrelated=false;
    /**
     * Support indicates connector accepts ORDER BY clause with columns not from the select    
     * @since 6.2
     * @return
     */
	@TranslatorProperty(display="Supports Order By Unrelated", description="True, if this connector supports ORDER BY clause with columns not from the select", advanced=true)
    public boolean supportsOrderByUnrelated() {
    	return supportsOrderByUnrelated;
    }
    
	public void setSupportsOrderByUnrelated(boolean supportsOrderByUnrelated) {
		this.supportsOrderByUnrelated = supportsOrderByUnrelated;
	}

	public List<?> translateConversionString(Condition obj, ExecutionContext context, boolean isUpdate,
											 List<?> converted) {
		return converted;
	}

	/**
     * Returns the default null ordering
     * @since 7.1
     * @return the {@link NullOrder}
     */
    public NullOrder getDefaultNullOrder() {
    	return NullOrder.UNKNOWN;
    }
    
	private boolean supportsOrderByNullOrdering=false;
	/**
	 * Returns whether the database supports explicit null ordering.
	 * @since 7.1
	 * @return true if nulls first/last can be specified
	 */
	@TranslatorProperty(display="Supports Order By Null Ordering", description="True, if nulls first/last can be specified", advanced=true)
	public boolean supportsOrderByNullOrdering() {
		return supportsOrderByNullOrdering;
	}
    
	public void setSupportsOrderByNullOrdering(boolean supportsOrderByNullOrdering) {
		this.supportsOrderByNullOrdering = supportsOrderByNullOrdering;
	}

	private boolean supportsGroupBy=false;
	/**
     * Whether the source supports an explicit GROUP BY clause
     * @since 6.1
     */
	@TranslatorProperty(display="Supports Group By", description="True, if this connector supports an explicit GROUP BY clause", advanced=true)
    public boolean supportsGroupBy() {
    	return supportsGroupBy;
    }
    
	public void setSupportsGroupBy(boolean supportsGroupBy) {
		this.supportsGroupBy = supportsGroupBy;
	}

	private boolean supportsOnlySingleTableGroupBy=false;
	/**
     * Whether the source supports grouping only over a single table
     * @return
     */
	@TranslatorProperty(display="Supports Only Single Table Group By", description="True, if this connector supports grouping only over a single table", advanced=true)
    public boolean supportsOnlySingleTableGroupBy() {
    	return supportsOnlySingleTableGroupBy;
    }

	public void setSupportsOnlySingleTableGroupBy(boolean supportsOnlySingleTableGroupBy) {
		this.supportsOnlySingleTableGroupBy = supportsOnlySingleTableGroupBy;
	}

	private boolean supportsHaving=false;
	/**
     * Whether the source supports the HAVING clause
     * @since 6.1
     */
	@TranslatorProperty(display="Supports Having", description="True, if this connector supports the HAVING clause", advanced=true)
    public boolean supportsHaving() {
    	return supportsHaving;
    }
    
	public void setSupportsHaving(boolean supportsHaving) {
		this.supportsHaving = supportsHaving;
	}

	private boolean supportsAggregatesSum=false;
	/** 
     * Support indicates connector can accept the SUM aggregate function 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aggregates Sum", description="True, if this connector supports the SUM aggregate function", advanced=true)
    public boolean supportsAggregatesSum() {
    	return supportsAggregatesSum;
    }
    
	public void setSupportsAggregatesSum(boolean supportsAggregatesSum) {
		this.supportsAggregatesSum = supportsAggregatesSum;
	}

	private boolean supportsAggregatesAvg=false;
	/** 
     * Support indicates connector can accept the AVG aggregate function
     * @since 3.1 SP2 
     */
	@TranslatorProperty(display="Supports Aggregates Avg", description="True, if this connector supports the AVG aggregate function", advanced=true)
    public boolean supportsAggregatesAvg() {
    	return supportsAggregatesAvg;
    }
    
	public void setSupportsAggregatesAvg(boolean supportsAggregatesAvg) {
		this.supportsAggregatesAvg = supportsAggregatesAvg;
	}

	private boolean supportsAggregatesMin=false;
	/** 
     * Support indicates connector can accept the MIN aggregate function 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aggregates Min", description="True, if this connector supports the MIN aggregate function", advanced=true)
    public boolean supportsAggregatesMin() {
    	return supportsAggregatesMin;
    }
    
	public void setSupportsAggregatesMin(boolean supportsAggregatesMin) {
		this.supportsAggregatesMin = supportsAggregatesMin;
	}

	private boolean supportsAggregatesMax=false;
	/** 
     * Support indicates connector can accept the MAX aggregate function 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aggregates Max", description="True, if this connector supports the MAX aggregate function", advanced=true)
    public boolean supportsAggregatesMax() {
    	return supportsAggregatesMax;
    }
    
	public void setSupportsAggregatesMax(boolean supportsAggregatesMax) {
		this.supportsAggregatesMax = supportsAggregatesMax;
	}

	private boolean supportsAggregatesCount=false;
	/** 
     * Support indicates connector can accept the COUNT aggregate function
     * @since 3.1 SP2 
     */
	@TranslatorProperty(display="Supports Aggregates Count", description="True, if this connector supports the COUNT aggregate function", advanced=true)
    public boolean supportsAggregatesCount() {
    	return supportsAggregatesCount;
    }
    
	public void setSupportsAggregatesCount(boolean supportsAggregatesCount) {
		this.supportsAggregatesCount = supportsAggregatesCount;
	}

	private boolean supportsAggregatesCountStar=false;
	/** 
     * Support indicates connector can accept the COUNT(*) aggregate function 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aggregates Count Star", description="True, if this connector supports the COUNT(*) aggregate function", advanced=true)
    public boolean supportsAggregatesCountStar() {
    	return supportsAggregatesCountStar;
    }
    
	public void setSupportsAggregatesCountStar(boolean supportsAggregatesCountStar) {
		this.supportsAggregatesCountStar = supportsAggregatesCountStar;
	}

	private boolean supportsAggregatesDistinct=false;
	/** 
     * Support indicates connector can accept DISTINCT within aggregate functions 
     * @since 3.1 SP2
     */
	@TranslatorProperty(display="Supports Aggregates Distinct", description="True, if this connector supports the DISTINCT within aggregate function", advanced=true)
    public boolean supportsAggregatesDistinct() {
    	return supportsAggregatesDistinct;
    }
    
	public void setSupportsAggregatesDistinct(boolean supportsAggregatesDistinct) {
		this.supportsAggregatesDistinct = supportsAggregatesDistinct;
	}

	private boolean supportsAggregatesEnhancedNumeric=false;
	/**
     * Support indicates connector can accept STDDEV_POP, STDDEV_VAR, VAR_POP, VAR_SAMP
     * @since 7.1
     */
	@TranslatorProperty(display="Supports Aggregates Enhanced Numeric", description="True, if this connector supports STDDEV_POP, STDDEV_VAR, VAR_POP, VAR_SAMP", advanced=true)
    public boolean supportsAggregatesEnhancedNumeric() {
    	return supportsAggregatesEnhancedNumeric;
    }

	public void setSupportsAggregatesEnhancedNumeric(boolean supportsAggregatesEnhancedNumeric) {
		this.supportsAggregatesEnhancedNumeric = supportsAggregatesEnhancedNumeric;
	}

	private boolean supportsScalarSubqueries=false;
	/** 
     * Support indicates connector can accept scalar subqueries in the SELECT, WHERE, and
     * HAVING clauses
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Scalar Subqueries", description="True, if this connector supports scalar subqueries in the SELECT, WHERE and HAVING clause", advanced=true)
    public boolean supportsScalarSubqueries() {
    	return supportsScalarSubqueries;
    }

	public void setSupportsScalarSubqueries(boolean supportsScalarSubqueries) {
		this.supportsScalarSubqueries = supportsScalarSubqueries;
	}

	private boolean supportsCorrelatedSubqueries=false;
	/** 
     * Support indicates connector can accept correlated subqueries wherever subqueries
     * are accepted 
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Correlated Subqueries", description="True, if this connector supports correlated subqueries wherever subqueries are accepted", advanced=true)
    public boolean supportsCorrelatedSubqueries() {
    	return supportsCorrelatedSubqueries;
    }
    
	public void setSupportsCorrelatedSubqueries(boolean supportsCorrelatedSubqueries) {
		this.supportsCorrelatedSubqueries = supportsCorrelatedSubqueries;
	}

	private boolean supportsSearchedCaseExpressions=false;
	/**
     * Support indicates connector can accept queries with searched CASE WHEN <criteria> ... END
     * @since 4.0
     */
	@TranslatorProperty(display="Supports Searched Case Expressions", description="True, if this connector supports queries with searched CASE WHEN <criteria> ... END", advanced=true)
    public boolean supportsSearchedCaseExpressions() {
    	return supportsSearchedCaseExpressions;
    }
   
	public void setSupportsSearchedCaseExpressions(boolean supportsSearchedCaseExpressions) {
		this.supportsSearchedCaseExpressions = supportsSearchedCaseExpressions;
	}

	private boolean supportsUnions=false;
	/**
     * Support indicates that the connector supports the UNION of two queries. 
     * @since 4.2
     */
	@TranslatorProperty(display="Supports Unions", description="True, if this connector supports the UNION of two queries", advanced=true)
    public boolean supportsUnions() {
    	return supportsUnions;
    }

	public void setSupportsUnions(boolean supportsUnions) {
		this.supportsUnions = supportsUnions;
	}

	private boolean supportsSetQueryOrderBy=false;
	/**
     * Support indicates that the connector supports an ORDER BY on a SetQuery. 
     * @since 5.6
     */
	@TranslatorProperty(display="Supports Set Query Order By", description="True, if this connector supports an ORDER BY on a SetQuery", advanced=true)
    public boolean supportsSetQueryOrderBy() {
    	return supportsSetQueryOrderBy;
    }
    
	public void setSupportsSetQueryOrderBy(boolean supportsSetQueryOrderBy) {
		this.supportsSetQueryOrderBy = supportsSetQueryOrderBy;
	}

	private boolean supportsIntersect=false;
	/**
     * Support indicates that the connector supports the INTERSECT of two queries. 
     * @since 5.6
     */
	@TranslatorProperty(display="Supports Intersect", description="True, if this connector supports the INTERSECT of two queries", advanced=true)
    public boolean supportsIntersect() {
    	return supportsIntersect;
    }

	public void setSupportsIntersect(boolean supportsIntersect) {
		this.supportsIntersect = supportsIntersect;
	}

	private boolean supportsExcept=false;
	/**
     * Support indicates that the connector supports the EXCEPT of two queries. 
     * @since 5.6
     */
	@TranslatorProperty(display="Supports Except", description="True, if this connector supports the EXCEPT of two queries", advanced=true)
    public boolean supportsExcept() {
    	return supportsExcept;
    }
        
	public void setSupportsExcept(boolean supportsExcept) {
		this.supportsExcept = supportsExcept;
	}

	/**
     * Get list of all supported function names.  Arithmetic functions have names like
     * &quot;+&quot;.  
     * @see SourceSystemFunctions for a listing of system pushdown functions.  Note that
     * not all system functions are listed as some functions will use a common name
     * such as CONCAT vs. the || operator, and other functions will be rewritten and
     * not pushed down, such as SPACE.
     * @since 3.1 SP3    
     */        
    public List<String> getSupportedFunctions() {
    	return null;
    }
    
    /**
     * Get a list of {@link FunctionMethod}s that will be contributed to the SYS schema.  
     * To avoid conflicts with system functions, the function name should contain a 
     * qualifier - typically &lt;translator name&gt;.&lt;function name&gt; 
     * @see ExecutionFactory#addPushDownFunction(String, String, FunctionParameter, FunctionParameter...)
     * @return
     */
    public List<FunctionMethod> getPushDownFunctions(){
    	return pushdownFunctions;
    }
    
    /**
     * Adds a pushdown function.
     * @param qualifier will be pre-pended to the name
     * @param name
     * @param returnType see {@link RUNTIME_NAMES} for type names
     * @param paramTypes see {@link RUNTIME_NAMES} for type names
     * @return the FunctionMethod created.
     */
    public FunctionMethod addPushDownFunction(String qualifier, String name, String returnType, String...paramTypes) {
    	FunctionMethod method = FunctionMethod.createFunctionMethod(qualifier + '.' + name, name, qualifier,
				returnType, paramTypes);
		method.setNameInSource(name);
    	pushdownFunctions.add(method);
    	return method;
    }
    
    /**
     * Get the integer value representing the number of values allowed in an IN criteria
     * in the WHERE clause of a query
     * @since 5.0
     */
	@TranslatorProperty(display="Max number of IN predicate entries", advanced=true)
    public int getMaxInCriteriaSize() {
        return maxInSize;
    }
	
	public void setMaxInCriteriaSize(int maxInSize) {
		this.maxInSize = maxInSize;
	}

	@TranslatorProperty(display="The time needed for running a new request (query), roughly in milliseconds", advanced=true)
	public float getNewRequestTime() {
		return newRequestTime;
	}

	public void setNewRequestTime(float newRequestTime) {
		this.newRequestTime = newRequestTime;
	}

	@TranslatorProperty(display="The time needed for reading data in a request (query), roughly in milliseconds", advanced=true)
	public float getReadTime() {
		return readTime;
	}

	public void setReadTime(float readTime) {
		this.readTime = readTime;
	}

	@TranslatorProperty(display="The time needed for comparing values in a request (query), roughly in milliseconds", advanced=true)
	public float getCompareTime() {
		return compareTime;
	}

	public void setCompareTime(float compareTime) {
		this.compareTime = compareTime;
	}

	/**
     * Get the integer value representing the max number of dependent IN predicates.
     * This may be used to split a single dependent value via OR, or multiple dependent values
     * via AND.
     */
	@TranslatorProperty(display="Max number of dependent IN predicates", advanced=true)
	public int getMaxDependentInPredicates() {
		return maxDependentInPredicates;
	}
	
	public void setMaxDependentInPredicates(int maxDependentInPredicates) {
		this.maxDependentInPredicates = maxDependentInPredicates;
	}

	private boolean supportsFunctionsInGroupBy=false;
    /**
     * <p>Support indicates that the connector supports non-column expressions in GROUP BY, such as:
     *  <code>SELECT dayofmonth(theDate), COUNT(*) FROM table GROUP BY dayofmonth(theDate)</code></p>
     * @since 5.0
     */
	@TranslatorProperty(display="Supports Functions in Group By", description="True, if this connector supports supports non-column expressions in GROUP BY", advanced=true)
    public boolean supportsFunctionsInGroupBy() {
    	return supportsFunctionsInGroupBy;
    }
    
	public void setSupportsFunctionsInGroupBy(boolean supportsFunctionsInGroupBy) {
		this.supportsFunctionsInGroupBy = supportsFunctionsInGroupBy;
	}

	private boolean supportsRowLimit=false;
	/**
     * Gets whether the connector can limit the number of rows returned by a query.
     * @since 5.0 SP1
     */
	@TranslatorProperty(display="Supports Row Limit", description="True, if this connector can limit the number of rows returned by a query", advanced=true)
    public boolean supportsRowLimit() {
    	return supportsRowLimit;
    }
    
	public void setSupportsRowLimit(boolean supportsRowLimit) {
		this.supportsRowLimit = supportsRowLimit;
	}

	private boolean supportsRowOffset=false;
	/**
     * Gets whether the connector supports a SQL clause (similar to the LIMIT with an offset) that can return
     * result sets that start in the middle of the resulting rows returned by a query
     * @since 5.0 SP1
     */
	@TranslatorProperty(display="Supports Row Offset", description="True, if this connector supports row offset", advanced=true)
    public boolean supportsRowOffset() {
    	return supportsRowOffset;
    }
    
	public void setSupportsRowOffset(boolean supportsRowOffset) {
		this.supportsRowOffset = supportsRowOffset;
	}

	/**
     * The number of groups supported in the from clause.  Added for a Sybase limitation. 
     * @since 5.6
     * @return the number of groups supported in the from clause, or -1 if there is no limit
     */
    public int getMaxFromGroups() {
    	return DEFAULT_MAX_FROM_GROUPS;
    }
    
    /**
     * Whether the source prefers to use ANSI style joins.
     * @since 6.0
     */
    public boolean useAnsiJoin() {
    	return false;
    }
    
    /**
     * Whether the source supports queries without criteria.
     * @since 6.0
     */
	@TranslatorProperty(display="Requries Criteria", description="True, if this connector requires criteria on source queries", advanced=true)
    public boolean requiresCriteria() {
    	return requiresCriteria;
    }
	
	public void setRequiresCriteria(boolean requiresCriteria) {
		this.requiresCriteria = requiresCriteria;
	}
    
    /**
     * Whether the source supports {@link BatchedUpdates}
     * @since 6.0
     */
    public boolean supportsBatchedUpdates() {
    	return false;
    }
    
    /**
     * Whether the source supports updates with multiple value sets
     * @since 6.0
     */
    public boolean supportsBulkUpdate() {
    	return false;
    }
    
    /**
     * Support indicates that the connector can accept INSERTs with
     * values specified by a {@link SetQuery} or {@link Select}
     * @since 6.1
     */
    public boolean supportsInsertWithQueryExpression() {
    	return false;
    }
    
    public static <T> T getInstance(Class<T> expectedType, String className, Collection<?> ctorObjs, Class<? extends T> defaultClass) throws TranslatorException {
    	try {
	    	if (className == null) {
	    		if (defaultClass == null) {
	    			 throw new TranslatorException(DataPlugin.Event.TEIID60004, DataPlugin.Util.gs(DataPlugin.Event.TEIID60004));
	    		}
	    		return expectedType.cast(defaultClass.newInstance());
	    	}
	    	return expectedType.cast(ReflectionHelper.create(className, ctorObjs, Thread.currentThread().getContextClassLoader()));
		} catch (TeiidException e) {
			 throw new TranslatorException(DataPlugin.Event.TEIID60005, e);
		} catch (IllegalAccessException e) {
			 throw new TranslatorException(DataPlugin.Event.TEIID60005, e);
		} catch(InstantiationException e) {
			 throw new TranslatorException(DataPlugin.Event.TEIID60005, e);
	// EXTENSION
	// ISSUE: DVCORE-2441
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.23
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-247, 2166, 2151, 2234, 2581, 2571, 2369, 1386, 2226, 2233, 2224, 2225, 2257
	// 	}    	
		}
	}
	
	public boolean supportsSelectWithoutFrom() {
		return false;
	// END EXTENSION
    } 
    
    /**
     * Implement to provide metadata to the metadata for use by the engine.  This is the 
     * primary method of creating metadata for dynamic VDBs.
     * @param metadataFactory
     * @param conn may be null if the source is not required 
     * @throws TranslatorException to indicate a recoverable error, otherwise a RuntimeException
     * @see #isSourceRequiredForMetadata()
     */
    public void getMetadata(MetadataFactory metadataFactory, C conn) throws TranslatorException {
	    MetadataProcessor mp = getMetadataProcessor();
	    if (mp != null) {
		    PropertiesUtils.setBeanProperties(mp, metadataFactory.getModelProperties(), "importer"); //$NON-NLS-1$
		    mp.process(metadataFactory, conn);
	    }
    }
    
    /**
     * Indicates if LOBs are usable after the execution is closed.
     * @return true if LOBs can be used after close
     * @since 7.2
     */
    public boolean areLobsUsableAfterClose() {
    	return false;
    }
    
	protected boolean supportsCommonTableExpressions=false;
    /**
     * @return true if the WITH clause is supported
     * @since 7.2
     */
	@TranslatorProperty(display="Supports Common Table Expressions", description="True, if this connector supports the WITH clause", advanced=true)
    public boolean supportsCommonTableExpressions() {
    	return supportsCommonTableExpressions;
    }

	public void setSupportsCommonTableExpressions(boolean supportsCommonTableExpressions) {
		this.supportsCommonTableExpressions = supportsCommonTableExpressions;
	}

	protected boolean supportsRecursiveCommonTableExpressions = false;
	/**
	 * @return true if a recursive WITH clause item is supported
	 * @since 8.9
	 */
	@TranslatorProperty(display="Supports Recursive Common Table Expressions", description="True, if this connector supports the WITH clause recursively", advanced=true)
	public boolean supportsRecursiveCommonTableExpressions() {
		return supportsRecursiveCommonTableExpressions;
	}

	public void setSupportsRecursiveCommonTableExpressions(boolean supportsRecursiveCommonTableExpressions) {
		this.supportsRecursiveCommonTableExpressions = supportsRecursiveCommonTableExpressions;
	}

	/**
	 * True if the only a single value is returned for the update count.
	 * This overrides the default expectation of a update count array
	 * for bulk/batch commands.  It is expected that every command
	 * is successful.
	 * @return
	 */
 	public boolean returnsSingleUpdateCount() {
		return false;
 	}

	private boolean supportsAdvancedOlapOperations=false;
    /**
     * @return true if the WITH clause can appear in subqueries
     * @since 8.12
     */
    public boolean supportsSubqueryCommonTableExpressions() {
    	return supportsCommonTableExpressions();
    }
    
    /**
     * @return true if Advanced OLAP operations are supported
     *  including the aggregate function filter clause.
     * @since 7.5
     */
	@TranslatorProperty(display="Supports Advanced Olap Operations", description="True, if this connector supports Advanced OLAP operations", advanced=true)
    public boolean supportsAdvancedOlapOperations() {
    	return supportsAdvancedOlapOperations;
    }
    
	public void setSupportsAdvancedOlapOperations(boolean supportsAdvancedOlapOperations) {
		this.supportsAdvancedOlapOperations = supportsAdvancedOlapOperations;
	}

	private boolean supportsElementaryOlapOperations=false;
	/**
     * @return true if Elementary OLAP operations are supported
     *  including window functions and inline window specifications that include 
     *  simple expressions in partitioning and ordering 
     * @since 7.5
     */
	@TranslatorProperty(display="Supports Elementary Olap Operations", description="True, if this connector supports Elementary OLAP operations", advanced=true)
    public boolean supportsElementaryOlapOperations() {
    	return supportsElementaryOlapOperations;
    }
    
	public void setSupportsElementaryOlapOperations(boolean supportsElementaryOlapOperations) {
		this.supportsElementaryOlapOperations = supportsElementaryOlapOperations;
	}

	/**
     * @return true if all aggregates can have window function order by clauses.
     * @since 7.5
     */
    public boolean supportsWindowOrderByWithAggregates() {
    	return supportsElementaryOlapOperations();
    }
    
    /**
     * @return true if distinct aggregates can be windowed function.
     * @since 7.6
     */
    public boolean supportsWindowDistinctAggregates() {
    	return supportsElementaryOlapOperations();
    }
    
	private boolean supportsArrayAgg=false;
    /**
     * @return true if array_agg is supported
     * @since 7.5
     */
	@TranslatorProperty(display="Supports Array Agg", description="True, if this connector supports array_agg", advanced=true)
    public boolean supportsArrayAgg() {
    	return supportsArrayAgg;
    }

	public void setSupportsArrayAgg(boolean supportsArrayAgg) {
		this.supportsArrayAgg = supportsArrayAgg;
	}

	private boolean supportsSimilarTo=false;
	/**
     * @return true if the SIMILAR TO predicate is supported
     * @since 7.5
     */
	@TranslatorProperty(display="Supports Similar To", description="True, if this connector supports SIMILAR TO predicate", advanced=true)
	public boolean supportsSimilarTo() {
		return supportsSimilarTo;
	}

	public void setSupportsSimilarTo(boolean supportsSimilarTo) {
		this.supportsSimilarTo = supportsSimilarTo;
	}

	private boolean supportsLikeRegex=false;
	/**
	 * @return true if the LIKE_REGEX predicate is supported
	 * @since 7.4
	 */
	@TranslatorProperty(display="Supports Like Regex", description="True, if this connector supports LIKE_REGEX predicate", advanced=true)
	public boolean supportsLikeRegex() {
		return supportsLikeRegex;
	}
	
	public void setSupportsLikeRegex(boolean supportsLikeRegex) {
		this.supportsLikeRegex = supportsLikeRegex;
	}

	/**
	 * Used for fine grained control of convert/cast pushdown.  The {@link #getSupportedFunctions()} should
	 * contain {@link SourceSystemFunctions#CONVERT}.  This method can then return false to indicate
	 * a lack of specific support.  The engine will does not care about an unnecessary conversion 
	 * where fromType == toType.
	 * 
	 * By default lob conversion is disabled.
	 * 
	 * @param fromType @see RUNTIME_CODES
	 * @param toType @see RUNTIME_CODES
	 * @return true if the given conversion is supported.
	 * @since 8.0
	 */
	public boolean supportsConvert(int fromType, int toType) {
		if (fromType == RUNTIME_CODES.OBJECT || (fromType == RUNTIME_CODES.CLOB && toType != RUNTIME_CODES.JSON) || fromType == RUNTIME_CODES.XML
				|| fromType == RUNTIME_CODES.BLOB || toType == RUNTIME_CODES.CLOB || toType == RUNTIME_CODES.XML
				|| toType == RUNTIME_CODES.BLOB || (fromType == RUNTIME_CODES.GEOGRAPHY && !supportsGeographyType())) {
			return false;
		}
		if ((fromType == RUNTIME_CODES.VARBINARY && toType != RUNTIME_CODES.BLOB)
				|| (fromType == RUNTIME_CODES.BLOB && toType != RUNTIME_CODES.VARBINARY))
			return false;
		return true;
	}
	
	/**
	 * @return true if only Literal comparisons (equality, ordered, like, etc.) are supported for non-join conditions.
	 * @since 8.0
	 */
	public boolean supportsOnlyLiteralComparison() {
		return false;
	}
	
	/**
	 * NOTE: The pushed independent tuples will not have been
	 * converted to a unique set and may contain duplicates.
	 * @return true if dependent join key pushdown is supported
	 * @since 8.0
	 */
	public boolean supportsDependentJoins() {
		return false;
	}

	/**
	 * @return true if full dependent join pushdown is supported
	 * @since 8.5
	 * @return
	 */
	public boolean supportsFullDependentJoins() {
		return false;
	}

	/**
	 * @since 8.4
	 * @return
	 */
	/*public int getDependentJoinMinimum() {
		return dependentJoinMinimum;
	}*/

	public enum Format {
		NUMBER,
		DATE
	}
	
	/**
	 * See also {@link #supportsFormatLiteral(String, Format)}
	 * @return true if only literal formats are supports.
	 */
	public boolean supportsOnlyFormatLiterals() {
		return false;
	}
	
	/**
	 * 
	 * @param literal
	 * @param format
	 * @return true if the given Java format string is supported
	 */
	public boolean supportsFormatLiteral(String literal, Format format) {
		return false;
	}
	
	/**
	 * Refines subquery support.
	 * @return true if subqueries are supported in the on clause.
	 */
	public boolean supportsSubqueryInOn() {
		return true;
	}

	/**
	 * Get the {@link CacheDirective} to control command caching.
	 * <p>Use {@link Scope#NONE} to indicate to the engine that no caching should be performed by the engine.</p>
	 * <p>If cache parameters on the {@link CacheDirective} will be changed by the {@link Execution}, then
	 * a new instance of a {@link CacheDirective} should be set each time.</p>
	 * @param command
	 * @param executionContext
	 * @param metadata
	 * @throws TranslatorException
	 */
	public CacheDirective getCacheDirective(Command command, ExecutionContext executionContext, RuntimeMetadata metadata) throws TranslatorException {
		return null;
	}
	
	/**
	 * When forkable the engine may use a separate thread to interact with returned {@link Execution}.
	 * @return true if {@link Execution}s can be called in separate threads from the processing thread
	 */
	public boolean isForkable() {
		return true;
	}
	
	/**
	 * @return True, if this translator's executions must complete in a single thread.
	 */
	@TranslatorProperty(display = "Thread Bound", description = "True, if this translator's executions must complete in a single thread.", advanced = true)
	public boolean isThreadBound() {
		return threadBound;
	}
	
	/**
	 * The engine uses array types for dependent joins and for array expression.
	 * @return true if an array type is supported.
	 */
	public boolean supportsArrayType() {
		return false;
	}

	/**
	 * @return true if array type expressions can be projected
	 */
	public boolean supportsSelectExpressionArrayType() {
		return supportsArrayType();
	}

	// EXTENSION
	// ISSUE: DV-84
	// FIXED BY: Roman Pedchenko
	// DATE: 2013.10.15,2013.11.23
	public boolean supportsFramingClause() {
    	return supportsElementaryOlapOperations();
	}
	public boolean supportsWindowWithoutOrderBy() {
    	return supportsElementaryOlapOperations();
	}
	// END EXTENSION
	// EXTENSION
	// ISSUE: DVCORE-2702
	// FIXED BY: Roman Pedchenko
	// DATE: 2015.02.26
	public boolean supportsWindowWithRange() {
    	return supportsElementaryOlapOperations();
	}
	// END EXTENSION
	// EXTENSION
	// ISSUE: DVCORE-980,DV-59
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.02.07
	public boolean supportsOrderByAlias() {
		return true;
	}
	public boolean supportsOrderByString() {
		return true;
	}
	// END EXTENSION
	// EXTENSION
	// ISSUE: DVCORE-2440
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.18
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177

	public boolean supportsLimitAfterCount() {
		return true;
	}

	/**
	 * True, if this translator supports execution of source specific commands unaltered through 'native' procedure.
	 * @return
	 */
	@Deprecated
	@TranslatorProperty(display="Supports Native Queries", description="True, if this translator supports execution of source specific commands unaltered through a 'native' procedure", advanced=true)
	public boolean supportsNativeQueries() {
		return this.supportsNativeQueries;
	}

	@Deprecated
	public void setSupportsNativeQueries(boolean state) {
		this.supportsNativeQueries = state;
	}
	
	/**
	 * Defines the name of the procedure that need to be treated as "native" query processing procedure. This metadata or signature
	 * of the procedure is defined automatically.
	 * @return
	 */
	@Deprecated
	@TranslatorProperty(display="Name of the native query", description="The name of the direct query procedure", advanced=true)
	public String getNativeQueryProcedureName() {
		return this.nativeProcedureName;
	}

	@Deprecated
	public void setNativeQueryProcedureName(String name) {
		this.nativeProcedureName = name;
	}	
	// END EXTENSION
	
	// EXTENSION
 	// ISSUE: DVCORE-2813
 	// FIXED BY: Salvatore Raunich
 	// DATE: 2015.06.05
	
	private boolean supportsCreateTableAsSelect = false;
	
	/**
	 * True, if this translator supports execution of CREATE TABLE ... AS SELECT ... statements
	 * @return
	 */
	@TranslatorProperty(display="Supports Create Table AS Select Queries", description="True, if this translator supports execution of CREATE TABLE ... AS SELECT ... statements", advanced=true)
	public boolean supportsCreateTableAsSelect() {
		return this.supportsCreateTableAsSelect;
	}
	
	public void setSupportsCreateTableAsSelect(boolean state) {
		this.supportsCreateTableAsSelect = state;
	}
	// END EXTENSION
	
	private boolean supportsMd5Function = true;
	
	/**
	 * True, if this translator supports a pushdown of the MD5 function
	 * @return
	 */
	@TranslatorProperty(display="Supports MD5 Function", description="True, if this translator supports a pushdown of the MD5 function", advanced=true)
	public boolean supportsMd5Function() {
		return this.supportsMd5Function;
	}
	
	public void setSupportsMd5Function(boolean state) {
		this.supportsMd5Function = state;
	}
	
	/**
     * Return true if the source has columns marked with the teiid_rel:partial that
     * can return more rows than specified by a filter if the column is also projected.
     * This most closely matches the semantics of ldap queries with multi-valued 
     * attributes marked as partial.
     * <br>When true, the following supports cannot also be true:
     * <ul>
     *   <li>supportsOuterJoins()
     *   <li>supportsFullOuterJoins()
     *   <li>supportsInlineViews()
     *   <li>supportsIntersect()
     *   <li>supportsExcept()
     *   <li>supportsSelectExpression()
     *   <li>supportsUnions()
     *   <li>supportsSelectDistinct()
     *   <li>supportsGroupBy()
     * </ul>
     * @return
     */
    public boolean supportsPartialFiltering() {
    	return false;
    }

	/**
	 * If dependent join predicates should use literals that are marked as bind eligible.
	 */
 	public boolean useBindingsForDependentJoin() {
		return true;
 	}

	private Boolean supportsStreamUpdate = null;

	@TranslatorProperty(display="Supports stream update", description="True, if this translator supports a stream update", advanced=true)
	public boolean supportsStreamUpdate() {
		if (supportsStreamUpdate == null)
			return supportsBulkUpdate();
		return supportsStreamUpdate;
	}

	public void setSupportsStreamUpdate(boolean supportsStreamUpdate) {
		this.supportsStreamUpdate = supportsStreamUpdate;
	}

	public enum ArrayEmulation {
		NONE, BINARY, STRING
	}

	public ArrayEmulation supportsArrayEmulation() {
		return ArrayEmulation.NONE;
	}

	Boolean supportsAggregatesLeadLagFirstLastValue = null;

	@TranslatorProperty(display="Supports lead(), lag(), firstValue(), and lastValue() aggregation symbols", description="True, if this translator supports lead(), lag(), firstValue(), and lastValue() aggregation symbols", advanced=true)
    public boolean supportsAggregatesLeadLagFirstLastValue() {
    	return supportsAggregatesLeadLagFirstLastValue == null ? supportsElementaryOlapOperations() : supportsAggregatesLeadLagFirstLastValue;
    }

	public void setSupportsAggregatesLeadLagFirstLastValue(boolean supportsAggregatesLeadLagFirstLastValue) {
		this.supportsAggregatesLeadLagFirstLastValue = supportsAggregatesLeadLagFirstLastValue;
	}

	public boolean supportsWindowLeadLagDefaultParameter() {
    	return supportsElementaryOlapOperations();
    }

    public int getOverrideFetchSize() {
        return -1;
    }

    public boolean getInsertInTransaction() {
        return false;
    }
    
    private boolean supportsTransactions = true;

	@TranslatorProperty(display="Supports transactions", description="True, if this translator supports transactions", advanced=true)
	public boolean supportsTransactions() {
		return supportsTransactions;
	}

	public void setSupportsTransactions(boolean supportsTransactions) {
		this.supportsTransactions = supportsTransactions;
	}

	public void setThreadBound(boolean threadBound) {
		this.threadBound = threadBound;
	}
	
	@TranslatorProperty(display = "Transaction Support", description = "The level of transaction support. Used by the engine to determine if a transaction is needed for autoCommit mode.", advanced = true)
	public TransactionSupport getTransactionSupport() {
		return transactionSupport;
	}

	public void setTransactionSupport(TransactionSupport transactionSupport) {
		this.transactionSupport = transactionSupport;
	}

	/**
	 * @return true if the source supports only timestamp add literals
	 */
	public boolean supportsOnlyTimestampAddLiteral() {
		return false;
	}

	public boolean getDefaultSupportMultipleOpenExecutions() {
		return true;
	}

	Boolean supportsMultipleOpenExecutions;

	/**
	 *
	 * @since 11.2
	 * @return true if multiple executions may be open against a single connection at a time
	 */
	@TranslatorProperty(display = "Supports multiple open executions", description = "True, if multiple executions may be open against a single connection at a time.", advanced = true)
 	public boolean supportsMultipleOpenExecutions() {
		return supportsMultipleOpenExecutions != null ? supportsMultipleOpenExecutions : getDefaultSupportMultipleOpenExecutions();
 	}

	public void setSupportsMultipleOpenExecutions(boolean supportsMultipleOpenExecutions) {
		this.supportsMultipleOpenExecutions = supportsMultipleOpenExecutions;
	}

	/**
	 * @return true if the source supports upsert
	 */
 	public boolean supportsUpsert() {
		return false;
}

	/**
	 * Method that will set importer.tableNamePattern property.
	 * @param modelName a model name (name of datasource)
	 * @param connectionName a connection name (name of connection and could be different from model name)
	 * @param sourceName a source name
	 * @param properties properties where importer.tableNamePattern is transferred
	 */
 	public void initModelProperties(String modelName, String connectionName, String sourceName, Properties properties){}

 	public boolean supportsRewriteSelectExpressionToConstant() {
 		return true;
    }

	private int maxStringSize = 4000;

	@TranslatorProperty(display = "Max string size", description = "Max string size.", advanced = true)
	public int getMaxStringSize() {
		return maxStringSize;
	}

	public void setMaxStringSize(int maxStringSize) {
		this.maxStringSize = maxStringSize;
	}

	public enum OversizeStringMode {
		CUT,
		CONVERT,
		FAIL;

		public boolean isCut() {
			return this == CUT || this == CONVERT;
		}
	}

	private OversizeStringMode oversizeStringProcessing = OversizeStringMode.CUT;
	@TranslatorProperty(display = "String to clob conversion mode", description = "String to clob conversion mode: one of CUT, CONVERT, FAIL", advanced = true)
	public OversizeStringMode getOversizeStringProcessing() {
		return oversizeStringProcessing;
	}

	public void setOversizeStringProcessing(OversizeStringMode oversizeStringProcessing) {
		this.oversizeStringProcessing = oversizeStringProcessing;
	}

	public String stringCutConvertFail(String orig) {
        return defaultStringCutConvertFail(orig);
    }

    protected String defaultStringCutConvertFail(String orig) {
		final int size = this.getMaxStringSize();
		if (orig.length() > size) {
            switch (this.getOversizeStringProcessing()) {
                case CONVERT:
                case CUT:
                    orig = orig.substring(0, size);
                    break;
                case FAIL:
					break;
            }
        }
        return orig;
    }

	protected boolean supportsLateralJoin;

	/**
	 *
	 * @return true if the source supports lateral join
	 */
	@TranslatorProperty(display="Supports lateral join", description="True, if this translator supports a lateral join", advanced=true)
	public boolean supportsLateralJoin() {
		return supportsLateralJoin;
	}

	public void setSupportsLateralJoin(boolean supportsLateralJoin) {
		this.supportsLateralJoin = supportsLateralJoin;
	}

	/**
	 *
	 * @return true if the source supports lateral join conditions
	 */
	public boolean supportsLateralJoinCondition() {
		return supportsLateralJoin();
	}

	/**
	 *
	 * @return
	 */
	public boolean supportsProcedureTable() {
		return false;
	}

	/**
	 * If the geography type is supported by the standard ST_ geospatial functions
	 * @since 11.2
	 * @return true if the translator supports the geography type
	 */
	public boolean supportsGeographyType() {
		return false;
	}

	/**
	 * If connection should close after an explicit request,
	 * instead of waiting for the query to finish
	 *
	 * @return true for LOB input
	 */
	public boolean explicitClose(Class<?> valueClass) {
		return DataTypeManager.isLOB(valueClass);
	}

	public String beforeRefreshDataSourceQuery() {
		return null;
	}

	public void checkAndRefreshOAuthAccessTokenIfExpired() {}
}
