📄 dialect.java
字号:
//$Id: Dialect.java 11303 2007-03-19 22:06:14Z steve.ebersole@jboss.com $package org.hibernate.dialect;import java.sql.CallableStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Types;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Properties;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.Hibernate;import org.hibernate.HibernateException;import org.hibernate.LockMode;import org.hibernate.MappingException;import org.hibernate.QueryException;import org.hibernate.cfg.Environment;import org.hibernate.dialect.function.CastFunction;import org.hibernate.dialect.function.SQLFunction;import org.hibernate.dialect.function.SQLFunctionTemplate;import org.hibernate.dialect.function.StandardSQLFunction;import org.hibernate.dialect.lock.LockingStrategy;import org.hibernate.dialect.lock.SelectLockingStrategy;import org.hibernate.engine.Mapping;import org.hibernate.exception.SQLExceptionConverter;import org.hibernate.exception.SQLStateConverter;import org.hibernate.exception.ViolatedConstraintNameExtracter;import org.hibernate.id.IdentityGenerator;import org.hibernate.id.SequenceGenerator;import org.hibernate.id.TableHiLoGenerator;import org.hibernate.mapping.Column;import org.hibernate.persister.entity.Lockable;import org.hibernate.sql.ANSICaseFragment;import org.hibernate.sql.ANSIJoinFragment;import org.hibernate.sql.CaseFragment;import org.hibernate.sql.JoinFragment;import org.hibernate.sql.ForUpdateFragment;import org.hibernate.type.Type;import org.hibernate.util.ReflectHelper;import org.hibernate.util.StringHelper;/** * Represents a dialect of SQL implemented by a particular RDBMS. * Subclasses implement Hibernate compatibility with different systems.<br> * <br> * Subclasses should provide a public default constructor that <tt>register()</tt> * a set of type mappings and default Hibernate properties.<br> * <br> * Subclasses should be immutable. * * @author Gavin King, David Channon */public abstract class Dialect { private static final Logger log = LoggerFactory.getLogger( Dialect.class ); public static final String DEFAULT_BATCH_SIZE = "15"; public static final String NO_BATCH = "0"; /** * Characters used for quoting SQL identifiers */ public static final String QUOTE = "`\"["; public static final String CLOSED_QUOTE = "`\"]"; // build the map of standard ANSI SQL aggregation functions ~~~~~~~~~~~~~~~ private static final Map STANDARD_AGGREGATE_FUNCTIONS = new HashMap(); static { STANDARD_AGGREGATE_FUNCTIONS.put( "count", new StandardSQLFunction("count") { public Type getReturnType(Type columnType, Mapping mapping) { return Hibernate.LONG; } } ); STANDARD_AGGREGATE_FUNCTIONS.put( "avg", new StandardSQLFunction("avg") { public Type getReturnType(Type columnType, Mapping mapping) throws QueryException { int[] sqlTypes; try { sqlTypes = columnType.sqlTypes( mapping ); } catch ( MappingException me ) { throw new QueryException( me ); } if ( sqlTypes.length != 1 ) throw new QueryException( "multi-column type in avg()" ); return Hibernate.DOUBLE; } } ); STANDARD_AGGREGATE_FUNCTIONS.put( "max", new StandardSQLFunction("max") ); STANDARD_AGGREGATE_FUNCTIONS.put( "min", new StandardSQLFunction("min") ); STANDARD_AGGREGATE_FUNCTIONS.put( "sum", new StandardSQLFunction("sum") { public Type getReturnType(Type columnType, Mapping mapping) { //pre H3.2 behavior: super.getReturnType(ct, m); int[] sqlTypes; try { sqlTypes = columnType.sqlTypes( mapping ); } catch ( MappingException me ) { throw new QueryException( me ); } if ( sqlTypes.length != 1 ) throw new QueryException( "multi-column type in sum()" ); int sqlType = sqlTypes[0]; // First allow the actual type to control the return value. (the actual underlying sqltype could actually be different) if ( columnType == Hibernate.BIG_INTEGER ) { return Hibernate.BIG_INTEGER; } else if ( columnType == Hibernate.BIG_DECIMAL ) { return Hibernate.BIG_DECIMAL; } else if ( columnType == Hibernate.LONG || columnType == Hibernate.SHORT || columnType == Hibernate.INTEGER) { return Hibernate.LONG; } else if ( columnType == Hibernate.FLOAT || columnType == Hibernate.DOUBLE) { return Hibernate.DOUBLE; } // finally use the sqltype if == on Hibernate types did not find a match. if ( sqlType == Types.NUMERIC ) { return columnType; //because numeric can be anything } else if ( sqlType == Types.FLOAT || sqlType == Types.DOUBLE || sqlType == Types.DECIMAL || sqlType == Types.REAL) { return Hibernate.DOUBLE; } else if ( sqlType == Types.BIGINT || sqlType == Types.INTEGER || sqlType == Types.SMALLINT || sqlType == Types.TINYINT ) { return Hibernate.LONG; } else { return columnType; } } }); } private final TypeNames typeNames = new TypeNames(); private final TypeNames hibernateTypeNames = new TypeNames(); private final Properties properties = new Properties(); private final Map sqlFunctions = new HashMap(); private final Set sqlKeywords = new HashSet(); // constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected Dialect() { log.info( "Using dialect: " + this ); sqlFunctions.putAll( STANDARD_AGGREGATE_FUNCTIONS ); // standard sql92 functions (can be overridden by subclasses) registerFunction( "substring", new SQLFunctionTemplate( Hibernate.STRING, "substring(?1, ?2, ?3)" ) ); registerFunction( "locate", new SQLFunctionTemplate( Hibernate.INTEGER, "locate(?1, ?2, ?3)" ) ); registerFunction( "trim", new SQLFunctionTemplate( Hibernate.STRING, "trim(?1 ?2 ?3 ?4)" ) ); registerFunction( "length", new StandardSQLFunction( "length", Hibernate.INTEGER ) ); registerFunction( "bit_length", new StandardSQLFunction( "bit_length", Hibernate.INTEGER ) ); registerFunction( "coalesce", new StandardSQLFunction( "coalesce" ) ); registerFunction( "nullif", new StandardSQLFunction( "nullif" ) ); registerFunction( "abs", new StandardSQLFunction( "abs" ) ); registerFunction( "mod", new StandardSQLFunction( "mod", Hibernate.INTEGER) ); registerFunction( "sqrt", new StandardSQLFunction( "sqrt", Hibernate.DOUBLE) ); registerFunction( "upper", new StandardSQLFunction("upper") ); registerFunction( "lower", new StandardSQLFunction("lower") ); registerFunction( "cast", new CastFunction() ); registerFunction( "extract", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(?1 ?2 ?3)") ); //map second/minute/hour/day/month/year to ANSI extract(), override on subclasses registerFunction( "second", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(second from ?1)") ); registerFunction( "minute", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(minute from ?1)") ); registerFunction( "hour", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(hour from ?1)") ); registerFunction( "day", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(day from ?1)") ); registerFunction( "month", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(month from ?1)") ); registerFunction( "year", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(year from ?1)") ); registerFunction( "str", new SQLFunctionTemplate(Hibernate.STRING, "cast(?1 as char)") ); // register hibernate types for default use in scalar sqlquery type auto detection registerHibernateType( Types.BIGINT, Hibernate.BIG_INTEGER.getName() ); registerHibernateType( Types.BINARY, Hibernate.BINARY.getName() ); registerHibernateType( Types.BIT, Hibernate.BOOLEAN.getName() ); registerHibernateType( Types.CHAR, Hibernate.CHARACTER.getName() ); registerHibernateType( Types.DATE, Hibernate.DATE.getName() ); registerHibernateType( Types.DOUBLE, Hibernate.DOUBLE.getName() ); registerHibernateType( Types.FLOAT, Hibernate.FLOAT.getName() ); registerHibernateType( Types.INTEGER, Hibernate.INTEGER.getName() ); registerHibernateType( Types.SMALLINT, Hibernate.SHORT.getName() ); registerHibernateType( Types.TINYINT, Hibernate.BYTE.getName() ); registerHibernateType( Types.TIME, Hibernate.TIME.getName() ); registerHibernateType( Types.TIMESTAMP, Hibernate.TIMESTAMP.getName() ); registerHibernateType( Types.VARCHAR, Hibernate.STRING.getName() ); registerHibernateType( Types.VARBINARY, Hibernate.BINARY.getName() ); registerHibernateType( Types.NUMERIC, Hibernate.BIG_DECIMAL.getName() ); registerHibernateType( Types.DECIMAL, Hibernate.BIG_DECIMAL.getName() ); registerHibernateType( Types.BLOB, Hibernate.BLOB.getName() ); registerHibernateType( Types.CLOB, Hibernate.CLOB.getName() ); registerHibernateType( Types.REAL, Hibernate.FLOAT.getName() ); } /** * Get an instance of the dialect specified by the current <tt>System</tt> properties. * * @return The specified Dialect * @throws HibernateException If no dialect was specified, or if it could not be instantiated. */ public static Dialect getDialect() throws HibernateException { String dialectName = Environment.getProperties().getProperty( Environment.DIALECT ); return instantiateDialect( dialectName ); } /** * Get an instance of the dialect specified by the given properties or by * the current <tt>System</tt> properties. * * @param props The properties to use for finding the dialect class to use. * @return The specified Dialect * @throws HibernateException If no dialect was specified, or if it could not be instantiated. */ public static Dialect getDialect(Properties props) throws HibernateException { String dialectName = props.getProperty( Environment.DIALECT ); if ( dialectName == null ) { return getDialect(); } return instantiateDialect( dialectName ); } private static Dialect instantiateDialect(String dialectName) throws HibernateException { if ( dialectName == null ) { throw new HibernateException( "The dialect was not set. Set the property hibernate.dialect." ); } try { return ( Dialect ) ReflectHelper.classForName( dialectName ).newInstance(); } catch ( ClassNotFoundException cnfe ) { throw new HibernateException( "Dialect class not found: " + dialectName ); } catch ( Exception e ) { throw new HibernateException( "Could not instantiate dialect class", e ); } } /** * Retrieve a set of default Hibernate properties for this database. * * @return a set of Hibernate properties */ public final Properties getDefaultProperties() { return properties; } public String toString() { return getClass().getName(); } // database type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Get the name of the database type associated with the given * {@link java.sql.Types} typecode. * * @param code The {@link java.sql.Types} typecode * @return the database type name * @throws HibernateException If no mapping was specified for that type. */ public String getTypeName(int code) throws HibernateException { String result = typeNames.get( code ); if ( result == null ) { throw new HibernateException( "No default type mapping for (java.sql.Types) " + code ); } return result; } /** * Get the name of the database type associated with the given * {@link java.sql.Types} typecode with the given storage specification * parameters. * * @param code The {@link java.sql.Types} typecode * @param length The datatype length * @param precision The datatype precision * @param scale The datatype scale * @return the database type name * @throws HibernateException If no mapping was specified for that type. */ public String getTypeName(int code, int length, int precision, int scale) throws HibernateException { String result = typeNames.get( code, length, precision, scale ); if ( result == null ) { throw new HibernateException( "No type mapping for java.sql.Types code: " + code + ", length: " + length ); } return result; } /** * Get the name of the database type appropriate for casting operations * (via the CAST() SQL function) for the given {@link java.sql.Types} typecode. * * @param code The {@link java.sql.Types} typecode * @return The database type name */ public String getCastTypeName(int code) { return getTypeName( code, Column.DEFAULT_LENGTH, Column.DEFAULT_PRECISION, Column.DEFAULT_SCALE ); } /** * Subclasses register a type name for the given type code and maximum * column length. <tt>$l</tt> in the type name with be replaced by the * column length (if appropriate). * * @param code The {@link java.sql.Types} typecode * @param capacity The maximum length of database type * @param name The database type name */ protected void registerColumnType(int code, int capacity, String name) { typeNames.put( code, capacity, name ); } /** * Subclasses register a type name for the given type code. <tt>$l</tt> in * the type name with be replaced by the column length (if appropriate). * * @param code The {@link java.sql.Types} typecode * @param name The database type name */ protected void registerColumnType(int code, String name) { typeNames.put( code, name ); } // hibernate type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Get the name of the Hibernate {@link org.hibernate.type.Type} associated with th given * {@link java.sql.Types} typecode. * * @param code The {@link java.sql.Types} typecode * @return The Hibernate {@link org.hibernate.type.Type} name. * @throws HibernateException If no mapping was specified for that type. */ public String getHibernateTypeName(int code) throws HibernateException { String result = hibernateTypeNames.get( code ); if ( result == null ) { throw new HibernateException( "No Hibernate type mapping for java.sql.Types code: " + code ); } return result; } /** * Get the name of the Hibernate {@link org.hibernate.type.Type} associated * with the given {@link java.sql.Types} typecode with the given storage * specification parameters. * * @param code The {@link java.sql.Types} typecode * @param length The datatype length * @param precision The datatype precision * @param scale The datatype scale * @return The Hibernate {@link org.hibernate.type.Type} name. * @throws HibernateException If no mapping was specified for that type. */ public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException { String result = hibernateTypeNames.get( code, length, precision, scale ); if ( result == null ) { throw new HibernateException( "No Hibernate type mapping for java.sql.Types code: " + code + ", length: " + length ); } return result; } /** * Registers a Hibernate {@link org.hibernate.type.Type} name for the given * {@link java.sql.Types} type code and maximum column length. * * @param code The {@link java.sql.Types} typecode * @param capacity The maximum length of database type * @param name The Hibernate {@link org.hibernate.type.Type} name */ protected void registerHibernateType(int code, int capacity, String name) { hibernateTypeNames.put( code, capacity, name); } /** * Registers a Hibernate {@link org.hibernate.type.Type} name for the given * {@link java.sql.Types} type code. * * @param code The {@link java.sql.Types} typecode * @param name The Hibernate {@link org.hibernate.type.Type} name */ protected void registerHibernateType(int code, String name) { hibernateTypeNames.put( code, name); } // function support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected void registerFunction(String name, SQLFunction function) { sqlFunctions.put( name, function ); } /** * Retrieves a map of the dialect's registered fucntions * (functionName => {@link org.hibernate.dialect.function.SQLFunction}). * * @return The map of registered functions. */ public final Map getFunctions() { return sqlFunctions; } // keyword support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected void registerKeyword(String word) { sqlKeywords.add(word); } public Set getKeywords() { return sqlKeywords; } // native identifier generatiion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * The class (which implements {@link org.hibernate.id.IdentifierGenerator}) * which acts as this dialects native generation strategy. * <p/> * Comes into play whenever the user specifies the native generator. * * @return The native generator class.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -