Big merge of my branch with new Hibernate 6 codebase

Lots of new functionality here related to HQL functions, SQL
dialects, and date/time handling.
This commit is contained in:
gavinking 2020-01-24 01:01:35 +01:00 committed by Steve Ebersole
parent 89ebcfbc32
commit 9565d499af
285 changed files with 20521 additions and 14877 deletions

View File

@ -26,7 +26,6 @@ import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Vlad Mihalcea

View File

@ -16,6 +16,8 @@ WS : WS_CHAR+ -> skip;
fragment
WS_CHAR : [ \f\t\r\n];
COMMENT : '/*' (~'*' | '*' ~'/' )* '*/' -> skip;
fragment
DIGIT : [0-9];
@ -53,11 +55,32 @@ FLOATING_POINT_NUMBER
| DIGIT+
;
INTEGER_LITERAL : INTEGER_NUMBER;
LONG_LITERAL : INTEGER_NUMBER LONG_SUFFIX;
FLOAT_LITERAL : FLOATING_POINT_NUMBER FLOAT_SUFFIX?;
DOUBLE_LITERAL : FLOATING_POINT_NUMBER DOUBLE_SUFFIX;
BIG_INTEGER_LITERAL : INTEGER_NUMBER BIG_INTEGER_SUFFIX;
BIG_DECIMAL_LITERAL : FLOATING_POINT_NUMBER BIG_DECIMAL_SUFFIX;
HEX_LITERAL : '0' [xX] HEX_DIGIT+ LONG_SUFFIX?;
OCTAL_LITERAL : '0' ('0'..'7')+ ('l'|'L')?;
fragment SINGLE_QUOTE : '\'';
fragment DOUBLE_QUOTE : '"';
STRING_LITERAL
: DOUBLE_QUOTE ( ~[\\"] | ESCAPE_SEQUENCE | DOUBLE_QUOTE DOUBLE_QUOTE )* DOUBLE_QUOTE
{ setText(getText().substring(1, getText().length()-1).replace("\"\"", "\"")); }
| SINGLE_QUOTE ( ~[\\'] | ESCAPE_SEQUENCE | SINGLE_QUOTE SINGLE_QUOTE )* SINGLE_QUOTE
{ setText(getText().substring(1, getText().length()-1).replace("''", "'")); }
;
fragment BACKSLASH : '\\';
fragment
@ -72,35 +95,11 @@ UNICODE_ESCAPE
: 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
;
INTEGER_LITERAL : INTEGER_NUMBER ;
LONG_LITERAL : INTEGER_NUMBER LONG_SUFFIX;
FLOAT_LITERAL : FLOATING_POINT_NUMBER FLOAT_SUFFIX?;
DOUBLE_LITERAL : FLOATING_POINT_NUMBER DOUBLE_SUFFIX;
BIG_INTEGER_LITERAL : INTEGER_NUMBER BIG_INTEGER_SUFFIX;
BIG_DECIMAL_LITERAL : FLOATING_POINT_NUMBER BIG_DECIMAL_SUFFIX;
HEX_LITERAL : '0' [xX] HEX_DIGIT+ LONG_SUFFIX?;
OCTAL_LITERAL : '0' ('0'..'7')+ ('l'|'L')? ;
STRING_LITERAL
: DOUBLE_QUOTE ( ~[\\"] | ESCAPE_SEQUENCE | DOUBLE_QUOTE DOUBLE_QUOTE )* DOUBLE_QUOTE
{ setText(getText().substring(1, getText().length()-1).replace("\"\"", "\"")); }
| SINGLE_QUOTE ( ~[\\'] | ESCAPE_SEQUENCE | SINGLE_QUOTE SINGLE_QUOTE )* SINGLE_QUOTE
{ setText(getText().substring(1, getText().length()-1).replace("''", "'")); }
;
fragment
OCTAL_ESCAPE
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
| '\\' ('0'..'7') ('0'..'7')
| '\\' ('0'..'7')
: BACKSLASH ('0'..'3') ('0'..'7') ('0'..'7')
| BACKSLASH ('0'..'7') ('0'..'7')
| BACKSLASH ('0'..'7')
;
@ -164,13 +163,14 @@ COLLATE : [cC] [oO] [lL] [lL] [aA] [tT] [eE];
CONCAT : [cC] [oO] [nN] [cC] [aA] [tT];
COUNT : [cC] [oO] [uU] [nN] [tT];
CROSS : [cC] [rR] [oO] [sS] [sS];
CURRENT : [cC] [uU] [rR] [rR] [eE] [nN] [tT];
CURRENT_DATE : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [dD] [aA] [tT] [eE];
CURRENT_DATETIME : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
CURRENT_INSTANT : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [iI] [nN] [sS] [tT] [aA] [nN] [tT];
CURRENT_INSTANT : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [iI] [nN] [sS] [tT] [aA] [nN] [tT]; //deprecated legacy
CURRENT_TIME : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE];
CURRENT_TIMESTAMP : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE] [sS] [tT] [aA] [mM] [pP];
DAY : [dD] [aA] [yY];
DATE : [dD] [aA] [tT] [eE];
DATETIME : [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
DAY : [dD] [aA] [yY];
DELETE : [dD] [eE] [lL] [eE] [tT] [eE];
DESC : [dD] [eE] [sS] [cC];
DISTINCT : [dD] [iI] [sS] [tT] [iI] [nN] [cC] [tT];
@ -180,6 +180,7 @@ EMPTY : [eE] [mM] [pP] [tT] [yY];
END : [eE] [nN] [dD];
ENTRY : [eE] [nN] [tT] [rR] [yY];
ESCAPE : [eE] [sS] [cC] [aA] [pP] [eE];
EVERY : [eE] [vV] [eE] [rR] [yY];
EXISTS : [eE] [xX] [iI] [sS] [tT] [sS];
EXP : [eE] [xX] [pP];
EXTRACT : [eE] [xX] [tT] [rR] [aA] [cC] [tT];
@ -199,6 +200,7 @@ IN : [iI] [nN];
INDEX : [iI] [nN] [dD] [eE] [xX];
INNER : [iI] [nN] [nN] [eE] [rR];
INSERT : [iI] [nN] [sS] [eE] [rR] [tT];
INSTANT : [iI] [nN] [sS] [tT] [aA] [nN] [tT];
INTO : [iI] [nN] [tT] [oO];
IS : [iI] [sS];
JOIN : [jJ] [oO] [iI] [nN];
@ -211,10 +213,11 @@ LIKE : [lL] [iI] [kK] [eE];
LIMIT : [lL] [iI] [mM] [iI] [tT];
LIST : [lL] [iI] [sS] [tT];
LN : [lL] [nN];
LOCATE : [lL] [oO] [cC] [aA] [tT] [eE];
LOCAL : [lL] [oO] [cC] [aA] [lL];
LOCAL_DATE : [lL] [oO] [cC] [aA] [lL] '_' [dD] [aA] [tT] [eE];
LOCAL_DATETIME : [lL] [oO] [cC] [aA] [lL] '_' [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
LOCAL_TIME : [lL] [oO] [cC] [aA] [lL] '_' [tT] [iI] [mM] [eE];
LOCATE : [lL] [oO] [cC] [aA] [tT] [eE];
LOWER : [lL] [oO] [wW] [eE] [rR];
MAP : [mM] [aA] [pP];
MAX : [mM] [aA] [xX];
@ -229,17 +232,21 @@ MININDEX : [mM] [iI] [nN] [iI] [nN] [dD] [eE] [xX];
MINUTE : [mM] [iI] [nN] [uU] [tT] [eE];
MOD : [mM] [oO] [dD];
MONTH : [mM] [oO] [nN] [tT] [hH];
NEW : [nN] [eE] [wW];
NANOSECOND : [nN] [aA] [nN] [oO] [sS] [eE] [cC] [oO] [nN] [dD];
NEW : [nN] [eE] [wW];
NOT : [nN] [oO] [tT];
NULLIF : [nN] [uU] [lL] [lL] [iI] [fF];
OBJECT : [oO] [bB] [jJ] [eE] [cC] [tT];
OF : [oO] [fF];
OFFSET : [oO] [fF] [fF] [sS] [eE] [tT];
OFFSET_DATETIME : [oO] [fF] [fF] [sS] [eE] [tT] '_' [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
ON : [oO] [nN];
OR : [oO] [rR];
ORDER : [oO] [rR] [dD] [eE] [rR];
OUTER : [oO] [uU] [tT] [eE] [rR];
OVERLAY : [oO] [vV] [eE] [rR] [lL] [aA] [yY];
PAD : [pP] [aA] [dD];
PLACING : [pP] [lL] [aA] [cC] [iI] [nN] [gG];
POSITION : [pP] [oO] [sS] [iI] [tT] [iI] [oO] [nN];
POWER : [pP] [oO] [wW] [eE] [rR];
QUARTER : [qQ] [uU] [aA] [rR] [tT] [eE] [rR];
@ -251,12 +258,14 @@ SELECT : [sS] [eE] [lL] [eE] [cC] [tT];
SET : [sS] [eE] [tT];
SIGN : [sS] [iI] [gG] [nN];
SIZE : [sS] [iI] [zZ] [eE];
SOME : [sS] [oO] [mM] [eE];
SQRT : [sS] [qQ] [rR] [tT];
STR : [sS] [tT] [rR];
SUBSTRING : [sS] [uU] [bB] [sS] [tT] [rR] [iI] [nN] [gG];
SUM : [sS] [uU] [mM];
THEN : [tT] [hH] [eE] [nN];
TIME : [tT] [iI] [mM] [eE];
TIMESTAMP : [tT] [iI] [mM] [eE] [sS] [tT] [aA] [mM] [pP];
TIMEZONE_HOUR : [tT] [iI] [mM] [eE] [zZ] [oO] [nN] [eE] '_' [hH] [oO] [uU] [rR];
TIMEZONE_MINUTE : [tT] [iI] [mM] [eE] [zZ] [oO] [nN] [eE] '_' [mM] [iI] [nN] [uU] [tT] [eE];
TRAILING : [tT] [rR] [aA] [iI] [lL] [iI] [nN] [gG];
@ -275,7 +284,7 @@ YEAR : [yY] [eE] [aA] [rR];
ACOS : [aA] [cC] [oO] [sH];
ASIN : [aA] [sS] [iI] [nN];
ATAN : [aA] [tT] [aA] [nN];
ATAN2 : [aA] [tT] [aA] [nN] '2';
ATAN2 : [aA] [tT] [aA] [nN] [2];
COS : [cC] [oO] [sH];
SIN : [sS] [iI] [nN];
TAN : [tT] [aA] [nN];
@ -285,11 +294,18 @@ TRUE : [tT] [rR] [uU] [eE];
FALSE : [fF] [aA] [lL] [sS] [eE];
NULL : [nN] [uU] [lL] [lL];
fragment
LETTER : [a-zA-Z\u0080-\ufffe_$];
// Identifiers
IDENTIFIER
: ('a'..'z'|'A'..'Z'|'_'|'$'|'\u0080'..'\ufffe')('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|'\u0080'..'\ufffe')*
: LETTER (LETTER | DIGIT)*
;
fragment
BACKTICK : '`';
QUOTED_IDENTIFIER
: '`' ( ESCAPE_SEQUENCE | ~('\\'|'`') )* '`'
: BACKTICK ( ~([\\`]) | ESCAPE_SEQUENCE )* BACKTICK
;

View File

@ -73,7 +73,8 @@ targetFieldsSpec
// QUERY SPEC - general structure of root sqm or sub sqm
querySpec
: selectClause? fromClause whereClause? ( groupByClause havingClause? )? orderByClause? limitClause? offsetClause?
: selectClause fromClause? whereClause? ( groupByClause havingClause? )? orderByClause? limitClause? offsetClause?
| fromClause whereClause? ( groupByClause havingClause? )? selectClause? orderByClause? limitClause? offsetClause?
;
@ -363,22 +364,27 @@ whereClause
;
predicate
//highest to lowest precedence
: LEFT_PAREN predicate RIGHT_PAREN # GroupedPredicate
| predicate OR predicate # OrPredicate
| predicate AND predicate # AndPredicate
| NOT predicate # NegatedPredicate
| expression IS (NOT)? NULL # IsNullPredicate
| expression IS (NOT)? EMPTY # IsEmptyPredicate
| expression EQUAL expression # EqualityPredicate
| expression NOT_EQUAL expression # InequalityPredicate
| expression GREATER expression # GreaterThanPredicate
| expression GREATER_EQUAL expression # GreaterThanOrEqualPredicate
| expression LESS expression # LessThanPredicate
| expression LESS_EQUAL expression # LessThanOrEqualPredicate
| expression (NOT)? IN inList # InPredicate
| expression (NOT)? BETWEEN expression AND expression # BetweenPredicate
| expression (NOT)? LIKE expression (likeEscape)? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate
| MEMBER OF path # MemberOfPredicate
| NOT predicate # NegatedPredicate
| predicate AND predicate # AndPredicate
| predicate OR predicate # OrPredicate
;
comparisonOperator
: EQUAL
| NOT_EQUAL
| GREATER
| GREATER_EQUAL
| LESS
| LESS_EQUAL
;
inList
@ -396,29 +402,40 @@ likeEscape
// Expression
expression
: expression DOUBLE_PIPE expression # ConcatenationExpression
| expression PLUS expression # AdditionExpression
| expression MINUS expression # SubtractionExpression
| expression ASTERISK expression # MultiplicationExpression
| expression SLASH expression # DivisionExpression
| expression PERCENT expression # ModuloExpression
// todo (6.0) : should these unary plus/minus rules only apply to literals?
// if so, move the MINUS / PLUS recognition to the `literal` rule
// specificcally for numeric literals
| MINUS expression # UnaryMinusExpression
| PLUS expression # UnaryPlusExpression
| caseStatement # CaseExpression
| coalesce # CoalesceExpression
| nullIf # NullIfExpression
| literal # LiteralExpression
| parameter # ParameterExpression
| entityTypeReference # EntityTypeExpression
| entityIdReference # EntityIdExpression
| entityVersionReference # EntityVersionExpression
| entityNaturalIdReference # EntityNaturalIdExpression
| path # PathExpression
| function # FunctionExpression
| LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression
//highest to lowest precedence
: LEFT_PAREN expression RIGHT_PAREN # GroupedExpression
| LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression
| caseList # CaseExpression
| literal # LiteralExpression
| parameter # ParameterExpression
| entityTypeReference # EntityTypeExpression
| entityIdReference # EntityIdExpression
| entityVersionReference # EntityVersionExpression
| entityNaturalIdReference # EntityNaturalIdExpression
| path # PathExpression
| function # FunctionExpression
| signOperator expression # UnaryExpression
| expression datetimeField # ToDurationExpression
| expression BY datetimeField # FromDurationExpression
| expression multiplicativeOperator expression # MultiplicationExpression
| expression additiveOperator expression # AdditionExpression
| expression DOUBLE_PIPE expression # ConcatenationExpression
;
multiplicativeOperator
: SLASH
| PERCENT
| ASTERISK
;
additiveOperator
: PLUS
| MINUS
;
signOperator
: PLUS
| MINUS
;
entityTypeReference
@ -437,12 +454,12 @@ entityNaturalIdReference
: NATURALID LEFT_PAREN path RIGHT_PAREN pathContinuation?
;
caseStatement
: simpleCaseStatement
| searchedCaseStatement
caseList
: simpleCaseList
| searchedCaseList
;
simpleCaseStatement
simpleCaseList
: CASE expression (simpleCaseWhen)+ (caseOtherwise)? END
;
@ -454,7 +471,7 @@ caseOtherwise
: ELSE expression
;
searchedCaseStatement
searchedCaseList
: CASE (searchedCaseWhen)+ (caseOtherwise)? END
;
@ -470,12 +487,15 @@ leastFunction
: LEAST LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
;
coalesce
coalesceFunction
: COALESCE LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
| IFNULL LEFT_PAREN expression COMMA expression RIGHT_PAREN
;
nullIf
ifnullFunction
: IFNULL LEFT_PAREN expression COMMA expression RIGHT_PAREN
;
nullifFunction
: NULLIF LEFT_PAREN expression COMMA expression RIGHT_PAREN
;
@ -507,14 +527,17 @@ temporalLiteral
dateTimeLiteral
: LEFT_BRACE dateTime RIGHT_BRACE
| DATETIME dateTime
;
dateLiteral
: LEFT_BRACE date RIGHT_BRACE
| DATE date
;
timeLiteral
: LEFT_BRACE time RIGHT_BRACE
| TIME time
;
dateTime
@ -596,7 +619,7 @@ nonStandardFunctionName
;
nonStandardFunctionArguments
: expression (COMMA expression)*
: (datetimeField COMMA)? expression (COMMA expression)*
;
jpaCollectionFunction
@ -617,6 +640,8 @@ aggregateFunction
| minFunction
| maxFunction
| countFunction
| everyFunction
| anyFunction
;
avgFunction
@ -627,6 +652,14 @@ sumFunction
: SUM LEFT_PAREN DISTINCT? expression RIGHT_PAREN
;
everyFunction
: (EVERY|ALL) LEFT_PAREN DISTINCT? predicate RIGHT_PAREN
;
anyFunction
: (ANY|SOME) LEFT_PAREN DISTINCT? predicate RIGHT_PAREN
;
minFunction
: MIN LEFT_PAREN DISTINCT? expression RIGHT_PAREN
;
@ -642,11 +675,18 @@ countFunction
standardFunction
: castFunction
| extractFunction
| coalesceFunction
| nullifFunction
| ifnullFunction
| formatFunction
| concatFunction
| substringFunction
| replaceFunction
| leftFunction
| rightFunction
| overlayFunction
| replaceFunction
| trimFunction
| padFunction
| upperFunction
| lowerFunction
| locateFunction
@ -670,10 +710,11 @@ standardFunction
| currentDateFunction
| currentTimeFunction
| currentTimestampFunction
| currentInstantFunction
| instantFunction
| localDateFunction
| localDateTimeFunction
| localTimeFunction
| localTimeFunction
| localDateTimeFunction
| offsetDateTimeFunction
;
@ -682,20 +723,20 @@ castFunction
;
castTarget
// todo (6.0) : should allow either
// - named cast (IDENTIFIER)
// - JavaTypeDescriptorRegistry (imported) key
// - java.sql.Types field NAME (alias for its value as a coded cast)
// - "pass through"
// - coded cast (INTEGER_LITERAL)
// - SqlTypeDescriptorRegistry key
: identifier
: identifier (LEFT_PAREN INTEGER_LITERAL (COMMA INTEGER_LITERAL)? RIGHT_PAREN)?
;
concatFunction
: CONCAT LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
;
leftFunction
: LEFT LEFT_PAREN expression COMMA expression RIGHT_PAREN
;
rightFunction
: RIGHT LEFT_PAREN expression COMMA expression RIGHT_PAREN
;
substringFunction
: SUBSTRING LEFT_PAREN expression COMMA substringFunctionStartArgument (COMMA substringFunctionLengthArgument)? RIGHT_PAREN
| SUBSTRING LEFT_PAREN expression FROM substringFunctionStartArgument (FOR substringFunctionLengthArgument)? RIGHT_PAREN
@ -723,6 +764,23 @@ trimCharacter
: STRING_LITERAL
;
padFunction
: PAD LEFT_PAREN expression WITH padLength padSpecification padCharacter? RIGHT_PAREN
;
padSpecification
: LEADING
| TRAILING
;
padCharacter
: STRING_LITERAL
;
padLength
: expression
;
upperFunction
: UPPER LEFT_PAREN expression RIGHT_PAREN
;
@ -747,6 +805,26 @@ locateFunctionStartArgument
: expression
;
overlayFunction
: OVERLAY LEFT_PAREN overlayFunctionStringArgument PLACING overlayFunctionReplacementArgument FROM overlayFunctionStartArgument (FOR overlayFunctionLengthArgument)? RIGHT_PAREN
;
overlayFunctionStringArgument
: expression
;
overlayFunctionReplacementArgument
: expression
;
overlayFunctionStartArgument
: expression
;
overlayFunctionLengthArgument
: expression
;
replaceFunction
: REPLACE LEFT_PAREN replaceFunctionStringArgument COMMA replaceFunctionPatternArgument COMMA replaceFunctionReplacementArgument RIGHT_PAREN
;
@ -764,7 +842,7 @@ replaceFunctionReplacementArgument
;
lengthFunction
: LENGTH LEFT_PAREN expression RIGHT_PAREN
: LENGTH LEFT_PAREN expression RIGHT_PAREN
;
absFunction
@ -838,7 +916,7 @@ trigFunctionName
| ACOS
| ASIN
| ATAN
| ATAN2
//ATAN2 is different!
;
atan2Function
@ -851,30 +929,42 @@ strFunction
currentDateFunction
: CURRENT_DATE (LEFT_PAREN RIGHT_PAREN)?
| CURRENT DATE
;
currentTimeFunction
: CURRENT_TIME (LEFT_PAREN RIGHT_PAREN)?
| CURRENT TIME
;
currentTimestampFunction
: CURRENT_TIMESTAMP (LEFT_PAREN RIGHT_PAREN)?
| CURRENT TIMESTAMP
;
currentInstantFunction
: CURRENT_INSTANT (LEFT_PAREN RIGHT_PAREN)?
instantFunction
: CURRENT_INSTANT (LEFT_PAREN RIGHT_PAREN)? //deprecated legacy syntax
| INSTANT
;
localDateTimeFunction
: LOCAL_DATETIME (LEFT_PAREN RIGHT_PAREN)?
| LOCAL DATETIME
;
offsetDateTimeFunction
: OFFSET_DATETIME (LEFT_PAREN RIGHT_PAREN)?
| OFFSET DATETIME
;
localDateFunction
: LOCAL_DATE (LEFT_PAREN RIGHT_PAREN)?
| LOCAL DATE
;
localTimeFunction
: LOCAL_TIME (LEFT_PAREN RIGHT_PAREN)?
| LOCAL TIME
;
formatFunction
@ -923,6 +1013,7 @@ weekField
timeZoneField
: OFFSET (HOUR | MINUTE)?
| TIMEZONE_HOUR | TIMEZONE_MINUTE
;
dateOrTimeField
@ -955,12 +1046,12 @@ positionFunctionStringArgument
identifier
: IDENTIFIER
| (ABS
| AS
| ALL
| AND
| ANY
| AS
| ASC
| ATAN2
| AVG
| BY
| BETWEEN
@ -981,6 +1072,7 @@ identifier
| CURRENT_TIMESTAMP
| DAY
| DATE
| DAY
| DELETE
| DESC
| DISTINCT
@ -989,6 +1081,7 @@ identifier
| EMPTY
| END
| ENTRY
| EVERY
| ESCAPE
| EXISTS
| EXP
@ -997,6 +1090,7 @@ identifier
| FLOOR
| FROM
| FOR
| FORMAT
| FULL
| FUNCTION
| GREATEST
@ -1008,6 +1102,7 @@ identifier
| INDEX
| INNER
| INSERT
| INSTANT
| INTO
| IS
| JOIN
@ -1033,6 +1128,7 @@ identifier
| MINELEMENT
| MININDEX
| MINUTE
| MEMBER
| MOD
| MONTH
| NANOSECOND
@ -1042,28 +1138,31 @@ identifier
| NULLIF
| OBJECT
| OF
| OFFSET
| ON
| OR
| ORDER
| OUTER
| PAD
| POSITION
| POWER
| QUARTER
| REPLACE
| RIGHT
| ROUND
| RIGHT
| SECOND
| SELECT
| SET
| SIGN
| SIZE
| SOME
| SQRT
| STR
| SUBSTRING
| SUM
| THEN
| TIME
| TIMESTAMP
| TIMEZONE_HOUR
| TIMEZONE_MINUTE
| TRAILING

View File

@ -1362,6 +1362,20 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
@SuppressWarnings("JavaDoc")
String HBM2DDL_DB_NAME = "javax.persistence.database-product-name";
/**
* Specifies the name of the database provider in cases where a Connection to the underlying database is
* not available (aka, mainly in generating scripts). This value is used to help more precisely determine
* how to perform schema generation tasks for the underlying database in cases where
* {@value #HBM2DDL_DB_NAME} does not provide enough distinction.
* <p/>
* The value of this setting is expected to match the value returned by
* {@link java.sql.DatabaseMetaData#getDatabaseProductVersion()} for the target database.
*
* @see #HBM2DDL_DB_NAME
*/
@SuppressWarnings("JavaDoc")
String HBM2DDL_DB_VERSION = "javax.persistence.database-product-version";
/**
* Specifies the major version of the underlying database, as would be returned by
* {@link java.sql.DatabaseMetaData#getDatabaseMajorVersion} for the target database. This value is used to

View File

@ -6,65 +6,26 @@
*/
package org.hibernate.dialect;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.sql.Types;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.ScrollMode;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.HANAExtractEmulation;
import org.hibernate.dialect.identity.HANAIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
import org.hibernate.dialect.sequence.HANASequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.ConfigurationService.Converter;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.BinaryStream;
import org.hibernate.engine.jdbc.BlobImplementer;
import org.hibernate.engine.jdbc.CharacterStream;
import org.hibernate.engine.jdbc.ClobImplementer;
import org.hibernate.engine.jdbc.NClobImplementer;
import org.hibernate.engine.jdbc.*;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords;
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.jdbc.env.spi.*;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.LockTimeoutException;
@ -76,6 +37,7 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.mapping.Table;
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorHANADatabaseImpl;
@ -88,21 +50,16 @@ import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.DataHelper;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.BitTypeDescriptor;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.BooleanTypeDescriptor;
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.sql.DoubleTypeDescriptor;
import org.hibernate.type.descriptor.sql.NCharTypeDescriptor;
import org.hibernate.type.descriptor.sql.NClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.NVarcharTypeDescriptor;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
import org.hibernate.type.descriptor.sql.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* An abstract base class for SAP HANA dialects.
@ -122,26 +79,6 @@ public abstract class AbstractHANADialect extends Dialect {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractHANADialect.class );
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" );
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
};
private static class CloseSuppressingReader extends FilterReader {
protected CloseSuppressingReader(final Reader in) {
@ -764,37 +701,36 @@ public abstract class AbstractHANADialect extends Dialect {
public AbstractHANADialect() {
super();
registerColumnType( Types.DECIMAL, "decimal($p, $s)" );
//there is no 'numeric' type in HANA
registerColumnType( Types.NUMERIC, "decimal($p, $s)" );
//'double precision' syntax not supported
registerColumnType( Types.DOUBLE, "double" );
//no explicit precision
registerColumnType(Types.TIMESTAMP, "timestamp");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp");
// varbinary max length 5000
registerColumnType( Types.BINARY, 5000, "varbinary($l)" );
registerColumnType( Types.VARBINARY, 5000, "varbinary($l)" );
registerColumnType( Types.LONGVARBINARY, 5000, "varbinary($l)" );
// for longer values, map to blob
registerColumnType( Types.BINARY, "blob" );
registerColumnType( Types.VARBINARY, "blob" );
registerColumnType( Types.LONGVARBINARY, "blob" );
registerColumnType( Types.CHAR, "varchar(1)" );
registerColumnType( Types.NCHAR, "nvarchar(1)" );
//there is no 'char' or 'nchar' type in HANA
registerColumnType( Types.CHAR, "varchar($l)" );
registerColumnType( Types.NCHAR, "nvarchar($l)" );
registerColumnType( Types.VARCHAR, 5000, "varchar($l)" );
registerColumnType( Types.LONGVARCHAR, 5000, "varchar($l)" );
registerColumnType( Types.NVARCHAR, 5000, "nvarchar($l)" );
registerColumnType( Types.LONGNVARCHAR, 5000, "nvarchar($l)" );
// for longer values map to clob/nclob
registerColumnType( Types.LONGVARCHAR, "clob" );
registerColumnType( Types.VARCHAR, "clob" );
registerColumnType( Types.LONGNVARCHAR, "nclob" );
registerColumnType( Types.NVARCHAR, "nclob" );
registerColumnType( Types.CLOB, "clob" );
registerColumnType( Types.NCLOB, "nclob" );
registerColumnType( Types.BOOLEAN, "boolean" );
registerColumnType( Types.BIT, 1, "boolean" );
// map bit/tinyint to smallint since tinyint is unsigned on HANA
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.TINYINT, "smallint" );
@ -814,16 +750,24 @@ public abstract class AbstractHANADialect extends Dialect {
getDefaultProperties().setProperty( AvailableSettings.USE_GET_GENERATED_KEYS, "false" );
}
public int getDefaultDecimalPrecision() {
//the maximum on HANA
return 34;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("locate", StandardBasicTypes.INTEGER, "locate(?2, ?1)", "locate(?2, ?1, ?3)");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"locate(?2, ?1)",
"locate(?2, ?1, ?3)"
).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.cosh( queryEngine );
@ -836,28 +780,52 @@ public abstract class AbstractHANADialect extends Dialect {
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.daynameMonthname( queryEngine );
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.characterLength_length( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.addYearsMonthsDaysHoursMinutesSeconds( queryEngine );
CommonFunctionFactory.daysBetween( queryEngine );
CommonFunctionFactory.secondsBetween( queryEngine );
CommonFunctionFactory.formatdatetime_toVarchar( queryEngine );
CommonFunctionFactory.format_toVarchar( queryEngine );
CommonFunctionFactory.currentUtcdatetimetimestamp( queryEngine );
queryEngine.getSqmFunctionRegistry().register( "extract", new HANAExtractEmulation() );
}
/**
* HANA has no extract() function, but we can emulate
* it using the appropriate named functions instead of
* extract().
*
* The supported fields are
* {@link TemporalUnit#YEAR},
* {@link TemporalUnit#MONTH}
* {@link TemporalUnit#DAY},
* {@link TemporalUnit#HOUR},
* {@link TemporalUnit#MINUTE},
* {@link TemporalUnit#SECOND}
* {@link TemporalUnit#WEEK},
* {@link TemporalUnit#DAY_OF_WEEK},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*/
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case DAY_OF_WEEK:
return "(mod(weekday(?2)+1,7)+1)";
case DAY:
case DAY_OF_MONTH:
return "dayofmonth(?2)";
case DAY_OF_YEAR:
return "dayofyear(?2)";
default:
//I think week() returns the ISO week number
return "?1(?2)";
}
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(final SQLException sqlException, final String message, final String sql) {
@ -895,8 +863,7 @@ public abstract class AbstractHANADialect extends Dialect {
// 257 - Cannot insert NULL or update to NULL
// 301 - Unique constraint violated
// 461 - foreign key constraint violation
// 462 - failed on update or delete by foreign key constraint
// violation
// 462 - failed on update or delete by foreign key constraint violation
if ( errorCode == 287 || errorCode == 301 || errorCode == 461 || errorCode == 462 ) {
final String constraintName = getViolatedConstraintNameExtracter()
.extractConstraintName( sqlException );
@ -929,43 +896,11 @@ public abstract class AbstractHANADialect extends Dialect {
return " cascade";
}
@Override
public String getCreateSequenceString(final String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
protected String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) throws MappingException {
if ( incrementSize == 0 ) {
throw new MappingException( "Unable to create the sequence [" + sequenceName + "]: the increment size must not be 0" );
}
String createSequenceString = getCreateSequenceString( sequenceName ) + " start with " + initialValue + " increment by " + incrementSize;
if ( incrementSize > 0 ) {
if ( initialValue < 1 ) {
// default minvalue for an ascending sequence is 1
createSequenceString += " minvalue " + initialValue;
}
}
else {
if ( initialValue > -1 ) {
// default maxvalue for a descending sequence is -1
createSequenceString += " maxvalue " + initialValue;
}
}
return createSequenceString;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp from sys.dummy";
}
@Override
public String getDropSequenceString(final String sequenceName) {
return "drop sequence " + sequenceName;
}
@Override
public String getForUpdateString(final String aliases) {
return getForUpdateString() + " of " + aliases;
@ -1009,12 +944,6 @@ public abstract class AbstractHANADialect extends Dialect {
return getForUpdateString() + " nowait";
}
@Override
public String getLimitString(final String sql, final boolean hasOffset) {
return new StringBuilder( sql.length() + 20 ).append( sql ).append( hasOffset ? " limit ? offset ?" : " limit ?" )
.toString();
}
@Override
public String getNotExpression(final String expression) {
return "not (" + expression + ")";
@ -1030,16 +959,6 @@ public abstract class AbstractHANADialect extends Dialect {
return SequenceInformationExtractorHANADatabaseImpl.INSTANCE;
}
@Override
public String getSelectSequenceNextValString(final String sequenceName) {
return sequenceName + ".nextval";
}
@Override
public String getSequenceNextValString(final String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from sys.dummy";
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(final int sqlCode) {
switch ( sqlCode ) {
@ -1198,18 +1117,8 @@ public abstract class AbstractHANADialect extends Dialect {
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public boolean supportsSequences() {
return true;
public SequenceSupport getSequenceSupport() {
return HANASequenceSupport.INSTANCE;
}
@Override
@ -1249,7 +1158,7 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
return LimitOffsetLimitHandler.INSTANCE;
}
@Override
@ -1399,6 +1308,11 @@ public abstract class AbstractHANADialect extends Dialect {
return timeoutInSeconds;
}
@Override
public String getFromDual() {
return "from sys.dummy";
}
@Override
public String getQueryHintString(String query, List<String> hints) {
return query + " with hint (" + String.join( ",", hints ) + ")";
@ -1488,12 +1402,10 @@ public abstract class AbstractHANADialect extends Dialect {
USE_UNICODE_STRING_TYPES_DEFAULT_VALUE ).booleanValue();
if ( this.useUnicodeStringTypes ) {
registerColumnType( Types.CHAR, "nvarchar(1)" );
registerColumnType( Types.CHAR, "nvarchar($l)" );
registerColumnType( Types.VARCHAR, 5000, "nvarchar($l)" );
registerColumnType( Types.LONGVARCHAR, 5000, "nvarchar($l)" );
// for longer values map to clob/nclob
registerColumnType( Types.LONGVARCHAR, "nclob" );
registerColumnType( Types.VARCHAR, "nclob" );
registerColumnType( Types.CLOB, "nclob" );
}
@ -1524,10 +1436,9 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public String toBooleanValueString(boolean bool) {
if ( this.useLegacyBooleanType ) {
return bool ? "1" : "0";
}
return bool ? "true" : "false";
return this.useLegacyBooleanType
? super.toBooleanValueString( bool )
: String.valueOf( bool );
}
@Override
@ -1579,6 +1490,6 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public String translateDatetimeFormat(String format) {
//I don't think HANA needs FM
return Oracle8iDialect.datetimeFormat( format, false ).result();
return OracleDialect.datetimeFormat( format, false ).result();
}
}

View File

@ -6,13 +6,6 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.boot.TempTableDdlTransactionHandling;
@ -22,13 +15,19 @@ import org.hibernate.dialect.identity.AbstractTransactSQLIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.TrimSpec;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.type.StandardBasicTypes;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
/**
* An abstract base class for Sybase and MS SQL Server dialects.
@ -38,92 +37,93 @@ import org.hibernate.type.StandardBasicTypes;
abstract class AbstractTransactSQLDialect extends Dialect {
public AbstractTransactSQLDialect() {
super();
registerColumnType( Types.BINARY, "binary($l)" );
registerColumnType( Types.BIT, "tinyint" );
registerColumnType( Types.BIGINT, "numeric(19,0)" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.BOOLEAN, "bit" );
//SQL Server/Sybase 'bit' type is always exactly one bit
registerColumnType( Types.BIT, "smallint" );
//'tinyint' is an unsigned type in Sybase and
//SQL Server, holding values in the range 0-255
//see HHH-6779
registerColumnType( Types.TINYINT, "smallint" );
//it's called 'int' not 'integer'
registerColumnType( Types.INTEGER, "int" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double precision" );
//note that 'real' is double precision on SQL Server, single precision on Sybase
//but 'float' is single precision on Sybase, double precision on SQL Server
registerColumnType( Types.DATE, "datetime" );
registerColumnType( Types.TIME, "datetime" );
registerColumnType( Types.TIMESTAMP, "datetime" );
registerColumnType( Types.VARBINARY, "varbinary($l)" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetime" );
registerColumnType( Types.BLOB, "image" );
registerColumnType( Types.CLOB, "text" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.ln_log( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.atan2_atn2( queryEngine );
CommonFunctionFactory.mod_operator( queryEngine );
CommonFunctionFactory.square( queryEngine );
CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.pad_replicate( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.ascii(queryEngine);
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.concat_plusOperator( queryEngine );
CommonFunctionFactory.trim1( queryEngine );
CommonFunctionFactory.repeat_replicate( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.characterLength_len( queryEngine );
CommonFunctionFactory.extract_datepart( queryEngine );
CommonFunctionFactory.substring_substringLen( queryEngine );
CommonFunctionFactory.datepartDatename( queryEngine );
CommonFunctionFactory.lastDay_eomonth( queryEngine );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "square" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "(?1 % ?2)" )
.setInvariantType( StandardBasicTypes.INTEGER )
.setExactArgumentCount( 2 )
.register( "mod" );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atn2" )
.setInvariantType( StandardBasicTypes.DOUBLE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().registerVarArgs( "concat", StandardBasicTypes.STRING, "(", "+", ")" );
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "ln", "log" );
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("dateadd(");
//TODO: SQL Server supports nanosecond, but what about Sybase?
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
magnitude.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
public String trimPattern(TrimSpec specification, char character) {
return replaceLtrimRtrim(specification, character);
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
sqlAppender.append("datediff(");
//TODO: SQL Server supports nanosecond, but what about Sybase?
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
static String replaceLtrimRtrim(TrimSpec specification, char character) {
boolean blank = character == ' ';
switch ( specification ) {
case LEADING:
return blank
? "ltrim(?1)"
: "replace(replace(ltrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')"
.replace('@', character);
case TRAILING:
return blank
? "rtrim(?1)"
: "replace(replace(rtrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')"
.replace('@', character);
default:
return blank
? "ltrim(rtrim(?1))"
: "replace(replace(ltrim(rtrim(replace(replace(?1,' ','#%#%'),'@',' '))),' ','@'),'#%#%',' ')"
.replace('@', character);
}
}
@Override
@ -131,11 +131,6 @@ abstract class AbstractTransactSQLDialect extends Dialect {
return "add";
}
@Override
public String getNullColumnString() {
return "";
}
@Override
public boolean qualifyIndexName() {
return false;

View File

@ -6,26 +6,25 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CUBRIDExtractEmulation;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.CUBRIDIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.CUBRIDLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitLimitHandler;
import org.hibernate.dialect.sequence.CUBRIDSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlTreeCreationException;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorCUBRIDDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import static org.hibernate.query.TemporalUnit.HOUR;
import static org.hibernate.query.TemporalUnit.MINUTE;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import static org.hibernate.query.TemporalUnit.SECOND;
import java.sql.Types;
import static org.hibernate.query.TemporalUnit.*;
/**
* An SQL dialect for CUBRID (8.3.x and later).
@ -39,27 +38,19 @@ public class CUBRIDDialect extends Dialect {
public CUBRIDDialect() {
super();
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.BIT, "bit(8)" );
registerColumnType( Types.BLOB, "bit varying(65535)" );
registerColumnType( Types.BOOLEAN, "bit(8)" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.CLOB, "string" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.DECIMAL, "decimal" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.INTEGER, "int" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.REAL, "double" );
registerColumnType( Types.SMALLINT, "short" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TINYINT, "short" );
registerColumnType( Types.VARBINARY, 2000, "bit varying($l)" );
registerColumnType( Types.VARCHAR, "string" );
registerColumnType( Types.VARCHAR, 2000, "varchar($l)" );
registerColumnType( Types.VARCHAR, 255, "varchar($l)" );
registerColumnType( Types.BOOLEAN, "bit" );
registerColumnType( Types.TINYINT, "smallint" ); //no 'tinyint'
//'timestamp' has a very limited range
//'datetime' does not support explicit precision
//(always 3, millisecond precision)
registerColumnType(Types.TIMESTAMP, "datetime");
registerColumnType(Types.TIMESTAMP, "datetimetz");
//CUBRID has no 'binary' nor 'varbinary', but 'bit' is
//intended to be used for binary data
registerColumnType( Types.BINARY, "bit($l)");
registerColumnType( Types.VARBINARY, "bit varying($l)");
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
@ -96,12 +87,35 @@ public class CUBRIDDialect extends Dialect {
registerKeyword( "SEARCH" );
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
//not used for anything right now, but it
//could be used for timestamp literal format
@Override
public int getDefaultTimestampPrecision() {
return 3;
}
@Override
public String getTypeName(int code, Size size) throws HibernateException {
//precision of a CUBRID 'float(p)' represents
//decimal digits instead of binary digits
return super.getTypeName( code, binaryToDecimalPrecision( code, size ) );
}
@Override
public int getFloatPrecision() {
return 21; // -> 7 decimal digits
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
@ -110,10 +124,12 @@ public class CUBRIDDialect extends Dialect {
CommonFunctionFactory.log2( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.rand( queryEngine );
//rand() returns an integer between 0 and 231 on CUBRID
// CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.sysdateSystimestamp( queryEngine );
CommonFunctionFactory.systimestamp( queryEngine );
//TODO: CUBRID also has systime()/sysdate() returning TIME/DATE
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
@ -125,138 +141,31 @@ public class CUBRIDDialect extends Dialect {
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.sha1sha2( queryEngine );
CommonFunctionFactory.sha1( queryEngine );
CommonFunctionFactory.sha2( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.position( queryEngine );
// CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.insert( queryEngine );
CommonFunctionFactory.nowCurdateCurtime( queryEngine );
CommonFunctionFactory.makedateMaketime( queryEngine );
CommonFunctionFactory.bitandorxornot_bitAndOrXorNot( queryEngine );
CommonFunctionFactory.median( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.datediff( queryEngine );
CommonFunctionFactory.adddateSubdateAddtimeSubtime( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
// CommonFunctionFactory.concat_operator( queryEngine );
IngresDialect.bitwiseFunctions( queryEngine );
queryEngine.getSqmFunctionRegistry().register( "extract", new CUBRIDExtractEmulation() );
queryEngine.getSqmFunctionRegistry().registerNoArgs( "rownum", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "makedate" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "maketime" )
.setInvariantType( StandardBasicTypes.TIME )
.setExactArgumentCount( 3 )
.register();
}
@Override
public String translateDatetimeFormat(String format) {
//I do not know if CUBRID supports FM, but it
//seems that it does pad by default, so it needs it!
return Oracle8iDialect.datetimeFormat( format, true )
.replace("SSSSSS", "FF")
.replace("SSSSS", "FF")
.replace("SSSS", "FF")
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("adddate(");
to.render();
sqlAppender.append(",interval ");
if ( unit == NANOSECOND ) {
sqlAppender.append("(");
}
magnitude.render();
if ( unit == NANOSECOND ) {
sqlAppender.append(")/1e6");
}
sqlAppender.append(" ");
if ( unit == NANOSECOND ) {
sqlAppender.append("microsecond");
}
else {
sqlAppender.append( unit.toString() );
}
sqlAppender.append(")");
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
switch ( unit ) {
case DAY:
sqlAppender.append("datediff(");
to.render();
sqlAppender.append(",");
from.render();
sqlAppender.append(")");
break;
case HOUR:
timediff(from, to, sqlAppender, HOUR, unit);
break;
case MINUTE:
sqlAppender.append("(");
timediff(from, to, sqlAppender, MINUTE, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, HOUR, unit);
sqlAppender.append(")");
break;
case SECOND:
sqlAppender.append("(");
timediff(from, to, sqlAppender, SECOND, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, MINUTE, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, HOUR, unit);
sqlAppender.append(")");
break;
case NANOSECOND:
sqlAppender.append("(");
timediff(from, to, sqlAppender, NANOSECOND, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, SECOND, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, MINUTE, unit);
sqlAppender.append("+");
timediff(from, to, sqlAppender, HOUR, unit);
sqlAppender.append(")");
break;
default:
throw new SqlTreeCreationException( "unsupported temporal unit for CUBRID: " + unit);
}
}
private void timediff(
Renderer from, Renderer to,
Appender sqlAppender,
TemporalUnit diffUnit,
TemporalUnit toUnit) {
if ( diffUnit == NANOSECOND ) {
sqlAppender.append("1e6*");
}
sqlAppender.append("extract(");
if ( diffUnit == NANOSECOND ) {
sqlAppender.append("millisecond");
}
else {
sqlAppender.append( diffUnit.toString() );
}
sqlAppender.append(",timediff(");
to.render();
sqlAppender.append(",");
from.render();
sqlAppender.append("))");
sqlAppender.append( diffUnit.conversionFactor(toUnit) );
CommonFunctionFactory.rownumInstOrderbyGroupbyNum( queryEngine );
}
@Override
@ -265,28 +174,8 @@ public class CUBRIDDialect extends Dialect {
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public String getAddColumnString() {
return "add";
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + sequenceName + ".next_value from table({1}) as T(X)";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create serial " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop serial " + sequenceName;
public SequenceSupport getSequenceSupport() {
return CUBRIDSequenceSupport.INSTANCE;
}
@Override
@ -299,11 +188,6 @@ public class CUBRIDDialect extends Dialect {
return false;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsExistsInSelect() {
return false;
@ -319,6 +203,13 @@ public class CUBRIDDialect extends Dialect {
return SequenceInformationExtractorCUBRIDDatabaseImpl.INSTANCE;
}
@Override
public String getFromDual() {
//TODO: is this really needed?
//TODO: would "from table({0})" be better?
return "from db_root";
}
@Override
public char openQuote() {
return '[';
@ -331,7 +222,7 @@ public class CUBRIDDialect extends Dialect {
@Override
public String getForUpdateString() {
return " ";
return "";
}
@Override
@ -371,7 +262,7 @@ public class CUBRIDDialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
return CUBRIDLimitHandler.INSTANCE;
return LimitLimitHandler.INSTANCE;
}
@Override
@ -383,4 +274,130 @@ public class CUBRIDDialect extends Dialect {
public boolean supportsPartitionBy() {
return true;
}
@Override
public String translateDatetimeFormat(String format) {
//I do not know if CUBRID supports FM, but it
//seems that it does pad by default, so it needs it!
return OracleDialect.datetimeFormat( format, true )
.replace("SSSSSS", "FF")
.replace("SSSSS", "FF")
.replace("SSSS", "FF")
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
}
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000_000; //milliseconds
}
/**
* CUBRID supports a limited list of temporal fields in the
* extract() function, but we can emulate some of them by
* using the appropriate named functions instead of
* extract().
*
* Thus, the additional supported fields are
* {@link TemporalUnit#DAY_OF_YEAR},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*
* In addition, the field {@link TemporalUnit#SECOND} is
* redefined to include milliseconds.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case SECOND:
return "(second(?2)+extract(millisecond from ?2)/1e3)";
case DAY_OF_WEEK:
return "dayofweek(?2)";
case DAY_OF_MONTH:
return "dayofmonth(?2)";
case DAY_OF_YEAR:
return "dayofyear(?2)";
case WEEK:
return "week(?2,3)"; //mode 3 is the ISO week
default:
return "?1(?2)";
}
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NANOSECOND:
return "adddate(?3, interval (?2)/1e6 millisecond)";
case NATIVE:
return "adddate(?3, interval ?2 millisecond)";
default:
return "adddate(?3, interval ?2 ?1)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
StringBuilder pattern = new StringBuilder();
switch ( unit ) {
case DAY:
//note: datediff() is backwards on CUBRID
return "datediff(?3,?2)";
case HOUR:
timediff(pattern, HOUR, unit);
break;
case MINUTE:
pattern.append("(");
timediff(pattern, MINUTE, unit);
pattern.append("+");
timediff(pattern, HOUR, unit);
pattern.append(")");
break;
case SECOND:
pattern.append("(");
timediff(pattern, SECOND, unit);
pattern.append("+");
timediff(pattern, MINUTE, unit);
pattern.append("+");
timediff(pattern, HOUR, unit);
pattern.append(")");
break;
case NATIVE:
case NANOSECOND:
pattern.append("(");
timediff(pattern, unit, unit);
pattern.append("+");
timediff(pattern, SECOND, unit);
pattern.append("+");
timediff(pattern, MINUTE, unit);
pattern.append("+");
timediff(pattern, HOUR, unit);
pattern.append(")");
break;
default:
throw new SemanticException("unsupported temporal unit for CUBRID: " + unit);
}
return pattern.toString();
}
private void timediff(
StringBuilder sqlAppender,
TemporalUnit diffUnit,
TemporalUnit toUnit) {
if ( diffUnit == NANOSECOND ) {
sqlAppender.append("1e6*");
}
sqlAppender.append("extract(");
if ( diffUnit == NANOSECOND || diffUnit == NATIVE ) {
sqlAppender.append("millisecond");
}
else {
sqlAppender.append("?1");
}
//note: timediff() is backwards on CUBRID
sqlAppender.append(",timediff(?3,?2))");
sqlAppender.append( diffUnit.conversionFactor( toUnit, this ) );
}
}

View File

@ -6,47 +6,10 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.Chache71IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.exception.internal.CacheSQLExceptionConversionDelegate;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.CacheJoinFragment;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.StandardBasicTypes;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
/**
* Cach&eacute; 2007.1 dialect.
*
* This class is required in order to use Hibernate with InterSystems Cach&eacute; SQL. Compatible with
* This class is required in order to use Hibernate with Intersystems Cach&eacute; SQL. Compatible with
* Cach&eacute; 2007.1.
*
* <h2>PREREQUISITES</h2>
@ -190,465 +153,9 @@ import static org.hibernate.query.TemporalUnit.NANOSECOND;
* Cache71Dialect ships with Hibernate 3.2. All other dialects are distributed by InterSystems and subclass Cache71Dialect.
*
* @author Jonathan Levinson
*
* @deprecated use {@link CacheDialect}
*/
@Deprecated
public class Cache71Dialect extends CacheDialect {}
public class Cache71Dialect extends Dialect {
private LimitHandler limitHandler;
/**
* Creates new <code>Cache71Dialect</code> instance. Sets up the JDBC /
* Cach&eacute; type mappings.
*/
public Cache71Dialect() {
super();
commonRegistration();
this.limitHandler = new TopLimitHandler( true, true );
}
protected final void commonRegistration() {
// Note: For object <-> SQL datatype mappings see:
// Configuration Manager | Advanced | SQL | System DDL Datatype Mappings
//
// TBD registerColumnType(Types.BINARY, "binary($1)");
// changed 08-11-2005, jsl
registerColumnType( Types.BINARY, "varbinary($1)" );
registerColumnType( Types.BIGINT, "BigInt" );
registerColumnType( Types.BIT, "bit" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.DECIMAL, "decimal" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.LONGVARBINARY, "longvarbinary" );
registerColumnType( Types.LONGVARCHAR, "longvarchar" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.REAL, "real" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.VARBINARY, "longvarbinary" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.BLOB, "longvarbinary" );
registerColumnType( Types.CLOB, "longvarchar" );
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
getDefaultProperties().setProperty( Environment.USE_SQL_COMMENTS, "false" );
}
static void useJdbcEscape(QueryEngine queryEngine, String name) {
queryEngine.getSqmFunctionRegistry().wrapInJdbcEscape(
name,
queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( name )
);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.daynameMonthname( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.dayofweekmonthyear( queryEngine );
CommonFunctionFactory.repeat_replicate( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.extract_datepart( queryEngine );
CommonFunctionFactory.lastDay( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("locate", StandardBasicTypes.INTEGER, "$find(?2, ?1)", "$find(?2, ?1, ?3)");
useJdbcEscape(queryEngine, "sin");
useJdbcEscape(queryEngine, "cos");
useJdbcEscape(queryEngine, "tan");
useJdbcEscape(queryEngine, "asin");
useJdbcEscape(queryEngine, "acos");
useJdbcEscape(queryEngine, "atan");
useJdbcEscape(queryEngine, "atan2");
useJdbcEscape(queryEngine, "exp");
useJdbcEscape(queryEngine, "log");
useJdbcEscape(queryEngine, "log10");
useJdbcEscape(queryEngine, "pi");
useJdbcEscape(queryEngine, "truncate");
useJdbcEscape(queryEngine, "left");
useJdbcEscape(queryEngine, "right");
useJdbcEscape(queryEngine, "hour");
useJdbcEscape(queryEngine, "minute");
useJdbcEscape(queryEngine, "second");
useJdbcEscape(queryEngine, "week");
useJdbcEscape(queryEngine, "quarter");
useJdbcEscape(queryEngine, "dayname");
useJdbcEscape(queryEngine, "monthname");
useJdbcEscape(queryEngine, "dayofweek");
useJdbcEscape(queryEngine, "dayofmonth");
useJdbcEscape(queryEngine, "dayofyear");
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("dateadd(");
if ( unit == NANOSECOND ) {
sqlAppender.append("millisecond");
}
else {
sqlAppender.append( unit.toString() );
}
sqlAppender.append(", ");
magnitude.render();
if ( unit == NANOSECOND ) {
sqlAppender.append("/1e6");
}
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
sqlAppender.append("datediff(");
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean hasAlterTable() {
// Does this dialect support the ALTER TABLE syntax?
return true;
}
@Override
public boolean qualifyIndexName() {
// Do we need to qualify index names with the schema name?
return false;
}
@Override
@SuppressWarnings("StringBufferReplaceableByString")
public String getAddForeignKeyConstraintString(
String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
// The syntax used to add a foreign key constraint to a table.
return new StringBuilder( 300 )
.append( " ADD CONSTRAINT " )
.append( constraintName )
.append( " FOREIGN KEY " )
.append( constraintName )
.append( " (" )
.append( String.join( ", ", foreignKey ) )
.append( ") REFERENCES " )
.append( referencedTable )
.append( " (" )
.append( String.join( ", ", primaryKey ) )
.append( ") " )
.toString();
}
/**
* Does this dialect support check constraints?
*
* @return {@code false} (Cache does not support check constraints)
*/
@SuppressWarnings("UnusedDeclaration")
public boolean supportsCheck() {
return false;
}
@Override
public String getAddColumnString() {
// The syntax used to add a column to a table
return " add column";
}
@Override
public String getCascadeConstraintsString() {
// Completely optional cascading drop clause.
return "";
}
@Override
public boolean dropConstraints() {
// Do we need to drop constraints before dropping tables in this dialect?
return true;
}
@Override
public boolean supportsCascadeDelete() {
return true;
}
@Override
public boolean hasSelfReferentialForeignKeyBug() {
return true;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
// return new GlobalTemporaryTableBulkIdStrategy(
// new IdTableSupportStandardImpl() {
// @Override
// public String generateIdTableName(String baseName) {
// final String name = super.generateIdTableName( baseName );
// return name.length() > 25 ? name.substring( 1, 25 ) : name;
// }
//
// @Override
// public String getCreateIdTableCommand() {
// return "create global temporary table";
// }
// },
// AfterUseAction.DROP
// );
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "identity";
}
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new Chache71IdentityColumnSupport();
}
// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsSequences() {
return false;
}
// It really does support sequences, but InterSystems elects to suggest usage of IDENTITY instead :/
// Anyway, below are the actual support overrides for users wanting to use this combo...
//
// public String getSequenceNextValString(String sequenceName) {
// return "select InterSystems.Sequences_GetNext('" + sequenceName + "') from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "')";
// }
//
// public String getSelectSequenceNextValString(String sequenceName) {
// return "(select InterSystems.Sequences_GetNext('" + sequenceName + "') from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "'))";
// }
//
// public String getCreateSequenceString(String sequenceName) {
// return "insert into InterSystems.Sequences(Name) values (ucase('" + sequenceName + "'))";
// }
//
// public String getDropSequenceString(String sequenceName) {
// return "delete from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "')";
// }
//
// public String getQuerySequencesString() {
// return "select name from InterSystems.Sequences";
// }
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax...
// Set your transaction mode to READ_COMMITTED before using
if ( lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_WRITE) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_READ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC) {
return new OptimisticLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC_FORCE_INCREMENT) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode);
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {
return new SelectLockingStrategy( lockable, lockMode );
}
}
// LIMIT support (ala TOP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return super.getLimitHandler();
}
return limitHandler;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimit() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimitOffset() {
return false;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsVariableLimit() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean bindLimitParametersFirst() {
// Does the LIMIT clause come at the start of the SELECT statement, rather than at the end?
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean useMaxForLimit() {
// Does the LIMIT clause take a "maximum" row number instead of a total number of returned rows?
return true;
}
@Override
@SuppressWarnings("deprecation")
public String getLimitString(String sql, boolean hasOffset) {
if ( hasOffset ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
// This does not support the Cache SQL 'DISTINCT BY (comma-list)' extensions,
// but this extension is not supported through Hibernate anyway.
final int insertionPoint = sql.startsWith( "select distinct" ) ? 15 : 6;
return new StringBuilder( sql.length() + 8 )
.append( sql )
.insert( insertionPoint, " TOP ? " )
.toString();
}
// callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
ps.execute();
return (ResultSet) ps.getObject( 1 );
}
// miscellaneous support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getLowercaseFunction() {
// The name of the SQL function that transforms a string to lowercase
return "lower";
}
@Override
public String getNullColumnString() {
// The keyword used to specify a nullable column.
return " null";
}
@Override
public JoinFragment createOuterJoinFragment() {
// Create an OuterJoinGenerator for this dialect.
return new CacheJoinFragment();
}
@Override
public String getNoColumnsInsertString() {
// The keyword used to insert a row without specifying
// any column values
return " default values";
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new CacheSQLExceptionConversionDelegate( this );
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
/**
* The Cache ViolatedConstraintNameExtracter.
*/
public static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
return extractUsingTemplate( "constraint (", ") violated", sqle.getMessage() );
}
};
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean areStringComparisonsCaseInsensitive() {
return true;
}
@Override
public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
return false;
}
@Override
public String translateDatetimeFormat(String format) {
//I don't think Cache needs FM
return Oracle8iDialect.datetimeFormat( format, false ).result();
}
}

View File

@ -0,0 +1,361 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.LockMode;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.CacheIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.lock.*;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.dialect.sequence.CacheSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.exception.internal.CacheSQLExceptionConversionDelegate;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.CacheJoinFragment;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.StandardBasicTypes;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
/**
* Dialect for Intersystems Cach&eacute; SQL 2007.1 and above.
*
* @author Jonathan Levinson
*/
public class CacheDialect extends Dialect {
public CacheDialect() {
super();
// Note: For object <-> SQL datatype mappings see:
// Configuration Manager > Advanced > SQL > System DDL Datatype Mappings
registerColumnType( Types.BOOLEAN, "bit" );
//no explicit precision
registerColumnType(Types.TIMESTAMP, "timestamp");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp");
registerColumnType( Types.BLOB, "image" );
registerColumnType( Types.CLOB, "text" );
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
getDefaultProperties().setProperty( Environment.USE_SQL_COMMENTS, "false" );
}
private static void useJdbcEscape(QueryEngine queryEngine, String name) {
//Yep, this seems to be truly necessary for certain functions
queryEngine.getSqmFunctionRegistry().wrapInJdbcEscape(
name,
queryEngine.getSqmFunctionRegistry().findFunctionDescriptor(name)
);
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public int getDefaultDecimalPrecision() {
//the largest *meaningful* value
return 19;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.daynameMonthname( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.dayofweekmonthyear( queryEngine );
CommonFunctionFactory.repeat_replicate( queryEngine );
CommonFunctionFactory.datepartDatename( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.nowCurdateCurtime( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.lastDay( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"$find(?2, ?1)",
"$find(?2, ?1, ?3)"
).setArgumentListSignature("(pattern, string[, start])");
useJdbcEscape(queryEngine, "sin");
useJdbcEscape(queryEngine, "cos");
useJdbcEscape(queryEngine, "tan");
useJdbcEscape(queryEngine, "asin");
useJdbcEscape(queryEngine, "acos");
useJdbcEscape(queryEngine, "atan");
useJdbcEscape(queryEngine, "atan2");
useJdbcEscape(queryEngine, "exp");
useJdbcEscape(queryEngine, "log");
useJdbcEscape(queryEngine, "log10");
useJdbcEscape(queryEngine, "pi");
useJdbcEscape(queryEngine, "truncate");
useJdbcEscape(queryEngine, "left");
useJdbcEscape(queryEngine, "right");
useJdbcEscape(queryEngine, "hour");
useJdbcEscape(queryEngine, "minute");
useJdbcEscape(queryEngine, "second");
useJdbcEscape(queryEngine, "week");
useJdbcEscape(queryEngine, "quarter");
useJdbcEscape(queryEngine, "dayname");
useJdbcEscape(queryEngine, "monthname");
useJdbcEscape(queryEngine, "dayofweek");
useJdbcEscape(queryEngine, "dayofmonth");
useJdbcEscape(queryEngine, "dayofyear");
}
@Override
public String extractPattern(TemporalUnit unit) {
return "datepart(?1, ?2)";
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "dateadd(millisecond, (?2)/1e6, ?3)";
default:
return "dateadd(?1, ?2, ?3)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "datediff(millisecond, ?2, ?3)*1e6";
default:
return "datediff(?1, ?2, ?3)";
}
}
// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean qualifyIndexName() {
// Do we need to qualify index names with the schema name?
return false;
}
@Override
@SuppressWarnings("StringBufferReplaceableByString")
public String getAddForeignKeyConstraintString(
String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
// The syntax used to add a foreign key constraint to a table.
return new StringBuilder( 300 )
.append( " ADD CONSTRAINT " )
.append( constraintName )
.append( " FOREIGN KEY " )
.append( constraintName )
.append( " (" )
.append( String.join( ", ", foreignKey ) )
.append( ") REFERENCES " )
.append( referencedTable )
.append( " (" )
.append( String.join( ", ", primaryKey ) )
.append( ") " )
.toString();
}
@Override
public boolean hasSelfReferentialForeignKeyBug() {
return true;
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "identity";
}
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new CacheIdentityColumnSupport();
}
// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public SequenceSupport getSequenceSupport() {
return CacheSequenceSupport.INSTANCE;
}
public String getQuerySequencesString() {
return "select name from InterSystems.Sequences";
}
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax...
// Set your transaction mode to READ_COMMITTED before using
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {
return new SelectLockingStrategy( lockable, lockMode );
}
}
// LIMIT support (ala TOP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public LimitHandler getLimitHandler() {
return TopLimitHandler.INSTANCE;
}
// callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
ps.execute();
return (ResultSet) ps.getObject( 1 );
}
// miscellaneous support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getLowercaseFunction() {
// The name of the SQL function that transforms a string to lowercase
return "lower";
}
@Override
public String getNullColumnString() {
// The keyword used to specify a nullable column.
return " null";
}
@Override
@SuppressWarnings("deprecation")
public JoinFragment createOuterJoinFragment() {
// Create an OuterJoinGenerator for this dialect.
return new CacheJoinFragment();
}
@Override
public String getNoColumnsInsertString() {
// The keyword used to insert a row without specifying
// any column values
return " default values";
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new CacheSQLExceptionConversionDelegate( this );
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
/**
* The Cache ViolatedConstraintNameExtracter.
*/
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
return extractUsingTemplate( "constraint (", ") violated", sqle.getMessage() );
}
};
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean areStringComparisonsCaseInsensitive() {
return true;
}
@Override
public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
return false;
}
@Override
public String translateDatetimeFormat(String format) {
//I don't think Cache needs FM
return OracleDialect.datetimeFormat( format, false ).result();
}
}

View File

@ -0,0 +1,307 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
import java.sql.Types;
import static org.hibernate.query.TemporalUnit.DAY;
import static org.hibernate.query.TemporalUnit.NATIVE;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiDateLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiTimeLiteral;
/**
* A dialect for CockroachDB.
*
* @author Gavin King
*/
public class CockroachDialect extends Dialect {
// KNOWN LIMITATIONS:
// * no support for java.sql.Clob
public CockroachDialect() {
super();
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//no binary/varbinary
registerColumnType( Types.VARBINARY, "bytes" );
registerColumnType( Types.BINARY, "bytes" );
//no clob
registerColumnType( Types.LONGVARCHAR, "string" );
registerColumnType( Types.CLOB, "string" );
//no nchar/nvarchar
registerColumnType( Types.NCHAR, "string($l)" );
registerColumnType( Types.NVARCHAR, "string($l)" );
//no nclob
registerColumnType( Types.LONGNVARCHAR, "string" );
registerColumnType( Types.NCLOB, "string" );
registerColumnType( Types.JAVA_OBJECT, "json" );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.overlay( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.substringFromFor( queryEngine );
CommonFunctionFactory.locate_positionSubstring( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.md5( queryEngine );
CommonFunctionFactory.sha1( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.cbrt( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.trunc( queryEngine ); //TODO: emulate second arg
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "experimental_strftime")
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.setArgumentListSignature("(datetime as pattern)")
.register();
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
}
@Override
public String getCascadeConstraintsString() {
return " cascade";
}
@Override
public boolean supportsIfExistsBeforeTableName() {
return true;
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return true;
}
@Override
public boolean supportsIfExistsAfterAlterTable() {
return true;
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public boolean supportsValuesList() {
return true;
}
@Override
public boolean supportsRowValueConstructorSyntax() {
return true;
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
@Override
public boolean supportsPartitionBy() {
return true;
}
@Override
public boolean supportsNonQueryWithCTE() {
return true;
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public String getNoColumnsInsertString() {
return "default values";
}
@Override
public String getCaseInsensitiveLike(){
return "ilike";
}
@Override
public boolean supportsCaseInsensitiveLike() {
return true;
}
@Override
public boolean requiresParensForTupleDistinctCounts() {
return true;
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "sequence";
}
@Override
public SequenceSupport getSequenceSupport() {
return PostgreSQLSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select sequence_name, sequence_schema, sequence_catalog, start_value, minimum_value, maximum_value, increment from information_schema.sequences";
}
@Override
public boolean supportsNationalizedTypes() {
return false;
}
@Override
protected String wrapDateLiteral(String date) {
return wrapAsAnsiDateLiteral(date);
}
@Override
protected String wrapTimeLiteral(String time) {
return wrapAsAnsiTimeLiteral(time);
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "timestamp with time zone '" + timestamp + "'";
}
/**
* The {@code extract()} function returns {@link TemporalUnit#DAY_OF_WEEK}
* numbered from 0 to 6. This isn't consistent with what most other
* databases do, so here we adjust the result by generating
* {@code (extract(dayofweek,arg)+1))}.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_WEEK:
return "(" + super.extractPattern(unit) + "+1)";
case SECOND:
return "(extract(second from ?2)+extract(microsecond from ?2)/1e6)";
default:
return super.extractPattern(unit);
}
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "dayofyear";
case DAY_OF_WEEK: return "dayofweek";
default: return super.translateExtractField( unit );
}
}
/**
* {@code microsecond} is the smallest unit for an {@code interval},
* and the highest precision for a {@code timestamp}.
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000; //microseconds
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e3 * interval '1 microsecond')";
case NATIVE:
return "(?3 + (?2) * interval '1 microsecond')";
case QUARTER: //quarter is not supported in interval literals
return "(?3 + (?2) * interval '3 month')";
case WEEK: //week is not supported in interval literals
return "(?3 + (?2) * interval '7 day')";
default:
return "(?3 + (?2) * interval '1 ?1')";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case YEAR:
return "(extract(year from ?3)-extract(year from ?2))";
case QUARTER:
return "(extract(year from ?3)*4-extract(year from ?2)*4+extract(month from ?3)//3-extract(month from ?2)//3)";
case MONTH:
return "(extract(year from ?3)*12-extract(year from ?2)*12+extract(month from ?3)-extract(month from ?2))";
}
if ( !toTimestamp && !fromTimestamp ) {
// special case: subtraction of two dates
// results in an integer number of days
// instead of an INTERVAL
return "(?3-?2)" + DAY.conversionFactor( unit, this );
}
else {
switch (unit) {
case WEEK:
return "extract_duration(hour from ?3-?2)/168";
case DAY:
return "extract_duration(hour from ?3-?2)/24";
case NANOSECOND:
return "extract_duration(microsecond from ?3-?2)*1e3";
default:
return "extract_duration(?1 from ?3-?2)";
}
}
}
@Override
public String translateDurationField(TemporalUnit unit) {
return unit==NATIVE
? "microsecond"
: super.translateDurationField(unit);
}
@Override
public String translateDatetimeFormat(String format) {
return SpannerDialect.datetimeFormat( format ).result();
}
@Override
public LimitHandler getLimitHandler() {
return OffsetFetchLimitHandler.INSTANCE;
}
}

View File

@ -8,10 +8,12 @@ package org.hibernate.dialect;
import org.hibernate.dialect.identity.DB2390IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.FetchLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.dialect.sequence.DB2390SequenceSupport;
import org.hibernate.dialect.sequence.NoSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
/**
@ -22,108 +24,40 @@ import org.hibernate.engine.spi.RowSelection;
*/
public class DB2390Dialect extends DB2Dialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
if (LimitHelper.hasFirstRow( selection )) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only";
}
private final int version;
@Override
public boolean supportsLimit() {
return true;
}
int get390Version() {
return version;
}
@Override
public boolean useMaxForLimit() {
return true;
}
public DB2390Dialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() );
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
public DB2390Dialect() {
this(7);
}
private static final AbstractLimitHandler LEGACY_LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only";
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
public DB2390Dialect(int version) {
super();
this.version = version;
}
@Override
public boolean supportsSequences() {
return false;
public SequenceSupport getSequenceSupport() {
return get390Version() < 8
? NoSequenceSupport.INSTANCE
: DB2390SequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return null;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public String getLimitString(String sql, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
if ( limit == 0 ) {
return sql;
}
return sql + " fetch first " + limit + " rows only ";
return get390Version() < 8 ? null : "select * from sysibm.syssequences";
}
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return LEGACY_LIMIT_HANDLER;
}
else {
return LIMIT_HANDLER;
}
return FetchLimitHandler.INSTANCE;
}
@Override

View File

@ -11,27 +11,13 @@ package org.hibernate.dialect;
* An SQL dialect for DB2/390 version 8.
*
* @author Tobias Sternvik
*
* @deprecated use {@code DB2390Dialect(8)}
*/
@Deprecated
public class DB2390V8Dialect extends DB2390Dialect {
@Override
public boolean supportsSequences() {
return true;
}
public String getSequenceNextValString(String sequenceName) {
return "select nextval for " + sequenceName + " from sysibm.sysdummy1";
}
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName + " as integer start with 1 increment by 1 minvalue 1 nomaxvalue nocycle nocache"; //simple default settings..
}
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName + " restrict";
}
public String getQuerySequencesString() {
return "select * from sysibm.syssequences";
public DB2390V8Dialect() {
super(8);
}
}

View File

@ -8,55 +8,25 @@ package org.hibernate.dialect;
import org.hibernate.dialect.identity.DB2390IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.FetchLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.dialect.sequence.NoSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
/**
* An SQL dialect for DB2/400. This class provides support for DB2 Universal Database for iSeries,
* also known as DB2/400.
* An SQL dialect for DB2/400. This class provides support for
* DB2 Universal Database for iSeries, also known as DB2/400.
*
* @author Peter DeGregorio (pdegregorio)
*/
public class DB2400Dialect extends DB2Dialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
if ( LimitHelper.hasFirstRow( selection ) ) {
//nest the main query in an outer select
return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( "
+ sql + " fetch first " + getMaxOrLimit( selection ) + " rows only ) as inner2_ ) as inner1_ where rownumber_ > "
+ selection.getFirstRow() + " order by rownumber_";
}
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only";
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
/**
* No support for sequences.
*/
@Override
public boolean supportsSequences() {
return false;
}
@Override
public boolean supportsLimit() {
return true;
public SequenceSupport getSequenceSupport() {
return NoSequenceSupport.INSTANCE;
}
@Override
@ -65,40 +35,13 @@ public class DB2400Dialect extends DB2Dialect {
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public String getLimitString(String sql, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
if ( limit == 0 ) {
return sql;
}
return sql + " fetch first " + limit + " rows only ";
public String getForUpdateString() {
return " for update with rs";
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public String getForUpdateString() {
return " for update with rs";
return FetchLimitHandler.INSTANCE;
}
@Override

View File

@ -6,74 +6,19 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
/**
* An SQL dialect for DB2 9.7.
*
* @author Gail Badner
*
* @deprecated use {@code DB2Dialect(970)}
*/
@Deprecated
public class DB297Dialect extends DB2Dialect {
@Override
public String getCrossJoinSeparator() {
// DB2 9.7 and later support "cross join"
return " cross join ";
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
// Starting in DB2 9.7, "real" global temporary tables that can be shared between sessions
// are supported; (obviously) data is not shared between sessions.
return new GlobalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, name -> "HT_" + name ),
() -> new TempIdTableExporter( false, this::getTypeName ) {
@Override
protected String getCreateOptions() {
return "not logged";
}
},
AfterUseAction.CLEAN,
runtimeModelCreationContext.getSessionFactory()
);
int getVersion() {
return 970;
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
// See HHH-12753
// It seems that DB2's JDBC 4.0 support as of 9.5 does not support the N-variant methods like
// NClob or NString. Therefore here we overwrite the sql type descriptors to use the non-N variants
// which are supported.
switch ( sqlCode ) {
case Types.NCHAR:
return CharTypeDescriptor.INSTANCE;
case Types.NCLOB:
if ( useInputStreamToInsertBlob() ) {
return ClobTypeDescriptor.STREAM_BINDING;
}
else {
return ClobTypeDescriptor.CLOB_BINDING;
}
case Types.NVARCHAR:
return VarcharTypeDescriptor.INSTANCE;
default:
return super.getSqlTypeDescriptorOverride( sqlCode );
}
}
}

View File

@ -6,27 +6,22 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.JDBCException;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.NullPrecedence;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DB2FormatEmulation;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.DB2LimitHandler;
import org.hibernate.dialect.pagination.LegacyDB2LimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.sequence.DB2SequenceSupport;
import org.hibernate.dialect.sequence.LegacyDB2SequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.unique.DB2UniqueDelegate;
import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
@ -34,14 +29,22 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDB2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.*;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
/**
* An SQL dialect for DB2.
@ -50,69 +53,55 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
*/
public class DB2Dialect extends Dialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
if (LimitHelper.hasFirstRow( selection )) {
//nest the main query in an outer select
return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( "
+ sql + " fetch first " + getMaxOrLimit( selection ) + " rows only ) as inner2_ ) as inner1_ where rownumber_ > "
+ selection.getFirstRow() + " order by rownumber_";
}
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only";
}
// KNOWN LIMITATIONS:
@Override
public boolean supportsLimit() {
return true;
}
// * can't select a parameter unless wrapped
// in a cast or function call
@Override
public boolean useMaxForLimit() {
return true;
}
private final int version;
@Override
public boolean supportsVariableLimit() {
return false;
}
};
private LimitHandler limitHandler;
int getVersion() {
return version;
}
private final UniqueDelegate uniqueDelegate;
/**
* Constructs a DB2Dialect
*/
public DB2Dialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
public DB2Dialect() {
this(900);
}
public DB2Dialect(int version) {
super();
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "varchar($l) for bit data" );
// DB2 converts numeric to decimal under the hood
// Note that the type returned by DB2 for a numeric column will be Types.DECIMAL. Thus, we have an issue when
// comparing the types during the schema validation, defining the type to decimal here as the type names will
// also be compared and there will be a match. See HHH-12827 for the details.
this.version = version;
registerColumnType( Types.BIT, 1, "boolean" ); //no bit
registerColumnType( Types.BIT, "smallint" ); //no bit
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//HHH-12827: map them both to the same type to
// avoid problems with schema update
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
if ( getVersion()<1100 ) {
registerColumnType( Types.BINARY, "varchar($l) for bit data" ); //should use 'binary' since version 11
registerColumnType( Types.BINARY, 254, "char($l) for bit data" ); //should use 'binary' since version 11
registerColumnType( Types.VARBINARY, "varchar($l) for bit data" ); //should use 'varbinary' since version 11
}
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
registerColumnType( Types.LONGVARCHAR, "long varchar" );
registerColumnType( Types.LONGVARBINARY, "long varchar for bit data" );
registerColumnType( Types.BINARY, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, 254, "char($l) for bit data" );
registerColumnType( Types.BOOLEAN, "smallint" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)" );
//not keywords, at least not in DB2 11,
//but perhaps they were in older versions?
registerKeyword( "current" );
registerKeyword( "date" );
registerKeyword( "time" );
@ -125,6 +114,15 @@ public class DB2Dialect extends Dialect {
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
uniqueDelegate = new DB2UniqueDelegate( this );
limitHandler = getVersion() < 1110
? LegacyDB2LimitHandler.INSTANCE
: DB2LimitHandler.INSTANCE;
}
public int getDefaultDecimalPrecision() {
//this is the maximum allowed in DB2
return 31;
}
@Override
@ -138,13 +136,11 @@ public class DB2Dialect extends Dialect {
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.bitand( queryEngine );
CommonFunctionFactory.bitor( queryEngine );
@ -158,159 +154,145 @@ public class DB2Dialect extends Dialect {
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.dateTimeTimestamp( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.insert( queryEngine );
CommonFunctionFactory.overlayCharacterLength_overlay( queryEngine );
CommonFunctionFactory.median( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.stdevVarianceSamp( queryEngine );
CommonFunctionFactory.addYearsMonthsDaysHoursMinutesSeconds( queryEngine );
CommonFunctionFactory.yearsMonthsDaysHoursMinutesSecondsBetween( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
queryEngine.getSqmFunctionRegistry().register( "formatdatetime", new DB2FormatEmulation() );
queryEngine.getSqmFunctionRegistry().register( "format", new DB2FormatEmulation() );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "upper" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 1, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "lower" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 1, 3 )
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "posstr" )
.setInvariantType( StandardBasicTypes.INTEGER )
.setExactArgumentCount( 2 )
.setArgumentListSignature("(string, pattern)")
.register();
}
// queryEngine.getSqmFunctionRegistry().namedTemplateBuilder( "posstr" )
// .setInvariantType( StandardSpiBasicTypes.INTEGER )
// .setExactArgumentCount( 2 )
// .register();
/**
* Since we're using {@code seconds_between()} and
* {@code add_seconds()}, it makes sense to use
* seconds as the "native" precision.
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
//Note that DB2 actually supports all the way up to
//thousands-of-nanoseconds precision for timestamps!
//i.e. timestamp(12)
return 1_000_000_000; //seconds
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
StringBuilder pattern = new StringBuilder();
boolean castFrom = !fromTimestamp && !unit.isDateUnit();
boolean castTo = !toTimestamp && !unit.isDateUnit();
switch (unit) {
case NATIVE:
case NANOSECOND:
sqlAppender.append("(second");
pattern.append("(seconds_between(");
break;
//note: DB2 does have weeks_between()
case MONTH:
case QUARTER:
// the months_between() function results
// in a non-integral value, so trunc() it
sqlAppender.append("trunc(month");
pattern.append("trunc(months_between(");
break;
default:
sqlAppender.append( unit.toString() );
pattern.append("?1s_between(");
}
sqlAppender.append("s_between(");
if (castTo) {
sqlAppender.append("cast(");
pattern.append("cast(?3 as timestamp)");
}
to.render();
if (castTo) {
sqlAppender.append(" as timestamp)");
else {
pattern.append("?3");
}
sqlAppender.append(",");
pattern.append(",");
if (castFrom) {
sqlAppender.append("cast(");
pattern.append("cast(?2 as timestamp)");
}
from.render();
if (castFrom) {
sqlAppender.append(" as timestamp)");
else {
pattern.append("?2");
}
sqlAppender.append(")");
pattern.append(")");
switch (unit) {
case NATIVE:
pattern.append("+(microsecond(?3)-microsecond(?2))/1e6)");
break;
case NANOSECOND:
sqlAppender.append("*1e9+(microsecond(");
to.render();
sqlAppender.append(")-microsecond(");
from.render();
sqlAppender.append("))*1e3)");
pattern.append("*1e9+(microsecond(?3)-microsecond(?2))*1e3)");
break;
case MONTH:
sqlAppender.append(")");
pattern.append(")");
break;
case QUARTER:
sqlAppender.append("/3)");
pattern.append("/3)");
break;
}
return pattern.toString();
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
StringBuilder pattern = new StringBuilder();
boolean castTo = !timestamp && !unit.isDateUnit();
sqlAppender.append("add_");
pattern.append("add_");
switch (unit) {
case NATIVE:
case NANOSECOND:
sqlAppender.append("second");
pattern.append("second");
break;
case WEEK:
//note: DB2 does not have add_weeks()
sqlAppender.append("day");
pattern.append("day");
break;
case QUARTER:
sqlAppender.append("month");
pattern.append("month");
break;
default:
sqlAppender.append( unit.toString() );
pattern.append("?1");
}
sqlAppender.append("s(");
pattern.append("s(");
if (castTo) {
sqlAppender.append("cast(");
pattern.append("cast(?3 as timestamp)");
}
to.render();
if (castTo) {
sqlAppender.append(" as timestamp)");
else {
pattern.append("?3");
}
sqlAppender.append(",");
pattern.append(",");
switch (unit) {
case NANOSECOND:
case WEEK:
case QUARTER:
sqlAppender.append("(");
break;
}
magnitude.render();
switch (unit) {
case NANOSECOND:
sqlAppender.append(")/1e9");
pattern.append("(?2)/1e9");
break;
case WEEK:
sqlAppender.append(")*7");
pattern.append("(?2)*7");
break;
case QUARTER:
sqlAppender.append(")*3");
pattern.append("(?2)*3");
break;
default:
pattern.append("?2");
}
sqlAppender.append(")");
}
@Override
public String translateDatetimeFormat(String format) {
//DB2 does not need nor support FM
return Oracle8iDialect.datetimeFormat( format, false ).result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
//WEEK means the ISO week number on DB2
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
default: return unit.toString();
}
pattern.append(")");
return pattern.toString();
}
@Override
public String getLowercaseFunction() {
return "lcase";
}
@Override
public String getAddColumnString() {
return "add column";
return getVersion() < 970 ? "lcase" : super.getLowercaseFunction();
}
@Override
@ -319,33 +301,10 @@ public class DB2Dialect extends Dialect {
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "values nextval for " + sequenceName;
}
@Override
public String getSelectSequenceNextValString(String sequenceName) throws MappingException {
return "next value for " + sequenceName;
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName + " restrict";
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
public SequenceSupport getSequenceSupport() {
return getVersion() < 970
? LegacyDB2SequenceSupport.INSTANCE
: DB2SequenceSupport.INSTANCE;
}
@Override
@ -364,54 +323,10 @@ public class DB2Dialect extends Dialect {
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimit() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsVariableLimit() {
return false;
}
@Override
@SuppressWarnings("deprecation")
public String getLimitString(String sql, int offset, int limit) {
if ( offset == 0 ) {
return sql + " fetch first " + limit + " rows only";
}
//nest the main query in an outer select
return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( "
+ sql + " fetch first " + limit + " rows only ) as inner2_ ) as inner1_ where rownumber_ > "
+ offset + " order by rownumber_";
}
/**
* {@inheritDoc}
* <p/>
*
* DB2 does have a one-based offset, however this was actually already handled in the limit string building
* (the '?+1' bit). To not mess up inheritors, I'll leave that part alone and not touch the offset here.
*/
@Override
@SuppressWarnings("deprecation")
public int convertToFirstRowValue(int zeroBasedFirstResult) {
return zeroBasedFirstResult;
}
@Override
@SuppressWarnings("deprecation")
public String getForUpdateString() {
return " for read only with rs use and keep update locks";
}
@Override
@SuppressWarnings("deprecation")
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
@ -430,21 +345,26 @@ public class DB2Dialect extends Dialect {
@Override
public String getSelectClauseNullString(int sqlType) {
return selectNullString(sqlType);
}
static String selectNullString(int sqlType) {
String literal;
switch ( sqlType ) {
case Types.VARCHAR:
case Types.CHAR:
literal = "'x'";
literal = "''";
break;
case Types.DATE:
literal = "'2000-1-1'";
break;
case Types.TIMESTAMP:
literal = "'2000-1-1 00:00:00'";
break;
case Types.TIME:
literal = "'00:00:00'";
break;
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
literal = "'2000-1-1 00:00:00'";
break;
default:
literal = "0";
}
@ -481,8 +401,24 @@ public class DB2Dialect extends Dialect {
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
if ( getVersion() >= 970 ) {
// Starting in DB2 9.7, "real" global temporary tables that can be shared between sessions
// are supported; (obviously) data is not shared between sessions.
return new GlobalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, name -> "HT_" + name ),
() -> new TempIdTableExporter( false, this::getTypeName ) {
@Override
protected String getCreateOptions() {
return "not logged";
}
},
AfterUseAction.CLEAN,
runtimeModelCreationContext.getSessionFactory()
);
}
return super.getFallbackSqmMutationStrategy( rootEntityDescriptor, runtimeModelCreationContext );
// // Prior to DB2 9.7, "real" global temporary tables that can be shared between sessions
// // are *not* supported; even though the DB2 command says to declare a "global" temp table
// // Hibernate treats it as a "local" temp table.
@ -553,7 +489,8 @@ public class DB2Dialect extends Dialect {
@Override
public String getCrossJoinSeparator() {
//DB2 v9.1 doesn't support 'cross join' syntax
return ", ";
//DB2 9.7 and later support "cross join"
return getVersion() < 970 ? ", " : super.getCrossJoinSeparator();
}
@ -580,15 +517,38 @@ public class DB2Dialect extends Dialect {
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
if ( sqlCode == Types.BOOLEAN ) {
return SmallIntTypeDescriptor.INSTANCE;
}
else if ( sqlCode == Types.NUMERIC ) {
return DecimalTypeDescriptor.INSTANCE;
}
public String getFromDual() {
return "from sysibm.dual";
}
return super.getSqlTypeDescriptorOverride( sqlCode );
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
if ( getVersion() < 970 ) {
return sqlCode == Types.NUMERIC
? DecimalTypeDescriptor.INSTANCE
: super.getSqlTypeDescriptorOverride(sqlCode);
}
else {
// See HHH-12753
// It seems that DB2's JDBC 4.0 support as of 9.5 does not
// support the N-variant methods like NClob or NString.
// Therefore here we overwrite the sql type descriptors to
// use the non-N variants which are supported.
switch ( sqlCode ) {
case Types.NCHAR:
return CharTypeDescriptor.INSTANCE;
case Types.NCLOB:
return useInputStreamToInsertBlob()
? ClobTypeDescriptor.STREAM_BINDING
: ClobTypeDescriptor.CLOB_BINDING;
case Types.NVARCHAR:
return VarcharTypeDescriptor.INSTANCE;
case Types.NUMERIC:
return DecimalTypeDescriptor.INSTANCE;
default:
return super.getSqlTypeDescriptorOverride(sqlCode);
}
}
}
@Override
@ -619,7 +579,7 @@ public class DB2Dialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
return limitHandler;
}
/**
@ -633,7 +593,6 @@ public class DB2Dialect extends Dialect {
* if expression has not been explicitly specified.
* @param nullPrecedence Nulls precedence. Default value: {@link NullPrecedence#NONE}.
*
* @return SQL string.
*/
@Override
public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nullPrecedence) {
@ -679,4 +638,22 @@ public class DB2Dialect extends Dialect {
public boolean supportsPartitionBy() {
return true;
}
@Override
public String translateDatetimeFormat(String format) {
//DB2 does not need nor support FM
return OracleDialect.datetimeFormat( format, false ).result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
//WEEK means the ISO week number on DB2
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
default: return super.translateExtractField( unit );
}
}
}

View File

@ -1,32 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* A Dialect for accessing Oracle through DataDirect driver
*/
public class DataDirectOracle9Dialect extends Oracle9iDialect {
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
boolean isResultSet = ps.execute();
// This assumes you will want to ignore any update counts
while (!isResultSet && ps.getUpdateCount() != -1) {
isResultSet = ps.getMoreResults();
}
return ps.getResultSet();
}
}

View File

@ -6,11 +6,14 @@
*/
package org.hibernate.dialect;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
/**
* List all supported relational database systems.
* A list of relational database systems for which Hibernate can resolve a {@link Dialect}.
*
* However, Hibernate can work with other database systems that are not listed by the {@link Database}
* enumeration, as long as a {@link Dialect} implementation class is provided via the {@code hibernate.dialect}
* configuration property.
*
* @author Vlad Mihalcea
*/
@ -18,539 +21,500 @@ public enum Database {
CACHE {
@Override
public Class<? extends Dialect> latestDialect() {
return Cache71Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new CacheDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith( "Cache" );
}
},
CUBRID {
@Override
public Class<? extends Dialect> latestDialect() {
return CUBRIDDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new CUBRIDDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "CUBRID".equalsIgnoreCase( databaseName ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "CUBRID".equalsIgnoreCase( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "cubrid.jdbc.driver.CUBRIDDriver";
}
},
DB2 {
@Override
public Class<? extends Dialect> latestDialect() {
return DB2400Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
// if ( "DB2 UDB for AS/400".equals( info.getDatabaseName() ) ) {
// return new DB2400Dialect();
// }
String databaseVersion = info.getDatabaseVersion();
if ( databaseVersion==null ) {
return new DB2Dialect(info);
}
//See https://www.ibm.com/support/knowledgecenter/SSEPEK_12.0.0/java/src/tpc/imjcc_c0053013.html
switch ( databaseVersion.substring(0,3) ) {
case "SQL": // Linux, UNIX, Windows
return new DB2Dialect(info);
case "DSN": // z/OS
return new DB2390Dialect(info);
case "QSQ": // i
return new DB2400Dialect();
default:
return null;
}
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "DB2 UDB for AS/400".equals( databaseName ) ) {
return new DB2400Dialect();
}
if ( databaseName.startsWith( "DB2/" ) ) {
return new DB2Dialect();
}
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith( "DB2" );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.ibm.db2.jcc.DB2Driver";
}
},
DERBY {
@Override
public Class<? extends Dialect> latestDialect() {
return DerbyTenSevenDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new DerbyDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "Apache Derby".equals( databaseName ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
final int minorVersion = info.getDatabaseMinorVersion();
if ( majorVersion > 10 || ( majorVersion == 10 && minorVersion >= 7 ) ) {
return latestDialectInstance( this );
}
else if ( majorVersion == 10 && minorVersion == 6 ) {
return new DerbyTenSixDialect();
}
else if ( majorVersion == 10 && minorVersion == 5 ) {
return new DerbyTenFiveDialect();
}
else {
return new DerbyDialect();
}
}
return null;
public boolean productNameMatches(String databaseName) {
return "Apache Derby".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return jdbcUrl.startsWith("jdbc:derby://")
? "org.apache.derby.jdbc.ClientDriver"
: "org.apache.derby.jdbc.EmbeddedDriver";
}
},
ENTERPRISEDB {
@Override
public Class<? extends Dialect> latestDialect() {
return PostgresPlusDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new PostgresPlusDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "EnterpriseDB".equals( databaseName ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "EnterpriseDB".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.edb.Driver";
}
@Override
public String getUrlPrefix() {
return "jdbc:edb:";
}
},
FIREBIRD {
@Override
public Class<? extends Dialect> latestDialect() {
return FirebirdDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new FirebirdDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( databaseName.startsWith( "Firebird" ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith( "Firebird" );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "org.firebirdsql.jdbc.FBDriver";
}
@Override
public String getUrlPrefix() {
return "jdbc:firebirdsql:";
}
},
FRONTBASE {
@Override
public Class<? extends Dialect> latestDialect() {
return FrontBaseDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new FrontBaseDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith( "FrontBase" );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.frontbase.jdbc.FBJDriver";
}
},
H2 {
@Override
public Class<? extends Dialect> latestDialect() {
return H2Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new H2Dialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "H2".equals( databaseName ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "H2".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "org.h2.Driver";
}
},
HANA {
@Override
public Class<? extends Dialect> latestDialect() {
return HANAColumnStoreDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new HANAColumnStoreDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "HDB".equals( databaseName ) ) {
// SAP recommends defaulting to column store.
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "HDB".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.sap.db.jdbc.Driver";
}
@Override
public String getUrlPrefix() {
return "jdbc:sap:";
}
},
HSQL {
@Override
public Class<? extends Dialect> latestDialect() {
return HSQLDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new HSQLDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "HSQL Database Engine".equals( databaseName ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "HSQL Database Engine".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "org.hsqldb.jdbc.JDBCDriver";
}
@Override
public String getUrlPrefix() {
return "jdbc:hsqldb:";
}
},
INFORMIX {
@Override
public Class<? extends Dialect> latestDialect() {
return Informix10Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new InformixDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "Informix Dynamic Server".equals( databaseName ) ) {
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
//usually "Informix Dynamic Server"
return databaseName.toLowerCase().startsWith("informix");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.informix.jdbc.IfxDriver" ;
}
@Override
public String getUrlPrefix() {
return "jdbc:informix-";
}
},
INGRES {
@Override
public Class<? extends Dialect> latestDialect() {
return Ingres10Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new IngresDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "ingres".equalsIgnoreCase( databaseName ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
final int minorVersion = info.getDatabaseMinorVersion();
if ( majorVersion < 9 ) {
return new IngresDialect();
}
else if ( majorVersion == 9 ) {
if ( minorVersion > 2 ) {
return new Ingres9Dialect();
}
return new IngresDialect();
}
else if ( majorVersion == 10 ) {
return new Ingres10Dialect();
}
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("ingres");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.ingres.jdbc.IngresDriver";
}
},
INTERBASE {
@Override
public Class<? extends Dialect> latestDialect() {
return InterbaseDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new InterbaseDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("interbase");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "interbase.interclient.Driver";
}
},
MARIADB {
@Override
public Class<? extends Dialect> latestDialect() {
return MariaDB103Dialect.class;
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
if ( info.getDriverName() != null && info.getDriverName().startsWith( "MariaDB" ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
final int minorVersion = info.getDatabaseMinorVersion();
if ( majorVersion == 10 ) {
if ( minorVersion >= 3 ) {
return new MariaDB103Dialect();
}
else if ( minorVersion == 2 ) {
return new MariaDB102Dialect();
}
else if ( minorVersion >= 0 ) {
return new MariaDB10Dialect();
}
return new MariaDB53Dialect();
}
else if ( majorVersion > 5 || ( majorVersion == 5 && minorVersion >= 3 ) ) {
return new MariaDB53Dialect();
}
return new MariaDBDialect();
public boolean matchesResolutionInfo(DialectResolutionInfo info) {
if ( productNameMatches( info.getDatabaseName() ) ) {
return true;
}
return null;
else {
//in case the product name has been set to MySQL
String driverName = info.getDriverName();
return driverName != null && driverName.startsWith("MariaDB");
}
}
@Override
public Dialect createDialect(DialectResolutionInfo info) {
return new MariaDBDialect(info);
}
@Override
public boolean productNameMatches(String productName) {
return "MariaDB".equals( productName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "org.mariadb.jdbc.Driver";
}
},
MAXDB {
@Override
public Class<? extends Dialect> latestDialect() {
return SAPDBDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new SAPDBDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("sap db")
|| databaseName.toLowerCase().startsWith("maxdb");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.sap.dbtech.jdbc.DriverSapDB";
}
@Override
public String getUrlPrefix() {
return "jdbc:sapdb:";
}
},
MCKOI {
@Override
public Class<? extends Dialect> latestDialect() {
return MckoiDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new MckoiDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("mckoi");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.mckoi.JDBCDriver";
}
},
MIMERSQL {
@Override
public Class<? extends Dialect> latestDialect() {
return MimerSQLDialect.class;
}
MIMER {
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public Dialect createDialect(DialectResolutionInfo info) {
return new MimerSQLDialect();
}
@Override
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith("Mimer SQL");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.mimer.jdbc.Driver";
}
},
MYSQL {
@Override
public Class<? extends Dialect> latestDialect() {
return MySQL8Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new MySQLDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "MySQL".equals( databaseName ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
final int minorVersion = info.getDatabaseMinorVersion();
if ( majorVersion < 5 ) {
return new MySQLDialect();
}
else if ( majorVersion == 5 ) {
if ( minorVersion < 5 ) {
return new MySQL5Dialect();
}
else if ( minorVersion < 7 ) {
return new MySQL55Dialect();
}
else {
return new MySQL57Dialect();
}
}
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "MySQL".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.mysql.cj.jdbc.Driver";
}
},
ORACLE {
@Override
public Class<? extends Dialect> latestDialect() {
return Oracle12cDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new OracleDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "Oracle".equals( databaseName ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
switch ( majorVersion ) {
case 12:
return new Oracle12cDialect();
case 11:
// fall through
case 10:
return new Oracle10gDialect();
case 9:
return new Oracle9iDialect();
case 8:
return new Oracle8iDialect();
default:
return latestDialectInstance( this );
}
}
return null;
public boolean productNameMatches(String databaseName) {
return "Oracle".equals( databaseName );
}
/*@Override
public String getDriverClassName() {
return "oracle.jdbc.OracleDriver";
}*/
},
POINTBASE {
@Override
public Class<? extends Dialect> latestDialect() {
return PointbaseDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new PointbaseDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("pointbase");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.pointbase.jdbc.jdbcUniversalDriver";
}
},
POSTGRESQL {
@Override
public Class<? extends Dialect> latestDialect() {
return PostgreSQL10Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new PostgreSQLDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "PostgreSQL".equals( databaseName ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
final int minorVersion = info.getDatabaseMinorVersion();
if ( majorVersion < 8 ) {
return new PostgreSQL81Dialect();
}
if ( majorVersion == 8 ) {
return minorVersion >= 2 ? new PostgreSQL82Dialect() : new PostgreSQL81Dialect();
}
if ( majorVersion == 9 ) {
if ( minorVersion < 2 ) {
return new PostgreSQL9Dialect();
}
else if ( minorVersion < 4 ) {
return new PostgreSQL92Dialect();
}
else if ( minorVersion < 5 ) {
return new PostgreSQL94Dialect();
}
else {
return new PostgreSQL95Dialect();
}
}
return latestDialectInstance( this );
}
return null;
public boolean productNameMatches(String databaseName) {
return "PostgreSQL".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "org.postgresql.Driver";
}
},
PROGRESS {
@Override
public Class<? extends Dialect> latestDialect() {
return ProgressDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new ProgressDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("progress")
|| databaseName.toLowerCase().startsWith("openedge");
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.ddtek.jdbc.openedge.OpenEdgeDriver";
}
@Override
public String getUrlPrefix() {
return "jdbc:datadirect:openedge:";
}
},
SQLSERVER {
@Override
public Class<? extends Dialect> latestDialect() {
return SQLServer2012Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new SQLServerDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( databaseName.startsWith( "Microsoft SQL Server" ) ) {
final int majorVersion = info.getDatabaseMajorVersion();
switch ( majorVersion ) {
case 8: {
return new SQLServerDialect();
}
case 9: {
return new SQLServer2005Dialect();
}
case 10: {
return new SQLServer2008Dialect();
}
case 11:
case 12:
case 13: {
return new SQLServer2012Dialect();
}
default: {
if ( majorVersion < 8 ) {
return new SQLServerDialect();
}
else {
// assume `majorVersion > 13`
return latestDialectInstance( this );
}
}
}
}
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.startsWith( "Microsoft SQL Server" );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
}
},
SYBASE {
@Override
public Class<? extends Dialect> latestDialect() {
return SybaseASE15Dialect.class;
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
public Dialect createDialect(DialectResolutionInfo info) {
final String databaseName = info.getDatabaseName();
if ( "Sybase SQL Server".equals( databaseName ) || "Adaptive Server Enterprise".equals( databaseName ) ) {
return latestDialectInstance( this );
if ( isASE( databaseName ) ) {
return new SybaseASEDialect(info);
}
if ( databaseName.startsWith( "Adaptive Server Anywhere" ) || "SQL Anywhere".equals( databaseName ) ) {
if ( isASA( databaseName ) ) {
return new SybaseAnywhereDialect();
}
return null;
return null; //impossible
}
private boolean isASA(String databaseName) {
return databaseName.startsWith( "Adaptive Server Anywhere" )
|| "SQL Anywhere".equals( databaseName );
}
private boolean isASE(String databaseName) {
return "Sybase SQL Server".equals( databaseName )
|| "Adaptive Server Enterprise".equals( databaseName );
}
@Override
public boolean productNameMatches(String productName) {
return isASA( productName ) || isASE( productName );
}
@Override
public boolean matchesUrl(String jdbcUrl) {
return jdbcUrl.startsWith("jdbc:sybase:")
|| jdbcUrl.startsWith("jdbc:sqlanywhere:");
}
},
TERADATA {
@Override
public Class<? extends Dialect> latestDialect() {
return Teradata14Dialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new TeradataDialect(info);
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return "Teradata".equals( databaseName );
}
@Override
public String getDriverClassName(String jdbcUrl) {
return "com.teradata.jdbc.TeraDriver";
}
},
TIMESTEN {
@Override
public Class<? extends Dialect> latestDialect() {
return TimesTenDialect.class;
public Dialect createDialect(DialectResolutionInfo info) {
return new TimesTenDialect();
}
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
return null;
public boolean productNameMatches(String databaseName) {
return databaseName.toLowerCase().startsWith("timesten");
}
};
public abstract Class<? extends Dialect> latestDialect();
public abstract Dialect resolveDialect(DialectResolutionInfo info);
private static Dialect latestDialectInstance(Database database) {
try {
return database.latestDialect().newInstance();
}
catch (InstantiationException | IllegalAccessException e) {
throw new HibernateException( e );
}
/**
* Does this database match the given metadata?
*/
public boolean matchesResolutionInfo(DialectResolutionInfo info) {
return productNameMatches( info.getDatabaseName() );
}
/**
* Does this database have the given product name?
*/
public abstract boolean productNameMatches(String productName);
/**
* Create a {@link Dialect} for the given metadata.
*/
public abstract Dialect createDialect(DialectResolutionInfo info);
/**
* Get the name of the JDBC driver class for this database,
* or null if we're not too sure what it should be.
*/
public String getDriverClassName(String jdbcUrl) {
return null;
}
/**
* Get the JDBC URL prefix used by this database.
*/
public String getUrlPrefix() {
return "jdbc:" + toString().toLowerCase() + ":";
}
/**
* Does the given JDBC URL connect to this database?
*/
public boolean matchesUrl(String jdbcUrl) {
return jdbcUrl.toLowerCase().startsWith( getUrlPrefix() );
}
}

View File

@ -6,25 +6,28 @@
*/
package org.hibernate.dialect;
import java.lang.reflect.Method;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.MappingException;
import org.hibernate.JDBCException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DerbyConcatEmulation;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.DerbyLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.sequence.DB2SequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.CastType;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
@ -33,151 +36,293 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DerbyCaseFragment;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.DerbyCaseExpressionWalker;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDerbyDatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.jboss.logging.Logger;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import static org.hibernate.query.CastType.BOOLEAN;
/**
* Hibernate Dialect for Cloudscape 10 - aka Derby. This implements both an
* override for the identity column generator as well as for the case statement
* issue documented at:
* http://www.jroller.com/comments/kenlars99/Weblog/cloudscape_soon_to_be_derby
* Hibernate Dialect for Apache Derby / Cloudscape 10
*
* @author Simon Johnston
* @author Gavin King
*
* @deprecated HHH-6073
*/
@Deprecated
public class DerbyDialect extends DB2Dialect {
@SuppressWarnings("deprecation")
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
DerbyDialect.class.getName()
);
public class DerbyDialect extends Dialect {
// KNOWN LIMITATIONS:
// * limited set of fields for extract()
// (no 'day of xxxx', nor 'week of xxxx')
// * no support for format()
// * pad() can only pad with blanks
// * can't cast String to Binary
// * can't select a parameter unless wrapped
// in a cast or function call
private final int version;
int getVersion() {
return version;
}
private int driverVersionMajor;
private int driverVersionMinor;
private final LimitHandler limitHandler;
/**
* Constructs a DerbyDialect
*/
@SuppressWarnings("deprecation")
public DerbyDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
public DerbyDialect() {
this(1000);
}
public DerbyDialect(int version) {
super();
if ( this.getClass() == DerbyDialect.class ) {
LOG.deprecatedDerbyDialect();
}
this.version = version;
registerColumnType( Types.BIT, 1, "boolean" ); //no bit
registerColumnType( Types.BIT, "smallint" ); //no bit
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//HHH-12827: map them both to the same type to
// avoid problems with schema update
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.BINARY, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, 254, "char($l) for bit data" );
registerColumnType( Types.VARBINARY, "varchar($l) for bit data" );
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
registerColumnType( Types.BLOB, "blob" );
registerDerbyKeywords();
determineDriverVersion();
if ( driverVersionMajor > 10 || ( driverVersionMajor == 10 && driverVersionMinor >= 7 ) ) {
registerColumnType( Types.BOOLEAN, "boolean" );
}
limitHandler = getVersion() < 1050
? AbstractLimitHandler.NO_LIMIT
: new DerbyLimitHandler( getVersion() >= 1060 );
}
this.limitHandler = new DerbyLimitHandler();
public int getDefaultDecimalPrecision() {
//this is the maximum allowed in Derby
return 31;
}
@Override
public int getFloatPrecision() {
return 23;
}
@Override
public int getDoublePrecision() {
return 52;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.sinh( queryEngine );
CommonFunctionFactory.cosh( queryEngine );
CommonFunctionFactory.tanh( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.trim1( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.leftRight_substrLength( queryEngine );
CommonFunctionFactory.characterLength_length( queryEngine );
CommonFunctionFactory.power_expLn( queryEngine );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "round", "floor(?1*1e?2+0.5)/1e?2")
.setExactArgumentCount( 2 )
.setInvariantType( StandardBasicTypes.DOUBLE )
.register();
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() );
//no way I can see to pad with anything other than spaces
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "lpad", "case when length(?1)<?2 then substr(char('',?2)||?1,length(?1)) else ?1 end" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.setArgumentListSignature("(string, length)")
.register();
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "rpad", "case when length(?1)<?2 then substr(?1||char('',?2),1,?2) else ?1 end" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.setArgumentListSignature("(string, length)")
.register();
}
private void determineDriverVersion() {
try {
// locate the derby sysinfo class and query its version info
final Class sysinfoClass = ReflectHelper.classForName( "org.apache.derby.tools.sysinfo", this.getClass() );
final Method majorVersionGetter = sysinfoClass.getMethod( "getMajorVersion", ReflectHelper.NO_PARAM_SIGNATURE );
final Method minorVersionGetter = sysinfoClass.getMethod( "getMinorVersion", ReflectHelper.NO_PARAM_SIGNATURE );
driverVersionMajor = (Integer) majorVersionGetter.invoke( null, ReflectHelper.NO_PARAMS );
driverVersionMinor = (Integer) minorVersionGetter.invoke( null, ReflectHelper.NO_PARAMS );
}
catch ( Exception e ) {
LOG.unableToLoadDerbyDriver( e.getMessage() );
driverVersionMajor = -1;
driverVersionMinor = -1;
/**
* Derby doesn't have an extract() function, and has
* no functions at all for calendaring, but we can
* emulate the most basic functionality of extract()
* using the functions it does have.
*
* The only supported {@link TemporalUnit}s are:
* {@link TemporalUnit#YEAR},
* {@link TemporalUnit#MONTH}
* {@link TemporalUnit#DAY},
* {@link TemporalUnit#HOUR},
* {@link TemporalUnit#MINUTE},
* {@link TemporalUnit#SECOND} (along with
* {@link TemporalUnit#NANOSECOND},
* {@link TemporalUnit#DATE}, and
* {@link TemporalUnit#TIME}, which are desugared
* by the parser).
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case DAY_OF_MONTH:
return "day(?2)";
case DAY_OF_YEAR:
return "({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),?2)}+1)";
case DAY_OF_WEEK:
return "(mod({fn timestampdiff(sql_tsi_day, {d '2000-01-01'}, ?2)},7)+1)";
default:
return "?1(?2)";
}
}
private boolean isTenPointFiveReleaseOrNewer() {
return driverVersionMajor > 10 || ( driverVersionMajor == 10 && driverVersionMinor >= 5 );
@Override
public String translateExtractField(TemporalUnit unit) {
switch (unit) {
case WEEK:
case DAY_OF_YEAR:
case DAY_OF_WEEK:
throw new NotYetImplementedFor6Exception("field type not supported on Derby: " + unit);
case DAY_OF_MONTH:
return "day";
default:
return super.translateExtractField(unit);
}
}
/**
* Derby does have a real {@link java.sql.Types#BOOLEAN}
* type, but it doesn't know how to cast to it. Worse,
* Derby makes us use the {@code double()} function to
* cast things to its floating point types.
*/
@Override
public String castPattern(CastType from, CastType to) {
switch (to) {
case FLOAT:
return "cast(double(?1) as real)";
case DOUBLE:
return "double(?1)";
case BOOLEAN:
switch (from) {
case STRING:
// return "case when lower(?1)in('t','true') then true when lower(?1)in('f','false') then false end";
return "case when ?1 in('t','true','T','TRUE') then true when ?1 in('f','false','F','FALSE') then false end";
case LONG:
case INTEGER:
return "(?1<>0)";
}
break;
case INTEGER:
case LONG:
if ( from == BOOLEAN && getVersion() >= 1070 ) {
return "case ?1 when false then 0 when true then 1 end";
}
break;
}
return super.castPattern(from, to);
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampadd(sql_tsi_frac_second, mod(bigint(?2),1000000000), {fn timestampadd(sql_tsi_second, bigint((?2)/1000000000), ?3)})}";
default:
return "{fn timestampadd(sql_tsi_?1, bigint(?2), ?3)}";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampdiff(sql_tsi_frac_second, ?2, ?3)}";
default:
return "{fn timestampdiff(sql_tsi_?1, ?2, ?3)}";
}
}
@Override
public String toBooleanValueString(boolean bool) {
return getVersion() < 1070
? super.toBooleanValueString( bool )
: String.valueOf( bool );
}
@Override
public String getCrossJoinSeparator() {
return ", ";
//Derby 10.5 doesn't support 'cross join' syntax
//Derby 10.6 and later support "cross join"
return getVersion() < 1060 ? ", " : super.getCrossJoinSeparator();
}
@Override
@SuppressWarnings("deprecation")
public CaseFragment createCaseFragment() {
return new DerbyCaseFragment();
}
@Override
public CaseExpressionWalker getCaseExpressionWalker() {
return DerbyCaseExpressionWalker.INSTANCE;
}
@Override
public boolean dropConstraints() {
return true;
}
@Override
public boolean supportsSequences() {
// technically sequence support was added in 10.6.1.0...
//
// The problem though is that I am not exactly sure how to differentiate 10.6.1.0 from any other 10.6.x release.
//
// http://db.apache.org/derby/docs/10.0/publishedapi/org/apache/derby/tools/sysinfo.html seems incorrect. It
// states that derby's versioning scheme is major.minor.maintenance, but obviously 10.6.1.0 has 4 components
// to it, not 3.
//
// Let alone the fact that it states that versions with the matching major.minor are 'feature
// compatible' which is clearly not the case here (sequence support is a new feature...)
return driverVersionMajor > 10 || ( driverVersionMajor == 10 && driverVersionMinor >= 6 );
public SequenceSupport getSequenceSupport() {
return getVersion() < 1060
? super.getSequenceSupport()
: DB2SequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
if ( supportsSequences() ) {
return "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid";
}
else {
return null;
}
return getVersion() < 1060
? "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid"
: null;
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
if ( getQuerySequencesString() == null ) {
return SequenceInformationExtractorNoOpImpl.INSTANCE;
}
else {
return SequenceInformationExtractorDerbyDatabaseImpl.INSTANCE;
}
return getVersion() < 1060
? SequenceInformationExtractorNoOpImpl.INSTANCE
: SequenceInformationExtractorDerbyDatabaseImpl.INSTANCE;
}
@Override
public String getSequenceNextValString(String sequenceName) {
if ( supportsSequences() ) {
return "values next value for " + sequenceName;
}
else {
throw new MappingException( "Derby does not support sequence prior to release 10.6.1.0" );
}
public String getSelectClauseNullString(int sqlType) {
return DB2Dialect.selectNullString( sqlType );
}
@Override
public boolean supportsLimit() {
return isTenPointFiveReleaseOrNewer();
public String getFromDual() {
return "from (values 0) as dual";
}
@Override
@ -186,12 +331,6 @@ public class DerbyDialect extends DB2Dialect {
return false;
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimitOffset() {
return isTenPointFiveReleaseOrNewer();
}
@Override
public String getForUpdateString() {
return " for update with rs";
@ -207,88 +346,106 @@ public class DerbyDialect extends DB2Dialect {
return " for read only with rs";
}
@Override
public String getWriteLockString(String aliases, int timeout) {
return " for update of " + aliases + " with rs";
}
@Override
public boolean supportsOuterJoinForUpdate() {
//TODO: check this!
return false;
}
@Override
public boolean supportsExistsInSelect() {
//TODO: check this!
return false;
}
@Override
public boolean supportsLockTimeouts() {
//as far as I know, Derby doesn't support this
return false;
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public String getCurrentTimestampSelectString() {
return "values current timestamp";
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public LimitHandler getLimitHandler() {
return limitHandler;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new DB2IdentityColumnSupport();
}
@Override
public boolean supportsTuplesInSubqueries() {
//checked on Derby 10.14
return false;
}
/**
* {@inheritDoc}
* <p/>
* From Derby 10.5 Docs:
* <pre>
* Query
* [ORDER BY clause]
* [result offset clause]
* [fetch first clause]
* [FOR UPDATE clause]
* [WITH {RR|RS|CS|UR}]
* </pre>
*/
@Override
public String getLimitString(String query, final int offset, final int limit) {
final StringBuilder sb = new StringBuilder(query.length() + 50);
final String normalizedSelect = query.toLowerCase(Locale.ROOT).trim();
final int forUpdateIndex = normalizedSelect.lastIndexOf( "for update") ;
if ( hasForUpdateClause( forUpdateIndex ) ) {
sb.append( query.substring( 0, forUpdateIndex-1 ) );
}
else if ( hasWithClause( normalizedSelect ) ) {
sb.append( query.substring( 0, getWithIndex( query ) - 1 ) );
}
else {
sb.append( query );
}
if ( offset == 0 ) {
sb.append( " fetch first " );
}
else {
sb.append( " offset " ).append( offset ).append( " rows fetch next " );
}
sb.append( limit ).append( " rows only" );
if ( hasForUpdateClause( forUpdateIndex ) ) {
sb.append( ' ' );
sb.append( query.substring( forUpdateIndex ) );
}
else if ( hasWithClause( normalizedSelect ) ) {
sb.append( ' ' ).append( query.substring( getWithIndex( query ) ) );
}
return sb.toString();
public boolean doesReadCommittedCauseWritersToBlockReaders() {
//TODO: check this
return true;
}
@Override
public boolean supportsVariableLimit() {
// we bind the limit and offset values directly into the sql...
public boolean supportsParametersInInsertSelect() {
//TODO: check this
return true;
}
@Override
public boolean requiresCastingOfParametersInSelectClause() {
//checked on Derby 10.14
return true;
}
@Override
public boolean supportsEmptyInList() {
//checked on Derby 10.14
return false;
}
private boolean hasForUpdateClause(int forUpdateIndex) {
return forUpdateIndex >= 0;
@Override
public boolean supportsTupleDistinctCounts() {
//checked on Derby 10.14
return false;
}
private boolean hasWithClause(String normalizedSelect){
return normalizedSelect.startsWith( "with ", normalizedSelect.length() - 7 );
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.NUMERIC
? DecimalTypeDescriptor.INSTANCE
: super.getSqlTypeDescriptorOverride(sqlCode);
}
private int getWithIndex(String querySelect) {
int i = querySelect.lastIndexOf( "with " );
if ( i < 0 ) {
i = querySelect.lastIndexOf( "WITH " );
}
return i;
@Override
public String getNotExpression( String expression ) {
return "not (" + expression + ")";
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@ -301,72 +458,6 @@ public class DerbyDialect extends DB2Dialect {
return false;
}
private final class DerbyLimitHandler extends AbstractLimitHandler {
/**
* {@inheritDoc}
* <p/>
* From Derby 10.5 Docs:
* <pre>
* Query
* [ORDER BY clause]
* [result offset clause]
* [fetch first clause]
* [FOR UPDATE clause]
* [WITH {RR|RS|CS|UR}]
* </pre>
*/
@Override
public String processSql(String sql, RowSelection selection) {
final StringBuilder sb = new StringBuilder( sql.length() + 50 );
final String normalizedSelect = sql.toLowerCase(Locale.ROOT).trim();
final int forUpdateIndex = normalizedSelect.lastIndexOf( "for update" );
if (hasForUpdateClause( forUpdateIndex )) {
sb.append( sql.substring( 0, forUpdateIndex - 1 ) );
}
else if (hasWithClause( normalizedSelect )) {
sb.append( sql.substring( 0, getWithIndex( sql ) - 1 ) );
}
else {
sb.append( sql );
}
if (LimitHelper.hasFirstRow( selection )) {
sb.append( " offset " ).append( selection.getFirstRow() ).append( " rows fetch next " );
}
else {
sb.append( " fetch first " );
}
sb.append( getMaxOrLimit( selection ) ).append(" rows only" );
if (hasForUpdateClause( forUpdateIndex )) {
sb.append( ' ' );
sb.append( sql.substring( forUpdateIndex ) );
}
else if (hasWithClause( normalizedSelect )) {
sb.append( ' ' ).append( sql.substring( getWithIndex( sql ) ) );
}
return sb.toString();
}
@Override
public boolean supportsLimit() {
return isTenPointFiveReleaseOrNewer();
}
@Override
@SuppressWarnings("deprecation")
public boolean supportsLimitOffset() {
return isTenPointFiveReleaseOrNewer();
}
@Override
public boolean supportsVariableLimit() {
return false;
}
}
@Override
public IdentifierHelper buildIdentifierHelper(
IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException {
@ -381,7 +472,28 @@ public class DerbyDialect extends DB2Dialect {
return builder.build();
}
protected void registerDerbyKeywords() {
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
// final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if( "40XL1".equals( sqlState ) || "40XL2".equals( sqlState ) ) {
throw new LockTimeoutException( message, sqlException, sql );
}
return null;
}
};
}
@Override
public String translateDatetimeFormat(String format) {
throw new NotYetImplementedFor6Exception("format() function not supported on Derby");
}
private void registerDerbyKeywords() {
registerKeyword( "ADD" );
registerKeyword( "ALL" );
registerKeyword( "ALLOCATE" );

View File

@ -6,37 +6,18 @@
*/
package org.hibernate.dialect;
/**
* Hibernate Dialect for Cloudscape 10 - aka Derby. This implements both an
* override for the identity column generator as well as for the case statement
* issue documented at:
* http://www.jroller.com/comments/kenlars99/Weblog/cloudscape_soon_to_be_derby
* Dialect for Derby/Cloudscape 10.5
*
* @author Simon Johnston
* @author Scott Marlow
*
* @deprecated use {@code DerbyDialect(1050)}
*/
@SuppressWarnings("deprecation")
@Deprecated
public class DerbyTenFiveDialect extends DerbyDialect {
/**
* Constructs a DerbyTenFiveDialect
*/
public DerbyTenFiveDialect() {
super();
}
@Override
public boolean supportsSequences() {
return false;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return true;
super(1050);
}
}

View File

@ -6,24 +6,17 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
/**
* Dialect for Derby 10.7
*
* @author Strong Liu
*
* @deprecated use {@code DerbyDialect(1070)}
*/
public class DerbyTenSevenDialect extends DerbyTenSixDialect {
/**
* Constructs a DerbyTenSevenDialect
*/
public DerbyTenSevenDialect() {
super();
registerColumnType( Types.BOOLEAN, "boolean" );
}
@Deprecated
public class DerbyTenSevenDialect extends DerbyDialect {
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public DerbyTenSevenDialect() {
super(1070);
}
}

View File

@ -7,24 +7,18 @@
package org.hibernate.dialect;
/**
* Hibernate Dialect for Cloudscape 10 - aka Derby. This implements both an
* override for the identity column generator as well as for the case statement
* issue documented at:
* http://www.jroller.com/comments/kenlars99/Weblog/cloudscape_soon_to_be_derby
* Dialect for Derby/Cloudscape 10.6
*
* @author Simon Johnston
* @author Scott Marlow
*
* @deprecated use {@code DerbyDialect(1060)}
*/
public class DerbyTenSixDialect extends DerbyTenFiveDialect {
/**
* Constructs a DerbyTenSixDialect
*/
@Deprecated
public class DerbyTenSixDialect extends DerbyDialect {
public DerbyTenSixDialect() {
super();
super(1060);
}
@Override
public boolean supportsSequences() {
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,74 +6,590 @@
*/
package org.hibernate.dialect;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.FirebirdIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.pagination.SkipFirstLimitHandler;
import org.hibernate.dialect.sequence.FirebirdSequenceSupport;
import org.hibernate.dialect.sequence.InterbaseSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.query.CastType;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorFirebirdDatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceNameExtractorImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.hibernate.query.CastType.*;
import static org.hibernate.type.descriptor.DateTimeUtils.formatAsTimestampWithMillis;
/**
* An SQL dialect for Firebird.
* An SQL dialect for Firebird 2.0 and above.
*
* @author Reha CENANI
* @author Gavin King
* @author Mark Rotteveel
*/
public class FirebirdDialect extends InterbaseDialect {
public class FirebirdDialect extends Dialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return new StringBuilder( sql.length() + 20 )
.append( sql )
.insert( 6, hasOffset ? " first ? skip ?" : " first ?" )
.toString();
}
private final int version;
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersFirst() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
};
public int getVersion() {
return version;
}
public FirebirdDialect() {
this(250);
}
public FirebirdDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
// KNOWN LIMITATIONS:
// * no support for format()
// * extremely low maximum decimal precision (18)
// making BigInteger/BigDecimal support useless
// * can't select a parameter unless wrapped in a
// cast (not even when wrapped in a function call)
public FirebirdDialect(int version) {
super();
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop generator " + sequenceName;
this.version = version;
registerColumnType( Types.BIT, 1, "smallint" );
registerColumnType( Types.BIT, "smallint" );
if ( getVersion() < 300 ) {
//'boolean' type introduced in 3.0
registerColumnType( Types.BOOLEAN, "smallint" );
}
registerColumnType( Types.TINYINT, "smallint" );
// Note: according to the documentation, Firebird has
// just two floating point types:
// - single precision 'float' (32 bit), and
// - 'double precision' (64 bit).
// However, it turns out that Firebird actually supports
// the ANSI types 'real', 'float(p)', 'double precision'.
// So we don't override anything here.
//no precision for 'timestamp' type
registerColumnType( Types.TIMESTAMP, "timestamp" );
if ( getVersion() < 400 ) {
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
}
else {
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp with time zone" );
}
registerColumnType( Types.VARCHAR, 8_191, "varchar($l)" );
registerColumnType( Types.VARCHAR, "blob sub_type text" );
registerColumnType( Types.BINARY, 32_767, "char($l) character set octets" );
registerColumnType( Types.BINARY, "blob sub_type binary" );
registerColumnType( Types.VARBINARY, 32_765, "varchar($l) character set octets" );
registerColumnType( Types.VARBINARY, "blob sub_type binary" );
registerColumnType( Types.BLOB, "blob sub_type binary" );
registerColumnType( Types.CLOB, "blob sub_type text" );
registerColumnType( Types.NCLOB, "blob sub_type text" ); // Firebird doesn't have NCLOB, but Jaybird emulates NCLOB support
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
return new StringBuilder( sql.length() + 20 )
.append( sql )
.insert( 6, hasOffset ? " first ? skip ?" : " first ?" )
.toString();
public int getPreferredSqlTypeCodeForBoolean() {
return getVersion() < 300
? Types.BIT
: super.getPreferredSqlTypeCodeForBoolean();
}
@Override
public boolean bindLimitParametersFirst() {
public String getTypeName(int code, Size size) throws HibernateException {
//precision of a Firebird 'float(p)' represents
//decimal digits instead of binary digits
return super.getTypeName( code, binaryToDecimalPrecision( code, size ) );
}
@Override
public int getFloatPrecision() {
return 21; // -> 7 decimal digits
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.sinh( queryEngine );
CommonFunctionFactory.tanh( queryEngine );
CommonFunctionFactory.cosh( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.substringFromFor( queryEngine );
CommonFunctionFactory.overlay( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.bitandorxornot_binAndOrXorNot( queryEngine );
CommonFunctionFactory.leastGreatest_minMaxValue( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
//TODO: lots more statistical functions
//TODO: gen_uid() and friends, gen_id()
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
).setArgumentListSignature("(pattern, string[, start])");
}
/**
* Firebird 2.5 doesn't have a real {@link java.sql.Types#BOOLEAN}
* type, so...
*/
@Override
public String castPattern(CastType from, CastType to) {
if ( to==BOOLEAN
&& (from==LONG || from==INTEGER)) {
return "(0<>?1)";
}
if ( getVersion() < 300 ) {
if ( to==BOOLEAN && from==STRING ) {
// return "iif(lower(?1) similar to 't|f|true|false', lower(?1) like 't%', null)";
return "decode(lower(?1),'t',1,'f',0,'true',1,'false',0)";
}
if ( to==STRING && from==BOOLEAN ) {
return "trim(decode(?1,0,'false','true'))";
}
}
else {
if ( from==BOOLEAN
&& (to==LONG || to==INTEGER)) {
return "decode(?1,false,0,true,1)";
}
}
return super.castPattern( from, to );
}
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000_000; //milliseconds
}
/**
* Firebird extract() function returns {@link TemporalUnit#DAY_OF_WEEK}
* numbered from 0 to 6, and {@link TemporalUnit#DAY_OF_YEAR} numbered
* for 0. This isn't consistent with what most other databases do, so
* here we adjust the result by generating {@code (extract(unit,arg)+1))}.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_WEEK:
case DAY_OF_YEAR:
return "(" + super.extractPattern(unit) + "+1)";
default:
return super.extractPattern(unit);
}
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NATIVE:
return "dateadd((?2) millisecond to ?3)";
case NANOSECOND:
return "dateadd((?2)/1e6 millisecond to ?3)";
case WEEK:
return "dateadd((?2)*7 day to ?3)";
case QUARTER:
return "dateadd((?2)*4 month to ?3)";
default:
return "dateadd(?2 ?1 to ?3)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NATIVE:
return "datediff(millisecond from ?2 to ?3)";
case NANOSECOND:
return "datediff(millisecond from ?2 to ?3)*1e6";
case WEEK:
return "datediff(day from ?2 to ?3)/7";
case QUARTER:
return "datediff(month from ?2 to ?3)/4";
default:
return "datediff(?1 from ?2 to ?3)";
}
}
@Override
public int getDefaultDecimalPrecision() {
//the extremely low maximum
return 18;
}
@Override
public String getAddColumnString() {
return "add";
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
public String getNoColumnsInsertString() {
return "default values";
}
@Override
public int getMaxAliasLength() {
return 20;
}
public IdentifierHelper buildIdentifierHelper(
IdentifierHelperBuilder builder,
DatabaseMetaData dbMetaData) throws SQLException {
// Any use of keywords as identifiers will result in token unknown error, so enable auto quote always
builder.setAutoQuoteKeywords( true );
return super.buildIdentifierHelper( builder, dbMetaData );
}
@Override
public boolean canCreateSchema() {
return false;
}
@Override
public String[] getCreateSchemaCommand(String schemaName) {
throw new UnsupportedOperationException( "No create schema syntax supported by " + getClass().getName() );
}
@Override
public String[] getDropSchemaCommand(String schemaName) {
throw new UnsupportedOperationException( "No drop schema syntax supported by " + getClass().getName() );
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public boolean supportsCommentOn() {
return getVersion() >= 200;
}
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean requiresCastingOfParametersInSelectClause() {
return true;
}
@Override
public boolean supportsLobValueChangePropogation() {
// May need changes in Jaybird for this to work
return false;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
// Blob ids are only guaranteed to work in the same transaction
return false;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public int getInExpressionCountLimit() {
// see http://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-commons-predicates.html#fblangref25-commons-in
return 1500;
}
@Override
public boolean supportsTuplesInSubqueries() {
return false;
}
@Override
public boolean supportsExistsInSelect() {
return getVersion() >= 300;
}
@Override
public boolean supportsPartitionBy() {
return getVersion() >= 300;
}
@Override
public String toBooleanValueString(boolean bool) {
//'boolean' type introduced in 3.0
return getVersion() < 300
? super.toBooleanValueString( bool )
: bool ? "true" : "false";
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return getVersion() < 300
? super.getIdentityColumnSupport()
: new FirebirdIdentityColumnSupport();
}
@Override
public SequenceSupport getSequenceSupport() {
if ( getVersion() < 200 ) {
return InterbaseSequenceSupport.INSTANCE;
}
else if ( getVersion() < 300 ) {
return FirebirdSequenceSupport.LEGACY_INSTANCE;
}
else {
return FirebirdSequenceSupport.INSTANCE;
}
}
@Override
public String getQuerySequencesString() {
return getVersion() < 300
? "select rdb$generator_name from rdb$generators"
// Note: currently has an 'off by increment' bug, see
// http://tracker.firebirdsql.org/browse/CORE-6084
// May need revision depending on the final solution
// The second column might need to be changed to
// rdb$initial_value + rdb$generator_increment
: "select rdb$generator_name, rdb$initial_value, rdb$generator_increment from rdb$generators";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return getVersion() < 300
? SequenceNameExtractorImpl.INSTANCE
: SequenceInformationExtractorFirebirdDatabaseImpl.INSTANCE;
}
@Override
public String getForUpdateString() {
// locking only happens on fetch
// ('for update' would force Firebird to return a single row per fetch)
return " with lock";
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
return getVersion() < 300
? SkipFirstLimitHandler.INSTANCE
: OffsetFetchLimitHandler.INSTANCE;
}
@Override
public String getSelectGUIDString() {
return getVersion() < 210
? super.getSelectGUIDString()
: "select uuid_to_char(gen_uuid()) " + getFromDual();
}
@Override
public boolean supportsLockTimeouts() {
// Lock timeouts are only supported when specified as part of the transaction
return false;
}
@Override
public boolean supportsOuterJoinForUpdate() {
// "WITH LOCK can only be used with a top-level, single-table SELECT statement"
// https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html#fblangref25-dml-with-lock
return false;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp " + getFromDual();
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getFromDual() {
return "from rdb$database";
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "yearday";
case DAY_OF_WEEK: return "weekday";
default: return super.translateExtractField( unit );
}
}
@Override
protected String formatAsTimestamp(Date date) {
return formatAsTimestampWithMillis(date);
}
@Override
protected String formatAsTimestamp(Calendar calendar) {
return formatAsTimestampWithMillis(calendar);
}
@Override
protected String formatAsTimestamp(TemporalAccessor temporalAccessor) {
return formatAsTimestampWithMillis(temporalAccessor);
}
@Override
public String translateDatetimeFormat(String format) {
throw new NotYetImplementedFor6Exception("format() function not supported on Firebird");
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
private static final ViolatedConstraintNameExtracter EXTRACTER = new ViolatedConstraintNameExtracter() {
final Pattern foreignUniqueOrPrimaryKeyPattern = Pattern.compile( "violation of .+? constraint \"([^\"]+)\"" );
final Pattern checkConstraintPattern = Pattern.compile(
"Operation violates CHECK constraint (.+?) on view or table" );
@Override
public String extractConstraintName(SQLException sqle) {
String message = sqle.getMessage();
if ( message != null ) {
Matcher foreignUniqueOrPrimaryKeyMatcher =
foreignUniqueOrPrimaryKeyPattern.matcher( message );
if ( foreignUniqueOrPrimaryKeyMatcher.find() ) {
return foreignUniqueOrPrimaryKeyMatcher.group( 1 );
}
Matcher checkConstraintMatcher = checkConstraintPattern.matcher( message );
if ( checkConstraintMatcher.find() ) {
return checkConstraintMatcher.group( 1 );
}
}
return null;
}
};
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
final String sqlExceptionMessage = sqlException.getMessage();
//final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
// Some of the error codes will only surface in Jaybird 3 or higher, as older versions return less specific error codes first
switch ( errorCode ) {
case 335544336:
// isc_deadlock (deadlock, note: not necessarily a deadlock, can also be an update conflict)
if (sqlExceptionMessage != null
&& sqlExceptionMessage.contains( "update conflicts with concurrent update" )) {
return new LockTimeoutException( message, sqlException, sql );
}
return new LockAcquisitionException( message, sqlException, sql );
case 335544345:
// isc_lock_conflict (lock conflict on no wait transaction)
case 335544510:
// isc_lock_timeout (lock time-out on wait transaction)
return new LockTimeoutException( message, sqlException, sql );
case 335544474:
// isc_bad_lock_level (invalid lock level {0})
case 335544475:
// isc_relation_lock (lock on table {0} conflicts with existing lock)
case 335544476:
// isc_record_lock (requested record lock conflicts with existing lock)
return new LockAcquisitionException( message, sqlException, sql );
case 335544466:
// isc_foreign_key (violation of FOREIGN KEY constraint "{0}" on table "{1}")
case 336396758:
// *no error name* (violation of FOREIGN KEY constraint "{0}")
case 335544558:
// isc_check_constraint (Operation violates CHECK constraint {0} on view or table {1})
case 336396991:
// *no error name* (Operation violates CHECK constraint {0} on view or table)
case 335544665:
// isc_unique_key_violation (violation of PRIMARY or UNIQUE KEY constraint "{0}" on table "{1}")
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName(
sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
}
// Apply heuristics based on exception message
String exceptionMessage = sqlException.getMessage();
if ( exceptionMessage != null ) {
if ( exceptionMessage.contains( "violation of " )
|| exceptionMessage.contains( "violates CHECK constraint" ) ) {
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName(
sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
}
}
return null;
}
};
}
}

View File

@ -5,19 +5,13 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.lock.*;
import org.hibernate.persister.entity.Lockable;
import java.sql.Types;
/**
* An SQL Dialect for Frontbase. Assumes you're using the latest version
* of the FrontBase JDBC driver, available from <tt>http://frontbase.com/</tt>
@ -42,27 +36,21 @@ public class FrontBaseDialect extends Dialect {
public FrontBaseDialect() {
super();
registerColumnType( Types.BIT, "bit" );
registerColumnType( Types.BOOLEAN, "bit" );
registerColumnType( Types.BIGINT, "longint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double precision" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
//FrontBase has no 'binary' nor 'varbinary'
registerColumnType( Types.BINARY, "bit($l)");
registerColumnType( Types.VARBINARY, "bit varying($l)");
//no precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "bit varying($l)" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.BLOB, "blob" );
registerColumnType( Types.CLOB, "clob" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp with time zone" );
}
@Override
public String getAddColumnString() {
return "add column";
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
@ -99,22 +87,19 @@ public class FrontBaseDialect extends Dialect {
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// Frontbase has no known variation of a "SELECT ... FOR UPDATE" syntax...
if ( lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode);
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_WRITE) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_READ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC) {
return new OptimisticLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC_FORCE_INCREMENT) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode);
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {

View File

@ -6,23 +6,20 @@
*/
package org.hibernate.dialect;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.JDBCException;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.H2ExtractEmulation;
import org.hibernate.dialect.function.Replacer;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.H2SequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
@ -30,7 +27,6 @@ import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
@ -40,12 +36,13 @@ import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.jboss.logging.Logger;
import java.sql.SQLException;
import static org.hibernate.query.TemporalUnit.SECOND;
/**
* A dialect compatible with the H2 database.
*
@ -57,90 +54,63 @@ public class H2Dialect extends Dialect {
H2Dialect.class.getName()
);
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return sql + (hasOffset ? " limit ? offset ?" : " limit ?");
}
private final LimitHandler limitHandler;
@Override
public boolean supportsLimit() {
return true;
}
private final boolean dropConstraints;
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
};
// private final String querySequenceString;
// private final SequenceInformationExtractor sequenceInformationExtractor;
private final String querySequenceString;
private final SequenceInformationExtractor sequenceInformationExtractor;
/**
* Constructs a H2Dialect
*/
public H2Dialect() {
this(0, 0);
}
public H2Dialect(int version, int buildId) {
super();
int buildId = Integer.MIN_VALUE;
limitHandler = !( version > 140 || buildId >= 199 )
? LimitOffsetLimitHandler.INSTANCE
: OffsetFetchLimitHandler.INSTANCE;
try {
// HHH-2300
final Class h2ConstantsClass = ReflectHelper.classForName( "org.h2.engine.Constants" );
final int majorVersion = (Integer) h2ConstantsClass.getDeclaredField( "VERSION_MAJOR" ).get( null );
final int minorVersion = (Integer) h2ConstantsClass.getDeclaredField( "VERSION_MINOR" ).get( null );
buildId = (Integer) h2ConstantsClass.getDeclaredField( "BUILD_ID" ).get( null );
// if ( buildId >= 32 ) {
// this.sequenceInformationExtractor = SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
// this.querySequenceString = "select * from information_schema.sequences";
// }
// else {
// this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
// this.querySequenceString = null;
// }
if ( ! ( majorVersion > 1 || minorVersion > 2 || buildId >= 139 ) ) {
LOG.unsupportedMultiTableBulkHqlJpaql( majorVersion, minorVersion, buildId );
}
}
catch ( Exception e ) {
// probably H2 not in the classpath, though in certain app server environments it might just mean we are
// not using the correct classloader
LOG.undeterminedH2Version();
//Note: H2 'bit' is a synonym for 'boolean', not a proper bit type
// registerColumnType( Types.BIT, "bit" );
if ( !( version > 120 || buildId >= 139 ) ) {
LOG.unsupportedMultiTableBulkHqlJpaql( version / 100, version % 100 / 10, buildId );
}
if ( buildId >= 32 ) {
this.sequenceInformationExtractor = SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
this.querySequenceString = "select * from INFORMATION_SCHEMA.SEQUENCES";
}
else {
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
this.querySequenceString = null;
}
registerColumnType( Types.BOOLEAN, "boolean" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.BINARY, "binary" );
registerColumnType( Types.BIT, "boolean" );
registerColumnType( Types.CHAR, "char($l)" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.LONGVARBINARY, "longvarbinary" );
// H2 does define "longvarchar", but it is a simple alias to "varchar"
registerColumnType( Types.LONGVARCHAR, String.format( "varchar(%d)", Integer.MAX_VALUE ) );
registerColumnType( Types.REAL, "real" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.VARBINARY, "binary($l)" );
registerColumnType( Types.BLOB, "blob" );
registerColumnType( Types.CLOB, "clob" );
// Prior to 1.4.200 we didn't need to drop constraints before
// dropping tables, that just lead to error messages about
// missing tables when we don't have a schema in the database
dropConstraints = version > 140 && buildId >= 200;
getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
// http://code.google.com/p/h2database/issues/detail?id=235
getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" );
}
private static int parseBuildId(DialectResolutionInfo info) {
String[] bits = info.getDatabaseVersion().split("[. ]");
return bits.length > 2 ? Integer.parseInt( bits[2] ) : 0;
}
public H2Dialect(DialectResolutionInfo info) {
this(
info.getDatabaseMajorVersion()*100
+ info.getDatabaseMinorVersion()*10,
parseBuildId( info )
);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
@ -157,12 +127,12 @@ public class H2Dialect extends Dialect {
CommonFunctionFactory.bitand( queryEngine );
CommonFunctionFactory.bitor( queryEngine );
CommonFunctionFactory.bitxor( queryEngine );
CommonFunctionFactory.bitAndOr( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.dayOfWeekMonthYear( queryEngine );
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.daynameMonthname( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
@ -171,87 +141,51 @@ public class H2Dialect extends Dialect {
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.trim1( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.formatdatetime( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.nowCurdateCurtime( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
CommonFunctionFactory.insert( queryEngine );
// CommonFunctionFactory.everyAny( queryEngine ); //this would work too
CommonFunctionFactory.everyAny_boolAndOr( queryEngine );
CommonFunctionFactory.median( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.format_formatdatetime( queryEngine );
CommonFunctionFactory.rownum( queryEngine );
}
queryEngine.getSqmFunctionRegistry().register( "extract", new H2ExtractEmulation() );
/**
* In H2, the extract() function does not return
* fractional seconds for the the field
* {@link TemporalUnit#SECOND}. We work around
* this here with two calls to extract().
*/
@Override
public String extractPattern(TemporalUnit unit) {
return unit == SECOND
? "(" + super.extractPattern(unit) + "+extract(nanosecond from ?2)/1e9)"
: super.extractPattern(unit);
}
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "rownum" )
.setInvariantType( StandardBasicTypes.LONG )
.setUseParenthesesWhenNoArgs(true)
.register();
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
return "dateadd(?1, ?2, ?3)";
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("dateadd(");
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
magnitude.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
sqlAppender.append("datediff(");
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case WEEK: return "iso_week";
default: return unit.toString();
}
}
@Override
public String translateDatetimeFormat(String format) {
return new Replacer( format, "'", "''" ).replace( "e", "u").result(); //NICE!!
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getForUpdateString() {
return " for update";
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
return "datediff(?1, ?2, ?3)";
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
return sql + (hasOffset ? " limit ? offset ?" : " limit ?");
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public boolean bindLimitParametersFirst() {
return false;
return limitHandler;
}
@Override
@ -259,49 +193,47 @@ public class H2Dialect extends Dialect {
return true;
}
@Override
public boolean supportsIfExistsAfterAlterTable() {
return dropConstraints;
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return true;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence if exists " + sequenceName;
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "next value for " + sequenceName;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "call next value for " + sequenceName;
public SequenceSupport getSequenceSupport() {
return H2SequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return querySequenceString;
return "select * from information_schema.sequences";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return sequenceInformationExtractor;
return SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
}
@Override
public String getFromDual() {
return "from dual";
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType entityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( entityDescriptor, basename -> "HT_" + basename ),
this::getTypeName,
AfterUseAction.CLEAN,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
@ -341,20 +273,17 @@ public class H2Dialect extends Dialect {
public JDBCException convert(SQLException sqlException, String message, String sql) {
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if (40001 == errorCode) {
// DEADLOCK DETECTED
return new LockAcquisitionException(message, sqlException, sql);
}
if (50200 == errorCode) {
// LOCK NOT AVAILABLE
return new PessimisticLockException(message, sqlException, sql);
}
if ( 90006 == errorCode ) {
// NULL not allowed for column [90006-145]
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
switch (errorCode) {
case 40001:
// DEADLOCK DETECTED
return new LockAcquisitionException(message, sqlException, sql);
case 50200:
// LOCK NOT AVAILABLE
return new PessimisticLockException(message, sqlException, sql);
case 90006:
// NULL not allowed for column [90006-145]
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName(sqlException);
return new ConstraintViolationException(message, sqlException, sql, constraintName);
}
return null;
@ -364,19 +293,6 @@ public class H2Dialect extends Dialect {
return delegate;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType entityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( entityDescriptor, basename -> "HT_" + basename ),
this::getTypeName,
AfterUseAction.CLEAN,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
@ -423,9 +339,7 @@ public class H2Dialect extends Dialect {
@Override
public boolean dropConstraints() {
// We don't need to drop constraints before dropping tables, that just leads to error
// messages about missing tables when we don't have a schema in the database
return false;
return dropConstraints;
}
@Override
@ -439,8 +353,16 @@ public class H2Dialect extends Dialect {
}
@Override
public boolean supportsSelectAliasInGroupByClause() {
return true;
public String translateDatetimeFormat(String format) {
return new Replacer( format, "'", "''" ).replace("e", "u").result(); //NICE!!
}
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case WEEK: return "iso_week";
default: return unit.toString();
}
}
}

View File

@ -32,6 +32,10 @@ import org.hibernate.type.StandardBasicTypes;
*/
public class HANAColumnStoreDialect extends AbstractHANADialect {
public HANAColumnStoreDialect() {
super();
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
@ -40,9 +44,9 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
queryEngine.getSqmFunctionRegistry().registerNamed( "score", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "snippets" );
queryEngine.getSqmFunctionRegistry().registerNamed( "highlighted" );
queryEngine.getSqmFunctionRegistry().registerVarArgs( "contains", StandardBasicTypes.BOOLEAN, "contains(", ",", ") /*" );
queryEngine.getSqmFunctionRegistry().registerPattern( "contains_rhs", "*/", StandardBasicTypes.BOOLEAN );
queryEngine.getSqmFunctionRegistry().registerVarArgs( "not_contains", StandardBasicTypes.BOOLEAN, "not_contains(", ",", ") /*" );
// queryEngine.getSqmFunctionRegistry().registerVarArgs( "contains", StandardSpiBasicTypes.BOOLEAN, "contains(", ",", ") /*" );
// queryEngine.getSqmFunctionRegistry().registerPattern( "contains_rhs", "*/", StandardSpiBasicTypes.BOOLEAN );
// queryEngine.getSqmFunctionRegistry().registerVarArgs( "not_contains", StandardSpiBasicTypes.BOOLEAN, "not_contains(", ",", ") /*" );
}
@Override

View File

@ -6,32 +6,23 @@
*/
package org.hibernate.dialect;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.StaleObjectStateException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.HSQLIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadSelectLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.lock.*;
import org.hibernate.dialect.pagination.LegacyHSQLLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.HSQLSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
@ -41,132 +32,103 @@ import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.CastType;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorHSQLDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.jboss.logging.Logger;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import static org.hibernate.query.CastType.*;
/**
* An SQL dialect compatible with HSQLDB (HyperSQL).
* <p/>
* Note this version supports HSQLDB version 1.8 and higher, only.
* <p/>
* Enhancements to version 3.5.0 GA to provide basic support for both HSQLDB 1.8.x and 2.x
* Does not works with Hibernate 3.2 - 3.4 without alteration.
* An SQL dialect compatible with HyperSQL (HSQLDB) version 1.8 and above.
*
* @author Christoph Sturm
* @author Phillip Baird
* @author Fred Toussi
*/
@SuppressWarnings("deprecation")
public class HSQLDialect extends Dialect {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
HSQLDialect.class.getName()
);
private final class HSQLLimitHandler extends AbstractLimitHandler {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
if ( hsqldbVersion < 200 ) {
return new StringBuilder( sql.length() + 10 )
.append( sql )
.insert(
sql.toLowerCase(Locale.ROOT).indexOf( "select" ) + 6,
hasOffset ? " limit ? ?" : " top ?"
)
.toString();
}
else {
return sql + (hasOffset ? " offset ? limit ?" : " limit ?");
}
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersFirst() {
return hsqldbVersion < 200;
}
}
/**
* version is 180 for 1.8.0 or 200 for 2.0.0
*/
private int hsqldbVersion = 180;
private final LimitHandler limitHandler;
private final int version;
int getVersion() {
return version;
}
public HSQLDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion()*100 + info.getDatabaseMinorVersion()*10 );
}
/**
* Constructs a HSQLDialect
*/
public HSQLDialect() {
this(180);
}
public HSQLDialect(int version) {
super();
try {
final Class props = ReflectHelper.classForName( "org.hsqldb.persist.HsqlDatabaseProperties" );
final String versionString = (String) props.getDeclaredField( "THIS_VERSION" ).get( null );
hsqldbVersion = Integer.parseInt( versionString.substring( 0, 1 ) ) * 100;
hsqldbVersion += Integer.parseInt( versionString.substring( 2, 3 ) ) * 10;
hsqldbVersion += Integer.parseInt( versionString.substring( 4, 5 ) );
}
catch ( Throwable e ) {
// must be a very old version
if ( version == 180 ) {
version = reflectedVersion(version);
}
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.BINARY, "binary($l)" );
registerColumnType( Types.BIT, "bit" );
registerColumnType( Types.BOOLEAN, "boolean" );
registerColumnType( Types.CHAR, "char($l)" );
registerColumnType( Types.DATE, "date" );
this.version = version;
registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.LONGVARBINARY, "longvarbinary" );
registerColumnType( Types.LONGVARCHAR, "longvarchar" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.VARBINARY, "varbinary($l)" );
//Note that all floating point types are synonyms for 'double'
//HSQL has actual types called 'longvarchar' and
//'longvarbinary', which one must suppose are meant
//to be used for this purpose
registerColumnType( Types.LONGVARCHAR, "longvarchar" ); //synonym for 'varchar(16M)'
registerColumnType( Types.LONGVARBINARY, "longvarbinary" ); //synonym for 'varbinary(16M)'
//HSQL has no 'nclob' type, but 'clob' is Unicode
//(See HHH-10364)
registerColumnType( Types.NCLOB, "clob" );
if ( hsqldbVersion < 200 ) {
if ( this.version < 200 ) {
//Older versions of HSQL did not accept
//precision for the 'numeric' type
registerColumnType( Types.NUMERIC, "numeric" );
}
else {
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
}
//HSQL has no Blob/Clob support .... but just put these here for now!
if ( hsqldbVersion < 200 ) {
//Older versions of HSQL had no lob support
registerColumnType( Types.BLOB, "longvarbinary" );
registerColumnType( Types.CLOB, "longvarchar" );
}
else {
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
if ( this.version >= 250 ) {
registerKeyword( "period" );
}
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
limitHandler = new HSQLLimitHandler();
}
private static int reflectedVersion(int version) {
try {
final Class props = ReflectHelper.classForName("org.hsqldb.persist.HsqlDatabaseProperties");
final String versionString = (String) props.getDeclaredField("THIS_VERSION").get( null );
return Integer.parseInt( versionString.substring(0, 1) ) * 100
+ Integer.parseInt( versionString.substring(2, 3) ) * 10
+ Integer.parseInt( versionString.substring(4, 5) );
}
catch (Throwable e) {
// might be a very old version, or not accessible in class path
return version;
}
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
@ -196,110 +158,97 @@ public class HSQLDialect extends Dialect {
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.trim1( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.nowCurdateCurtime( queryEngine );
CommonFunctionFactory.insert( queryEngine );
CommonFunctionFactory.overlay( queryEngine );
CommonFunctionFactory.median( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
if ( hsqldbVersion >= 200 ) {
if ( version >= 200 ) {
//SYSDATE is similar to LOCALTIMESTAMP but it returns the timestamp when it is called
CommonFunctionFactory.sysdateSystimestamp( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
}
// from v. 2.2.0 ROWNUM() is supported in all modes as the equivalent of Oracle ROWNUM
if ( hsqldbVersion > 219 ) {
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "rownum" )
.setInvariantType( StandardBasicTypes.LONG )
.setUseParenthesesWhenNoArgs(true)
.register();
if ( version > 219 ) {
CommonFunctionFactory.rownum( queryEngine );
}
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
public String castPattern(CastType from, CastType to) {
if ( from== BOOLEAN
&& (to== INTEGER || to== LONG)) {
return "casewhen(?1,1,0)";
}
return super.castPattern( from, to );
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
StringBuilder pattern = new StringBuilder();
boolean castTo = !timestamp && !unit.isDateUnit();
if ( unit == NANOSECOND ) {
sqlAppender.append("timestampadd(sql_tsi_frac_second"); //nanos
switch (unit) {
case NANOSECOND:
case NATIVE:
pattern.append("timestampadd(sql_tsi_frac_second"); //nanos
break;
default:
pattern.append("dateadd(?1");
}
pattern.append(", ?2, ");
if (castTo) {
pattern.append("cast(?3 as timestamp)");
}
else {
sqlAppender.append("dateadd(");
sqlAppender.append( unit.toString() );
pattern.append("?3");
}
sqlAppender.append(", ");
magnitude.render();
sqlAppender.append(", ");
if (castTo) {
sqlAppender.append("cast(");
}
to.render();
if (castTo) {
sqlAppender.append(" as timestamp)");
}
sqlAppender.append(")");
pattern.append(")");
return pattern.toString();
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
StringBuilder pattern = new StringBuilder();
boolean castFrom = !fromTimestamp && !unit.isDateUnit();
boolean castTo = !toTimestamp && !unit.isDateUnit();
if ( unit == NANOSECOND ) {
sqlAppender.append("timestampdiff(sql_tsi_frac_second"); //nanos
switch (unit) {
case NANOSECOND:
case NATIVE:
pattern.append("timestampdiff(sql_tsi_frac_second"); //nanos
break;
default:
pattern.append("datediff(?1");
}
pattern.append(", ");
if (castFrom) {
pattern.append("cast(?2 as timestamp)");
}
else {
sqlAppender.append("datediff(");
sqlAppender.append( unit.toString() );
pattern.append("?2");
}
sqlAppender.append(", ");
if (castFrom) {
sqlAppender.append("cast(");
}
from.render();
if (castFrom) {
sqlAppender.append(" as timestamp)");
}
sqlAppender.append(", ");
pattern.append(", ");
if (castTo) {
sqlAppender.append("cast(");
pattern.append("cast(?3 as timestamp)");
}
to.render();
if (castTo) {
sqlAppender.append(" as timestamp)");
else {
pattern.append("?3");
}
sqlAppender.append(")");
}
@Override
public String translateDatetimeFormat(String format) {
return Oracle8iDialect.datetimeFormat(format, false)
.replace("SSSSSS", "FF")
.replace("SSSSS", "FF")
.replace("SSSS", "FF")
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
//TODO: does not support MICROSECOND, but on the
// other hand it doesn't support microsecond
// precision in timestamps either so who cares?
switch (unit) {
case WEEK: return "week_of_year"; //this is the ISO week number, I believe
default: return unit.toString();
}
}
@Override
public String getAddColumnString() {
return "add column";
pattern.append(")");
return pattern.toString();
}
@Override
@ -309,7 +258,7 @@ public class HSQLDialect extends Dialect {
@Override
public String getForUpdateString() {
if ( hsqldbVersion >= 200 ) {
if ( version >= 200 ) {
return " for update";
}
else {
@ -319,37 +268,13 @@ public class HSQLDialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
return limitHandler;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
if ( hsqldbVersion < 200 ) {
return new StringBuilder( sql.length() + 10 )
.append( sql )
.insert(
sql.toLowerCase(Locale.ROOT).indexOf( "select" ) + 6,
hasOffset ? " limit ? ?" : " top ?"
)
.toString();
}
else {
return sql + (hasOffset ? " offset ? limit ?" : " limit ?");
}
}
@Override
public boolean bindLimitParametersFirst() {
return hsqldbVersion < 200;
return version < 200 ? LegacyHSQLLimitHandler.INSTANCE
: version < 250 ? LimitOffsetLimitHandler.INSTANCE
: OffsetFetchLimitHandler.INSTANCE;
}
// Note : HSQLDB actually supports [IF EXISTS] before AND after the <tablename>
// But as CASCADE has to be AFTER IF EXISTS in case it's after the tablename,
// But as CASCADE has to be AFTER IF EXISTS in case it's after the tablename,
// We put the IF EXISTS before the tablename to be able to add CASCADE after.
@Override
public boolean supportsIfExistsAfterTableName() {
@ -363,53 +288,12 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsColumnCheck() {
return hsqldbVersion >= 200;
return version >= 200;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
/**
* HSQL will start with 0, by default. In order for Hibernate to know that this not transient,
* manually start with 1.
*/
@Override
protected String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName + " start with 1";
}
/**
* Because of the overridden {@link #getCreateSequenceString(String)}, we must also override
* {@link #getCreateSequenceString(String, int, int)} to prevent 2 instances of "start with".
*/
@Override
protected String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) throws MappingException {
if ( supportsPooledSequences() ) {
return "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize;
}
throw new MappingException( getClass().getName() + " does not support pooled sequences" );
}
@Override
protected String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName + " if exists";
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "next value for " + sequenceName;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "call next value for " + sequenceName;
public SequenceSupport getSequenceSupport() {
return HSQLSequenceSupport.INSTANCE;
}
@Override
@ -423,40 +307,45 @@ public class HSQLDialect extends Dialect {
return SequenceInformationExtractorHSQLDBDatabaseImpl.INSTANCE;
}
@Override
public String getFromDual() {
return "from (values(0))";
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return hsqldbVersion < 200 ? EXTRACTER_18 : EXTRACTER_20;
return version < 200 ? EXTRACTER_18 : EXTRACTER_20;
}
private static final ViolatedConstraintNameExtracter EXTRACTER_18 = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle );
if ( errorCode == -8 ) {
constraintName = extractUsingTemplate(
"Integrity constraint violation ", " table:", sqle.getMessage()
);
switch (errorCode) {
case -8:
return extractUsingTemplate(
"Integrity constraint violation ", " table:",
sqle.getMessage()
);
case -9:
return extractUsingTemplate(
"Violation of unique index: ", " in statement [",
sqle.getMessage()
);
case -104:
return extractUsingTemplate(
"Unique constraint violation: ", " in statement [",
sqle.getMessage()
);
case -177:
return extractUsingTemplate(
"Integrity constraint violation - no parent ", " table:",
sqle.getMessage()
);
}
else if ( errorCode == -9 ) {
constraintName = extractUsingTemplate(
"Violation of unique index: ", " in statement [", sqle.getMessage()
);
}
else if ( errorCode == -104 ) {
constraintName = extractUsingTemplate(
"Unique constraint violation: ", " in statement [", sqle.getMessage()
);
}
else if ( errorCode == -177 ) {
constraintName = extractUsingTemplate(
"Integrity constraint violation - no parent ", " table:",
sqle.getMessage()
);
}
return constraintName;
return null;
}
};
@ -468,31 +357,32 @@ public class HSQLDialect extends Dialect {
private static final ViolatedConstraintNameExtracter EXTRACTER_20 = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle );
if ( errorCode == -8 ) {
constraintName = extractUsingTemplate(
"; ", " table: ", sqle.getMessage()
);
switch (errorCode) {
case -8:
return extractUsingTemplate(
"; ", " table: ",
sqle.getMessage()
);
case -9:
return extractUsingTemplate(
"; ", " table: ",
sqle.getMessage()
);
case -104:
return extractUsingTemplate(
"; ", " table: ",
sqle.getMessage()
);
case -177:
return extractUsingTemplate(
"; ", " table: ",
sqle.getMessage()
);
}
else if ( errorCode == -9 ) {
constraintName = extractUsingTemplate(
"; ", " table: ", sqle.getMessage()
);
}
else if ( errorCode == -104 ) {
constraintName = extractUsingTemplate(
"; ", " table: ", sqle.getMessage()
);
}
else if ( errorCode == -177 ) {
constraintName = extractUsingTemplate(
"; ", " table: ", sqle.getMessage()
);
}
return constraintName;
return null;
}
};
@ -520,6 +410,7 @@ public class HSQLDialect extends Dialect {
literal = "cast(null as date)";
break;
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
literal = "cast(null as timestamp)";
break;
case Types.BOOLEAN:
@ -621,12 +512,6 @@ public class HSQLDialect extends Dialect {
return "call current_timestamp";
}
@Override
public String getCurrentTimestampSQLFunctionName() {
// the standard SQL function name is current_timestamp...
return "current_timestamp";
}
/**
* For HSQLDB 2.0, this is a copy of the base class implementation.
* For HSQLDB 1.8, only READ_UNCOMMITTED is supported.
@ -635,23 +520,19 @@ public class HSQLDialect extends Dialect {
*/
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode );
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteSelectLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadSelectLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
else if ( lockMode == LockMode.PESSIMISTIC_WRITE ) {
return new PessimisticWriteSelectLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.PESSIMISTIC_READ ) {
return new PessimisticReadSelectLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC ) {
return new OptimisticLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT ) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode );
}
if ( hsqldbVersion < 200 ) {
if ( version < 200 ) {
return new ReadUncommittedLockingStrategy( lockable, lockMode );
}
else {
@ -660,7 +541,7 @@ public class HSQLDialect extends Dialect {
}
private static class ReadUncommittedLockingStrategy extends SelectLockingStrategy {
public ReadUncommittedLockingStrategy(Lockable lockable, LockMode lockMode) {
private ReadUncommittedLockingStrategy(Lockable lockable, LockMode lockMode) {
super( lockable, lockMode );
}
@ -676,7 +557,7 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsCommentOn() {
return hsqldbVersion >= 200;
return version >= 200;
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -693,12 +574,12 @@ public class HSQLDialect extends Dialect {
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return hsqldbVersion >= 200;
return version >= 200;
}
@Override
public boolean doesRepeatableReadCauseReadersToBlockWriters() {
return hsqldbVersion >= 200;
return version >= 200;
}
@Override
@ -714,12 +595,12 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsTupleDistinctCounts() {
// from v. 2.2.9 is added support for COUNT(DISTINCT ...) with multiple arguments
return hsqldbVersion >= 229;
return version >= 229;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new HSQLIdentityColumnSupport( this.hsqldbVersion );
return new HSQLIdentityColumnSupport( this.version);
}
@Override
@ -728,7 +609,7 @@ public class HSQLDialect extends Dialect {
}
@Override
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException {
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
return false;
}
@ -740,6 +621,30 @@ public class HSQLDialect extends Dialect {
@Override
public String getCascadeConstraintsString() {
return " CASCADE ";
return " cascade ";
}
@Override
public String translateDatetimeFormat(String format) {
return OracleDialect.datetimeFormat(format, false)
.replace("SSSSSS", "FF")
.replace("SSSSS", "FF")
.replace("SSSS", "FF")
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
//TODO: does not support MICROSECOND, but on the
// other hand it doesn't support microsecond
// precision in timestamps either so who cares?
switch (unit) {
case WEEK: return "week_of_year"; //this is the ISO week number, I believe
default: return unit.toString();
}
}
}

View File

@ -6,17 +6,16 @@
*/
package org.hibernate.dialect;
import org.hibernate.dialect.pagination.Informix10LimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
/**
* Since version 10.00.xC3 Informix has limit/offset support which was introduced in July 2005.
* Dialect for Informix 10
*
* @deprecated use {@code InformixDialect(10)}
*/
@Deprecated
public class Informix10Dialect extends InformixDialect {
@Override
public LimitHandler getLimitHandler() {
return Informix10LimitHandler.INSTANCE;
public Informix10Dialect() {
super(10);
}
}

View File

@ -6,26 +6,24 @@
*/
package org.hibernate.dialect;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.InformixExtractEmulation;
import org.hibernate.dialect.function.Replacer;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.InformixIdentityColumnSupport;
import org.hibernate.dialect.pagination.FirstLimitHandler;
import org.hibernate.dialect.pagination.LegacyFirstLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.SkipFirstLimitHandler;
import org.hibernate.dialect.sequence.InformixSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.unique.InformixUniqueDelegate;
import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
@ -34,63 +32,99 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorInformixDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.SQLException;
import java.sql.Types;
/**
* Informix dialect.<br>
* <br>
* Seems to work with Informix Dynamic Server Version 7.31.UD3, Informix JDBC driver version 2.21JC3.
* Dialect for Informix 7.31.UD3 with Informix
* JDBC driver 2.21JC3 and above.
*
* @author Steve Molitor
*/
public class InformixDialect extends Dialect {
private final int version;
int getVersion() {
return version;
}
public InformixDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() );
}
private final UniqueDelegate uniqueDelegate;
private final LimitHandler limitHandler;
public InformixDialect() {
this(7);
}
/**
* Creates new <code>InformixDialect</code> instance. Sets up the JDBC /
* Informix type mappings.
*/
public InformixDialect() {
public InformixDialect(int version) {
super();
this.version = version;
registerColumnType( Types.BIGINT, "int8" );
registerColumnType( Types.BINARY, "byte" );
// Informix doesn't have a bit type
registerColumnType( Types.BIT, 1, "boolean" );
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.CHAR, "char($l)" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.DECIMAL, "decimal" );
registerColumnType( Types.DOUBLE, "float" );
registerColumnType( Types.FLOAT, "smallfloat" );
registerColumnType( Types.INTEGER, "integer" );
// or BYTE
registerColumnType( Types.LONGVARBINARY, "blob" );
// or TEXT?
registerColumnType( Types.LONGVARCHAR, "clob" );
// or MONEY
registerColumnType( Types.NUMERIC, "decimal" );
registerColumnType( Types.REAL, "smallfloat" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TIMESTAMP, "datetime year to fraction(5)" );
registerColumnType( Types.TIME, "datetime hour to second" );
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.BIGINT, "int8" );
//Ingres ignores the precision argument in
//float(n) and just always defaults to
//double precision.
//TODO: return 'smallfloat' when n <= 24
registerColumnType( Types.TIME, "datetime hour to second" );
registerColumnType( Types.TIMESTAMP, "datetime year to fraction($p)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetime year to fraction($p)" );
//these types have no defined length
registerColumnType( Types.BINARY, "byte" );
registerColumnType( Types.VARBINARY, "byte" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.VARCHAR, 255, "varchar($l)" );
registerColumnType( Types.VARCHAR, 32739, "lvarchar($l)" );
registerColumnType( Types.VARCHAR, 32_739, "lvarchar($l)" );
registerColumnType( Types.VARCHAR, "text" );
uniqueDelegate = new InformixUniqueDelegate( this );
limitHandler = getVersion() < 10
? FirstLimitHandler.INSTANCE
//according to the Informix documentation for
//version 11 and above, parameters are supported
//but I have not tested this at all!
: new SkipFirstLimitHandler( getVersion() >= 11 );
}
public int getDefaultDecimalPrecision() {
//the maximum
return 32;
}
@Override
public int getDefaultTimestampPrecision() {
//the maximum
return 5;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
@ -99,23 +133,241 @@ public class InformixDialect extends Dialect {
CommonFunctionFactory.sinh( queryEngine );
CommonFunctionFactory.tanh( queryEngine );
CommonFunctionFactory.cosh( queryEngine );
CommonFunctionFactory.moreHyperbolic( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.variance( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
).setArgumentListSignature("(pattern, string[, start])");
//coalesce() and nullif() both supported since Informix 12
}
// queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() );
/**
* Informix has no extract() function, but we can
* partially emulate it by using the appropriate
* named functions, and by using to_char() with
* a format string.
*
* The supported fields are
* {@link TemporalUnit#HOUR},
* {@link TemporalUnit#MINUTE},
* {@link TemporalUnit#SECOND},
* {@link TemporalUnit#DAY},
* {@link TemporalUnit#MONTH},
* {@link TemporalUnit#YEAR},
* {@link TemporalUnit#QUARTER},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_WEEK}.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case SECOND:
return "to_number(to_char(?2,'%S'))";
case MINUTE:
return "to_number(to_char(?2,'%M'))";
case HOUR:
return "to_number(to_char(?2,'%H'))";
case DAY_OF_WEEK:
return "(weekday(?2)+1)";
case DAY_OF_MONTH:
return "day(?2)";
default:
//I think week() returns the ISO week number
return "?1(?2)";
}
}
queryEngine.getSqmFunctionRegistry().register( "coalesce", new InformixExtractEmulation() );
@Override
public String getAddColumnString() {
return "add";
}
/**
* Informix constraint name must be at the end.
* <p/>
* {@inheritDoc}
*/
@Override
public String getAddForeignKeyConstraintString(
String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
final StringBuilder result = new StringBuilder( 30 )
.append( " add constraint " )
.append( " foreign key (" )
.append( String.join( ", ", foreignKey ) )
.append( ") references " )
.append( referencedTable );
if ( !referencesPrimaryKey ) {
result.append( " (" )
.append( String.join( ", ", primaryKey ) )
.append( ')' );
}
result.append( " constraint " ).append( constraintName );
return result.toString();
}
public String getAddForeignKeyConstraintString(
String constraintName,
String foreignKeyDefinition) {
return " add constraint " + foreignKeyDefinition
+ " constraint " + constraintName;
}
/**
* Informix constraint name must be at the end.
* <p/>
* {@inheritDoc}
*/
@Override
public String getAddPrimaryKeyConstraintString(String constraintName) {
return " add constraint primary key constraint " + constraintName + " ";
}
@Override
public SequenceSupport getSequenceSupport() {
return InformixSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select systables.tabname as sequence_name, syssequences.* from syssequences join systables on syssequences.tabid = systables.tabid where tabtype = 'Q'";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorInformixDatabaseImpl.INSTANCE;
}
@Override
public LimitHandler getLimitHandler() {
return limitHandler;
}
@Override
public String getFromDual() {
return "from (select 0 from systables where tabid = 1) as dual";
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle );
switch (errorCode) {
case -268:
constraintName = extractUsingTemplate(
"Unique constraint (",
") violated.",
sqle.getMessage()
);
break;
case -691:
constraintName = extractUsingTemplate(
"Missing key in referenced table for referential constraint (",
").",
sqle.getMessage()
);
break;
case -692:
constraintName = extractUsingTemplate(
"Key value for constraint (",
") is still being referenced.",
sqle.getMessage()
);
break;
}
if ( constraintName != null ) {
// strip table-owner because Informix always returns constraint names as "<table-owner>.<constraint-name>"
final int i = constraintName.indexOf( '.' );
if ( i != -1 ) {
constraintName = constraintName.substring( i + 1 );
}
}
return constraintName;
}
};
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select distinct current timestamp from informix.systables";
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
return "create temp table";
}
@Override
protected String getCreateOptions() {
return "with no log";
}
},
AfterUseAction.NONE,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new InformixIdentityColumnSupport();
}
@Override
public String toBooleanValueString(boolean bool) {
return bool ? "'t'" : "'f'";
}
@Override
@ -177,233 +429,4 @@ public class InformixDialect extends Dialect {
.replace("S", "%F1");
}
@Override
public String getAddColumnString() {
return "add";
}
/**
* Informix constraint name must be at the end.
* <p/>
* {@inheritDoc}
*/
@Override
public String getAddForeignKeyConstraintString(
String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
final StringBuilder result = new StringBuilder( 30 )
.append( " add constraint " )
.append( " foreign key (" )
.append( String.join( ", ", foreignKey ) )
.append( ") references " )
.append( referencedTable );
if ( !referencesPrimaryKey ) {
result.append( " (" )
.append( String.join( ", ", primaryKey ) )
.append( ')' );
}
result.append( " constraint " ).append( constraintName );
return result.toString();
}
public String getAddForeignKeyConstraintString(
String constraintName,
String foreignKeyDefinition) {
return new StringBuilder( 30 )
.append( " add constraint " )
.append( foreignKeyDefinition )
.append( " constraint " )
.append( constraintName )
.toString();
}
/**
* Informix constraint name must be at the end.
* <p/>
* {@inheritDoc}
*/
@Override
public String getAddPrimaryKeyConstraintString(String constraintName) {
return " add constraint primary key constraint " + constraintName + " ";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from informix.systables where tabid=1";
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return sequenceName + ".nextval";
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public String getQuerySequencesString() {
return "select systables.tabname as sequence_name, syssequences.* from syssequences join systables on syssequences.tabid = systables.tabid where tabtype = 'Q'";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorInformixDatabaseImpl.INSTANCE;
}
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return LegacyFirstLimitHandler.INSTANCE;
}
return FirstLimitHandler.INSTANCE;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return new StringBuilder( querySelect.length() + 8 )
.append( querySelect )
.insert( querySelect.toLowerCase(Locale.ROOT).indexOf( "select" ) + 6, " first " + limit )
.toString();
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle );
if ( errorCode == -268 ) {
constraintName = extractUsingTemplate( "Unique constraint (", ") violated.", sqle.getMessage() );
}
else if ( errorCode == -691 ) {
constraintName = extractUsingTemplate(
"Missing key in referenced table for referential constraint (",
").",
sqle.getMessage()
);
}
else if ( errorCode == -692 ) {
constraintName = extractUsingTemplate(
"Key value for constraint (",
") is still being referenced.",
sqle.getMessage()
);
}
if ( constraintName != null ) {
// strip table-owner because Informix always returns constraint names as "<table-owner>.<constraint-name>"
final int i = constraintName.indexOf( '.' );
if ( i != -1 ) {
constraintName = constraintName.substring( i + 1 );
}
}
return constraintName;
}
};
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select distinct current timestamp from informix.systables";
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
return "create temp table";
}
@Override
protected String getCreateOptions() {
return "with no log";
}
},
AfterUseAction.NONE,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new InformixIdentityColumnSupport();
}
@Override
public String toBooleanValueString(boolean bool) {
return bool ? "'t'" : "'f'";
}
}

View File

@ -6,13 +6,6 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import java.util.Properties;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Ingres10IdentityColumnSupport;
/**
* A SQL dialect for Ingres 10 and later versions.
* <p/>
@ -23,46 +16,14 @@ import org.hibernate.dialect.identity.Ingres10IdentityColumnSupport;
* </ul>
*
* @author Raymond Fan
*
* @deprecated use {@code IngresDialect(1000)}
*/
public class Ingres10Dialect extends Ingres9Dialect {
/**
* Constructs a Ingres10Dialect
*/
@Deprecated
public class Ingres10Dialect extends IngresDialect {
public Ingres10Dialect() {
super();
registerBooleanSupport();
registerDefaultProperties();
}
protected void registerBooleanSupport() {
// Boolean type (mapping/BooleanType) mapping maps SQL BIT to Java
// Boolean. In order to create a boolean column, BIT needs to be mapped
// to boolean as well, similar to H2Dialect.
registerColumnType( Types.BIT, "boolean" );
registerColumnType( Types.BOOLEAN, "boolean" );
}
private void registerDefaultProperties() {
// true, false and unknown are now valid values
// Remove the query substitutions previously added in IngresDialect.
final Properties properties = getDefaultProperties();
final String querySubst = properties.getProperty( Environment.QUERY_SUBSTITUTIONS );
if ( querySubst != null ) {
final String newQuerySubst = querySubst.replace( "true=1,false=0", "" );
properties.setProperty( Environment.QUERY_SUBSTITUTIONS, newQuerySubst );
}
}
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String toBooleanValueString(boolean bool) {
return bool ? "true" : "false";
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new Ingres10IdentityColumnSupport();
super(1000);
}
}

View File

@ -6,17 +6,6 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Ingres9IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.query.spi.QueryEngine;
/**
* A SQL dialect for Ingres 9.3 and later versions.
* <p/>
@ -28,163 +17,19 @@ import org.hibernate.query.spi.QueryEngine;
* <li>Added support for pooled sequences</li>
* <li>Added support for SELECT queries with limit and offset</li>
* <li>Added getIdentitySelectString</li>
* <li>Modified concatenation operator</li>
* <li>Modified concatination operator</li>
* </ul>
*
* @author Enrico Schenk
* @author Raymond Fan
*
* @deprecated use {@code IngresDialect(930)}
*/
@Deprecated
public class Ingres9Dialect extends IngresDialect {
private static final LimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final String soff = " offset " + selection.getFirstRow();
final String slim = " fetch first " + getMaxOrLimit( selection ) + " rows only";
final StringBuilder sb = new StringBuilder( sql.length() + soff.length() + slim.length() )
.append( sql );
if (LimitHelper.hasFirstRow( selection )) {
sb.append( soff );
}
if (LimitHelper.hasMaxRows( selection )) {
sb.append( slim );
}
return sb.toString();
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
/**
* Constructs a Ingres9Dialect
*/
public Ingres9Dialect() {
super();
registerColumnType( Types.DATE, "ansidate" );
registerColumnType( Types.TIMESTAMP, "timestamp(9) with time zone" );
super(930);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
}
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public boolean forUpdateOfColumns() {
return true;
}
// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getQuerySequencesString() {
return "select seq_name from iisequences";
}
@Override
public boolean supportsPooledSequences() {
return true;
}
// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp";
}
@Override
public String getCurrentTimestampSQLFunctionName() {
return "current_timestamp";
}
// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsUnionAll() {
return true;
}
// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return true;
}
@Override
public boolean doesRepeatableReadCauseReadersToBlockWriters() {
return true;
}
// limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public LimitHandler getDefaultLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public boolean supportsLimitOffset() {
return true;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public boolean useMaxForLimit() {
return false;
}
@Override
public String getLimitString(String querySelect, int offset, int limit) {
final StringBuilder soff = new StringBuilder( " offset " + offset );
final StringBuilder slim = new StringBuilder( " fetch first " + limit + " rows only" );
final StringBuilder sb = new StringBuilder( querySelect.length() + soff.length() + slim.length() )
.append( querySelect );
if ( offset > 0 ) {
sb.append( soff );
}
if ( limit > 0 ) {
sb.append( slim );
}
return sb.toString();
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new Ingres9IdentityColumnSupport();
}
}

View File

@ -6,14 +6,18 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Ingres10IdentityColumnSupport;
import org.hibernate.dialect.identity.Ingres9IdentityColumnSupport;
import org.hibernate.dialect.pagination.FirstLimitHandler;
import org.hibernate.dialect.pagination.LegacyFirstLimitHandler;
import org.hibernate.dialect.pagination.IngresLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.sequence.ANSISequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
@ -23,6 +27,8 @@ import org.hibernate.tool.schema.extract.internal.SequenceNameExtractorImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.Types;
/**
* An SQL dialect for Ingres 9.2.
* <p/>
@ -41,45 +47,77 @@ import org.hibernate.type.StandardBasicTypes;
* Perform string casts to varchar; removes space padding.
* </li>
* </ul>
*
*
* @author Ian Booth
* @author Bruce Lunsford
* @author Max Rydahl Andersen
* @author Raymond Fan
*/
@SuppressWarnings("deprecation")
public class IngresDialect extends Dialect {
private final LimitHandler limitHandler;
private final int version;
private final SequenceSupport sequenceSupport;
int getVersion() {
return version;
}
public IngresDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
public IngresDialect() {
this(920);
}
/**
* Constructs a IngresDialect
*/
public IngresDialect() {
public IngresDialect(int version) {
super();
this.version = version;
if ( getVersion() < 1000 ) {
registerColumnType( Types.BIT, 1, "tinyint" );
registerColumnType( Types.BOOLEAN, "tinyint" );
}
else {
registerColumnType( Types.BIT, 1, "boolean" );
registerColumnType( Types.BOOLEAN, "boolean" );
}
registerColumnType( Types.BIT, "tinyint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.REAL, "real" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "float" );
registerColumnType( Types.NUMERIC, "decimal($p, $s)" );
registerColumnType( Types.DECIMAL, "decimal($p, $s)" );
registerColumnType( Types.BINARY, 32000, "byte($l)" );
registerColumnType( Types.BINARY, "long byte" );
registerColumnType( Types.VARBINARY, 32000, "varbyte($l)" );
registerColumnType( Types.VARBINARY, "long byte" );
registerColumnType( Types.LONGVARBINARY, "long byte" );
registerColumnType( Types.CHAR, 32000, "char($l)" );
registerColumnType( Types.VARCHAR, 32000, "varchar($l)" );
registerColumnType( Types.VARCHAR, "long varchar" );
registerColumnType( Types.LONGVARCHAR, "long varchar" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time with time zone" );
registerColumnType( Types.TIMESTAMP, "timestamp with time zone" );
registerColumnType( Types.BLOB, "blob" );
registerColumnType( Types.CLOB, "clob" );
registerColumnType( Types.NUMERIC, "decimal($p, $s)" ); //Ingres has no 'numeric' type
final int maxStringLength = 32_000;
registerColumnType( Types.BINARY, maxStringLength, "byte($l)" );
registerColumnType( Types.VARBINARY, maxStringLength, "varbyte($l)" );
//note: 'long byte' is a synonym for 'blob'
registerColumnType( Types.VARBINARY, "long byte($l)" );
//TODO: should we be using nchar/nvarchar/long nvarchar
// here? I think Ingres char/varchar types don't
// support Unicode. Copy what AbstractHANADialect
// does with a Hibernate property to config this.
registerColumnType( Types.CHAR, maxStringLength, "char($l)" );
registerColumnType( Types.VARCHAR, maxStringLength, "varchar($l)" );
//note: 'long varchar' is a synonym for 'clob'
registerColumnType( Types.VARCHAR, "long varchar($l)" );
registerColumnType( Types.NCHAR, maxStringLength, "nchar($l)" );
registerColumnType( Types.NVARCHAR, maxStringLength, "nvarchar($l)" );
//note: 'long nvarchar' is a synonym for 'nclob'
registerColumnType( Types.NVARCHAR, "long nvarchar($l)" );
if ( getVersion() >= 930 ) {
// Not completely necessary, given that Ingres
// can be configured to set DATE = ANSIDATE
registerColumnType( Types.DATE, "ansidate" );
}
// Ingres driver supports getGeneratedKeys but only in the following
// form:
@ -93,10 +131,40 @@ public class IngresDialect extends Dialect {
// Ingres JDBC Driver returns table and object keys as BINARY values.
getDefaultProperties().setProperty( Environment.USE_GET_GENERATED_KEYS, "false" );
// There is no support for a native boolean type that accepts values
// of true, false or unknown. Using the tinyint type requires
// substitions of true and false.
getDefaultProperties().setProperty( Environment.QUERY_SUBSTITUTIONS, "true=1,false=0" );
if ( getVersion() < 1000 ) {
// There is no support for a native boolean type that accepts values
// of true, false or unknown. Using the tinyint type requires
// substitutions of true and false.
getDefaultProperties().setProperty( Environment.QUERY_SUBSTITUTIONS, "true=1,false=0" );
}
limitHandler = getVersion() < 930 ? FirstLimitHandler.INSTANCE : IngresLimitHandler.INSTANCE;
sequenceSupport = new ANSISequenceSupport() {
@Override
public boolean supportsPooledSequences() {
return getVersion() >= 930;
}
};
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return getVersion() < 1000 ? Types.BIT : Types.BOOLEAN;
}
@Override
public String toBooleanValueString(boolean bool) {
return getVersion() < 1000
? super.toBooleanValueString( bool )
: String.valueOf( bool );
}
@Override
public int getDefaultDecimalPrecision() {
//the maximum
return 39;
}
@Override
@ -111,31 +179,37 @@ public class IngresDialect extends Dialect {
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
CommonFunctionFactory.dayofweekmonthyear( queryEngine );
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.formatdatetime_dateFormat( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.format_dateFormat( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("locate", StandardBasicTypes.INTEGER, "position(?1 in ?2)", "(position(?1 in substring(?2 from ?3)) + (?3) - 1)");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1', ?2)", StandardBasicTypes.INTEGER );
bitwiseFunctions(queryEngine);
CommonFunctionFactory.bitandorxornot_bitAndOrXorNot(queryEngine);
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "squeeze" )
.setExactArgumentCount( 1 )
@ -144,64 +218,15 @@ public class IngresDialect extends Dialect {
}
static void bitwiseFunctions(QueryEngine queryEngine) {
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_and" )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitand", "bit_and");
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
return "timestampadd(?1, ?2, ?3)";
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_or" )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitor", "bit_xor");
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_xor" )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitxor", "bit_xor");
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_not" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitnot", "bit_not");
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("timestampadd(");
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
magnitude.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
sqlAppender.append("timestampdiff(");
sqlAppender.append( unit.toString() );
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public String translateDatetimeFormat(String format) {
return MySQLDialect.datetimeFormat( format ).result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
case WEEK: return "iso_week";
default: return unit.toString();
}
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
return "timestampdiff(?1, ?2, ?3)";
}
@Override
@ -214,44 +239,24 @@ public class IngresDialect extends Dialect {
return false;
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getNullColumnString() {
return " with null";
}
@Override
public boolean supportsSequences() {
return true;
}
// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getSequenceNextValString(String sequenceName) {
return "select nextval for " + sequenceName;
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return sequenceName + ".nextval";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName + " restrict";
public SequenceSupport getSequenceSupport() {
return sequenceSupport;
}
@Override
public String getQuerySequencesString() {
return "select seq_name from iisequence";
return getVersion() < 930
? "select seq_name from iisequence"
: "select seq_name from iisequences";
}
@Override
@ -266,45 +271,44 @@ public class IngresDialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return LegacyFirstLimitHandler.INSTANCE;
return limitHandler;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
if ( getVersion() >= 1000 ) {
return new Ingres10IdentityColumnSupport();
}
else if (getVersion() >= 930) {
return new Ingres9IdentityColumnSupport();
}
else {
return super.getIdentityColumnSupport();
}
return getDefaultLimitHandler();
}
protected LimitHandler getDefaultLimitHandler() {
return FirstLimitHandler.INSTANCE;
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsOuterJoinForUpdate() {
return getVersion() >= 930;
}
@Override
public boolean supportsLimit() {
return true;
public boolean forUpdateOfColumns() {
return getVersion() >= 930;
}
// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsLimitOffset() {
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return new StringBuilder( querySelect.length() + 16 )
.append( querySelect )
.insert( 6, " first " + limit )
.toString();
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public boolean useMaxForLimit() {
return true;
public boolean supportsCurrentTimestampSelection() {
return getVersion() >= 930;
}
@Override
@ -334,10 +338,37 @@ public class IngresDialect extends Dialect {
// );
}
@Override
@SuppressWarnings("deprecation")
public String getCurrentTimestampSQLFunctionName() {
return getVersion() >= 930 ? "current_timestamp" : "date(now)";
}
// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getCurrentTimestampSQLFunctionName() {
return "date(now)";
public boolean supportsUnionAll() {
return getVersion() >= 930;
}
// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return getVersion() >= 930;
}
@Override
public boolean doesRepeatableReadCauseReadersToBlockWriters() {
return getVersion() >= 930;
}
// limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String getFromDual() {
//this is only necessary if the query has a where clause
return "from (select 0) as dual";
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -361,4 +392,21 @@ public class IngresDialect extends Dialect {
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public String translateDatetimeFormat(String format) {
return MySQLDialect.datetimeFormat( format ).result();
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
case WEEK: return "iso_week";
default: return super.translateExtractField( unit );
}
}
}

View File

@ -6,70 +6,50 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.dialect.pagination.RowsLimitHandler;
import org.hibernate.dialect.sequence.InterbaseSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.tool.schema.extract.internal.SequenceNameExtractorImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import java.sql.Types;
/**
* An SQL dialect for Interbase.
*
* @author Gavin King
*/
@SuppressWarnings("deprecation")
public class InterbaseDialect extends Dialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return hasOffset ? sql + " rows ? to ?" : sql + " rows ?";
}
@Override
public boolean supportsLimit() {
return true;
}
};
/**
* Constructs a InterbaseDialect
*/
public InterbaseDialect() {
super();
registerColumnType( Types.BIT, 1, "boolean" );
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.BIGINT, "numeric(18,0)" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double precision" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.BIGINT, "numeric(19,0)" );
registerColumnType( Types.REAL, "float");
registerColumnType( Types.FLOAT, "double precision");
registerColumnType( Types.VARBINARY, "blob" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.BLOB, "blob" );
registerColumnType( Types.CLOB, "blob sub_type 1" );
registerColumnType( Types.BOOLEAN, "smallint" );
//no precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
public int getDefaultDecimalPrecision() {
//the extremely low maximum
return 18;
}
@Override
@ -78,28 +58,13 @@ public class InterbaseDialect extends Dialect {
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from RDB$DATABASE";
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "gen_id( " + sequenceName + ", 1 )";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create generator " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "delete from RDB$GENERATORS where RDB$GENERATOR_NAME = '" + sequenceName.toUpperCase(Locale.ROOT) + "'";
public SequenceSupport getSequenceSupport() {
return InterbaseSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select RDB$GENERATOR_NAME from RDB$GENERATORS";
return "select rdb$generator_name from rdb$generators";
}
@Override
@ -112,52 +77,24 @@ public class InterbaseDialect extends Dialect {
return " with lock";
}
@Override
public String getForUpdateString(String aliases) {
return " for update of " + aliases + " with lock";
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
return hasOffset ? sql + " rows ? to ?" : sql + " rows ?";
}
@Override
public boolean bindLimitParametersFirst() {
return false;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return false;
return RowsLimitHandler.INSTANCE;
}
@Override
public String getCurrentTimestampSelectString() {
// TODO : not sure which (either?) is correct, could not find docs on how to do this.
// did find various blogs and forums mentioning that select CURRENT_TIMESTAMP
// does not work...
return "{?= call CURRENT_TIMESTAMP }";
// return "select CURRENT_TIMESTAMP from RDB$DATABASE";
return "select current_timestamp " + getFromDual();
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return true;
return false;
}
@Override
public String getFromDual() {
return "from rdb$database";
}
}

View File

@ -18,30 +18,23 @@ import org.hibernate.dialect.identity.JDataStoreIdentityColumnSupport;
* @author Vishy Kasar
*/
public class JDataStoreDialect extends Dialect {
/**
* Creates new JDataStoreDialect
*/
public JDataStoreDialect() {
super();
//only surviving documentation known to Google:
//https://web.mit.edu/jbuilder_v2005/distrib/share/doc/jds_devgd.pdf
//'bit' is a synonym for 'boolean'
registerColumnType( Types.BIT, "tinyint" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "varbinary($l)" );
registerColumnType( Types.NUMERIC, "numeric($p, $s)" );
//no 'blob' nor 'clob', at least not in 7
registerColumnType( Types.BLOB, "varbinary" );
registerColumnType( Types.CLOB, "varchar" );
//no precision, at least not in 7
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
}

View File

@ -0,0 +1,72 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.MappingException;
import org.hibernate.dialect.sequence.SequenceSupport;
/**
* @author Gavin King
*/
@SuppressWarnings("deprecation")
public class LegacySequenceSupport implements SequenceSupport {
private Dialect dialect;
public LegacySequenceSupport(Dialect dialect) {
this.dialect = dialect;
}
@Override
public boolean supportsSequences() {
return dialect.supportsSequences();
}
@Override
public boolean supportsPooledSequences() {
return dialect.supportsPooledSequences();
}
@Override
public String getSequenceNextValString(String sequenceName) throws MappingException {
return dialect.getSequenceNextValString( sequenceName );
}
@Override
public String getSequenceNextValString(String sequenceName, int increment) throws MappingException {
return dialect.getSequenceNextValString( sequenceName, increment );
}
@Override
public String getSelectSequenceNextValString(String sequenceName) throws MappingException {
return dialect.getSelectSequenceNextValString( sequenceName );
}
@Override
public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) throws MappingException {
return dialect.getCreateSequenceStrings( sequenceName, initialValue, incrementSize );
}
@Override
public String getCreateSequenceString(String sequenceName) throws MappingException {
return dialect.getCreateSequenceString( sequenceName );
}
@Override
public String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) throws MappingException {
return dialect.getCreateSequenceString( sequenceName, initialValue, incrementSize );
}
@Override
public String[] getDropSequenceStrings(String sequenceName) throws MappingException {
return dialect.getDropSequenceStrings( sequenceName );
}
@Override
public String getDropSequenceString(String sequenceName) throws MappingException {
return dialect.getDropSequenceString( sequenceName );
}
}

View File

@ -6,28 +6,14 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
public class MariaDB102Dialect extends MariaDB10Dialect {
/**
* @deprecated use {@code MariaDBDialect(1020)}
*/
@Deprecated
public class MariaDB102Dialect extends MariaDBDialect {
public MariaDB102Dialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
super(1020);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
queryEngine.getSqmFunctionRegistry().registerNamed( "json_valid", StandardBasicTypes.NUMERIC_BOOLEAN );
}
@Override
public boolean supportsColumnCheck() {
return true;
}
}

View File

@ -6,87 +6,18 @@
*/
package org.hibernate.dialect;
import org.hibernate.LockOptions;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMariaDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
/**
* An SQL dialect for MariaDB 10.3 and later, provides sequence support, lock-timeouts, etc.
*
* @author Philippe Marschall
*
* @deprecated use {@code MariaDBDialect(1030)}
*/
public class MariaDB103Dialect extends MariaDB102Dialect {
@Deprecated
public class MariaDB103Dialect extends MariaDBDialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
queryEngine.getSqmFunctionRegistry().registerNamed( "chr", StandardBasicTypes.CHARACTER );
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "nextval(" + sequenceName + ")";
}
@Override
public String getQuerySequencesString() {
return "select table_name from information_schema.TABLES where table_type='SEQUENCE'";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorMariaDBDatabaseImpl.INSTANCE;
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return getForUpdateNowaitString();
}
if ( timeout > 0 ) {
return getForUpdateString() + " wait " + timeout;
}
return getForUpdateString();
}
@Override
public String getForUpdateNowaitString() {
return getForUpdateString() + " nowait";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateString( aliases ) + " nowait";
public MariaDB103Dialect() {
super(1030);
}
}

View File

@ -6,16 +6,14 @@
*/
package org.hibernate.dialect;
import org.hibernate.type.StandardBasicTypes;
public class MariaDB10Dialect extends MariaDB53Dialect {
/**
* @deprecated use {@code MariaDBDialect(1000)}
*/
@Deprecated
public class MariaDB10Dialect extends MariaDBDialect {
public MariaDB10Dialect() {
super();
super(1000);
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return true;
}
}

View File

@ -6,20 +6,16 @@
*/
package org.hibernate.dialect;
import org.hibernate.query.spi.QueryEngine;
/**
* @author Vlad Mihalcea
*
* @deprecated use {@code MariaDBDialect(530)}
*/
@Deprecated
public class MariaDB53Dialect extends MariaDBDialect {
public MariaDB53Dialect() {
upgradeTo57();
super(530);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
upgradeTo57( queryEngine );
}
}

View File

@ -6,20 +6,120 @@
*/
package org.hibernate.dialect;
import org.hibernate.LockOptions;
import org.hibernate.dialect.sequence.ANSISequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMariaDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
/**
* SQL dialect for MariaDB
*
* @author Vlad Mihalcea
* @author Gavin King
*/
public class MariaDBDialect extends MySQL5Dialect {
public class MariaDBDialect extends MySQLDialect {
private final int version;
int getMariaVersion() {
return version;
}
public MariaDBDialect() {
super();
this(500);
}
public MariaDBDialect(int version) {
super(version < 530 ? 500 : 570);
this.version = version;
}
public MariaDBDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
if ( getMariaVersion() >= 1020 ) {
queryEngine.getSqmFunctionRegistry().registerNamed("json_valid", StandardBasicTypes.NUMERIC_BOOLEAN);
}
}
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
@Override
public boolean supportsColumnCheck() {
return getMariaVersion() >= 1020;
}
@Override
protected MySQLStorageEngine getDefaultMySQLStorageEngine() {
return InnoDBStorageEngine.INSTANCE;
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return getMariaVersion() >= 1000;
}
@Override
public SequenceSupport getSequenceSupport() {
return getMariaVersion() < 1030
? super.getSequenceSupport()
: ANSISequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return supportsSequences()
? "select table_name from information_schema.TABLES where table_type='SEQUENCE'"
: super.getQuerySequencesString(); //fancy way to write "null"
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return supportsSequences()
? SequenceInformationExtractorMariaDBDatabaseImpl.INSTANCE
: super.getSequenceInformationExtractor();
}
@Override
public String getWriteLockString(int timeout) {
if ( getMariaVersion() < 1030 ) {
return super.getWriteLockString( timeout );
}
if ( timeout == LockOptions.NO_WAIT ) {
return getForUpdateNowaitString();
}
if ( timeout > 0 ) {
return getForUpdateString() + " wait " + timeout;
}
return getForUpdateString();
}
@Override
public String getForUpdateNowaitString() {
return getMariaVersion() < 1030
? super.getForUpdateNowaitString()
: getForUpdateString() + " nowait";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getMariaVersion() < 1030
? super.getForUpdateNowaitString( aliases )
: getForUpdateString( aliases ) + " nowait";
}
}

View File

@ -6,25 +6,18 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.lock.*;
import org.hibernate.dialect.sequence.MckoiSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.MckoiCaseFragment;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.MckoiCaseExpressionWalker;
import java.sql.Types;
/**
* An SQL dialect compatible with McKoi SQL
@ -38,22 +31,16 @@ public class MckoiDialect extends Dialect {
*/
public MckoiDialect() {
super();
registerColumnType( Types.BIT, "bit" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "varbinary" );
registerColumnType( Types.NUMERIC, "numeric" );
registerColumnType( Types.BLOB, "blob" );
registerColumnType( Types.CLOB, "clob" );
//Note: there is no single-precision type
//'float' and 'double' are the exact same
//double precision type.
registerColumnType( Types.FLOAT, "float" ); //precision argument not supported
registerColumnType( Types.DOUBLE, "double" ); //'double precision' not supported
//no explicit precision
registerColumnType(Types.TIMESTAMP, "timestamp");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp");
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@ -63,35 +50,16 @@ public class MckoiDialect extends Dialect {
super.initializeFunctionRegistry(queryEngine);
CommonFunctionFactory.characterLength_length( queryEngine );
CommonFunctionFactory.trim1( queryEngine );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "if(?1=?2, null, ?1)" )
.setExactArgumentCount( 2 )
.register( "nullif" );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "nullif", "if(?1=?2, null, ?1)" )
.setExactArgumentCount(2)
.register();
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "nextval('" + sequenceName + "')";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
public SequenceSupport getSequenceSupport() {
return MckoiSequenceSupport.INSTANCE;
}
@Override
@ -100,39 +68,27 @@ public class MckoiDialect extends Dialect {
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public CaseFragment createCaseFragment() {
return new MckoiCaseFragment();
}
@Override
public CaseExpressionWalker getCaseExpressionWalker() {
return MckoiCaseExpressionWalker.INSTANCE;
}
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// Mckoi has no known variation of a "SELECT ... FOR UPDATE" syntax...
if ( lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode);
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_WRITE) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_READ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC) {
return new OptimisticLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC_FORCE_INCREMENT) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode);
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {

View File

@ -6,117 +6,224 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.MimerSQLIdentityColumnSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.MimerSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.query.CastType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMimerSQLDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.Types;
import static org.hibernate.query.CastType.BOOLEAN;
/**
* An Hibernate 3 SQL dialect for Mimer SQL. This dialect requires Mimer SQL 9.2.1 or later
* because of the mappings to NCLOB, BINARY, and BINARY VARYING.
* A dialect for Mimer SQL 11.
*
* @author Fredrik lund <fredrik.alund@mimer.se>
* @author Gavin King
*/
@SuppressWarnings("deprecation")
public class MimerSQLDialect extends Dialect {
private static final int NATIONAL_CHAR_LENGTH = 2000;
private static final int BINARY_MAX_LENGTH = 2000;
// KNOWN LIMITATIONS:
// * no support for format()
// * can't cast non-literal String to Binary
// * no power(), exp(), ln(), sqrt() functions
// * no trig functions, not even sin()
// * can't select a parameter unless wrapped
// in a cast or function call
/**
* Even though Mimer SQL supports character and binary columns up to 15 000 in length,
* this is also the maximum width of the table (excluding LOBs). To avoid breaking the limit all the
* time we limit the length of the character columns to CHAR_MAX_LENTH, NATIONAL_CHAR_LENGTH for national
* characters, and BINARY_MAX_LENGTH for binary types.
*/
public MimerSQLDialect() {
super();
registerColumnType( Types.BIT, "ODBC.BIT" );
registerColumnType( Types.BIGINT, "BIGINT" );
registerColumnType( Types.SMALLINT, "SMALLINT" );
registerColumnType( Types.TINYINT, "ODBC.TINYINT" );
registerColumnType( Types.INTEGER, "INTEGER" );
registerColumnType( Types.CHAR, "NCHAR(1)" );
registerColumnType( Types.VARCHAR, NATIONAL_CHAR_LENGTH, "NATIONAL CHARACTER VARYING($l)" );
registerColumnType( Types.VARCHAR, "NCLOB($l)" );
registerColumnType( Types.LONGVARCHAR, "CLOB($1)" );
registerColumnType( Types.FLOAT, "FLOAT" );
registerColumnType( Types.DOUBLE, "DOUBLE PRECISION" );
registerColumnType( Types.DATE, "DATE" );
registerColumnType( Types.TIME, "TIME" );
registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
registerColumnType( Types.VARBINARY, BINARY_MAX_LENGTH, "BINARY VARYING($l)" );
registerColumnType( Types.VARBINARY, "BLOB($1)" );
registerColumnType( Types.LONGVARBINARY, "BLOB($1)" );
registerColumnType( Types.BINARY, BINARY_MAX_LENGTH, "BINARY" );
registerColumnType( Types.BINARY, "BLOB($1)" );
registerColumnType( Types.NUMERIC, "NUMERIC(19, $l)" );
registerColumnType( Types.BLOB, "BLOB($l)" );
registerColumnType( Types.CLOB, "NCLOB($l)" );
//no 'bit' type
registerColumnType( Types.BIT, 1, "boolean" );
//no 'tinyint', so use integer with 3 decimal digits
registerColumnType( Types.BIT, "integer(3)" );
registerColumnType( Types.TINYINT, "integer(3)" );
//Mimer CHARs are ASCII!!
registerColumnType( Types.CHAR, "nchar($l)" );
registerColumnType( Types.VARCHAR, 5_000, "nvarchar($l)" );
registerColumnType( Types.VARCHAR, "nclob($l)" );
registerColumnType( Types.NVARCHAR, 5_000, "nvarchar($l)" );
registerColumnType( Types.NVARCHAR, "nclob($l)" );
registerColumnType( Types.VARBINARY, 15_000, "varbinary($l)" );
registerColumnType( Types.VARBINARY, "blob($l)" );
//default length is 1M, which is quite low
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "nclob($l)" );
registerColumnType( Types.NCLOB, "nclob($l)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)" );
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, "50" );
}
@Override
public String getTypeName(int code, Size size) throws HibernateException {
//precision of a Mimer 'float(p)' represents
//decimal digits instead of binary digits
return super.getTypeName( code, binaryToDecimalPrecision( code, size ) );
}
// @Override
// public int getDefaultDecimalPrecision() {
// //the maximum, but I guess it's too high
// return 45;
// }
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
queryEngine.getSqmFunctionRegistry().registerNamed( "round" );
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.pad_repeat( queryEngine );
CommonFunctionFactory.dayofweekmonthyear( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
}
queryEngine.getSqmFunctionRegistry().registerNamed( "dacos", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dasin", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "datan", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "datan2", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dcos", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dcot", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "cot", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "ddegrees", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "degrees", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dexp", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dlog", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "log", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dlog10", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "log10", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dradian", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "radian", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dsin", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "soundex", StandardBasicTypes.STRING );
queryEngine.getSqmFunctionRegistry().registerNamed( "dsqrt", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dtan", StandardBasicTypes.DOUBLE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dpower" );
queryEngine.getSqmFunctionRegistry().registerNamed( "date", StandardBasicTypes.DATE );
queryEngine.getSqmFunctionRegistry().registerNamed( "dayofweek", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().registerNamed( "dayofyear", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().registerNamed( "time", StandardBasicTypes.TIME );
queryEngine.getSqmFunctionRegistry().registerNamed( "timestamp", StandardBasicTypes.TIMESTAMP );
queryEngine.getSqmFunctionRegistry().registerNamed( "week", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().registerNamed( "varchar", StandardBasicTypes.STRING );
queryEngine.getSqmFunctionRegistry().registerNamed( "real", StandardBasicTypes.FLOAT );
queryEngine.getSqmFunctionRegistry().registerNamed( "bigint", StandardBasicTypes.LONG );
queryEngine.getSqmFunctionRegistry().registerNamed( "char", StandardBasicTypes.CHARACTER );
queryEngine.getSqmFunctionRegistry().registerNamed( "integer", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().registerNamed( "smallint", StandardBasicTypes.SHORT );
queryEngine.getSqmFunctionRegistry().registerNamed( "ascii_char", StandardBasicTypes.CHARACTER );
queryEngine.getSqmFunctionRegistry().registerNamed( "ascii_code", StandardBasicTypes.STRING );
queryEngine.getSqmFunctionRegistry().registerNamed( "unicode_char", StandardBasicTypes.LONG );
queryEngine.getSqmFunctionRegistry().registerNamed( "unicode_code", StandardBasicTypes.STRING );
/**
* Mimer does have a real {@link java.sql.Types#BOOLEAN}
* type, but it doesn't know how to cast to it.
*/
@Override
public String castPattern(CastType from, CastType to) {
switch (to) {
case BOOLEAN:
switch (from) {
case STRING:
// return "case when regexp_match(lower(?1), '^(t|f|true|false)$') then lower(?1) like 't%' end";
// return "case when lower(?1)in('t','true') then true when lower(?1)in('f','false') then false end";
return "case when ?1 in('t','true','T','TRUE') then true when ?1 in('f','false','F','FALSE') then false end";
case LONG:
case INTEGER:
return "(?1<>0)";
}
break;
case INTEGER:
case LONG:
if (from == BOOLEAN) {
return "case ?1 when false then 0 when true then 1 end";
}
break;
}
return super.castPattern(from, to);
}
@Override
public String getAddColumnString() {
return "add column";
public String currentTimestamp() {
return "localtimestamp";
}
@Override
public String currentTime() {
return "localtime";
}
/**
* Mimer supports a limited list of temporal fields in the
* extract() function, but we can emulate some of them by
* using the appropriate named functions instead of
* extract().
*
* Thus, the additional supported fields are
* {@link TemporalUnit#WEEK},
* {@link TemporalUnit#DAY_OF_YEAR},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case WEEK:
return "week(?2)";
case DAY_OF_WEEK:
return "dayofweek(?2)";
case DAY_OF_YEAR:
return "dayofyear(?2)";
case DAY_OF_MONTH:
return "day(?2)";
default:
return super.extractPattern(unit);
}
}
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
StringBuilder pattern = new StringBuilder();
pattern.append("cast((?3 - ?2) ");
switch (unit) {
case NATIVE:
case NANOSECOND:
case SECOND:
pattern.append("second(12,9)");
break;
case MINUTE:
pattern.append("minute(10)");
break;
case HOUR:
pattern.append("hour(8)");
break;
case DAY:
case WEEK:
pattern.append("day(7)");
break;
case MONTH:
case QUARTER:
pattern.append("month(7)");
break;
case YEAR:
pattern.append("year(7)");
break;
default:
throw new SemanticException("unsupported duration unit: " + unit);
}
pattern.append(" as bigint)");
switch (unit) {
case WEEK:
pattern.append("/7");
break;
case QUARTER:
pattern.append("/3");
break;
case NATIVE:
case NANOSECOND:
pattern.append("*1e9");
break;
}
return pattern.toString();
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch ( unit ) {
case NATIVE:
case NANOSECOND:
return "(?3 + (?2)/1e9 * interval '1' second)";
case QUARTER:
return "(?3 + (?2) * interval '3' month)";
case WEEK:
return "(?3 + (?2) * interval '7' day)";
default:
return "(?3 + (?2) * interval '1' ?1)";
}
}
@Override
@ -124,36 +231,16 @@ public class MimerSQLDialect extends Dialect {
return false;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select next_value of " + sequenceName + " from system.onerow";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create unique sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName + " restrict";
}
@Override
public boolean supportsLimit() {
return false;
}
@Override
public String getCascadeConstraintsString() {
return " cascade";
}
@Override
public SequenceSupport getSequenceSupport() {
return MimerSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select * from information_schema.ext_sequences";
@ -165,8 +252,13 @@ public class MimerSQLDialect extends Dialect {
}
@Override
public boolean forUpdateOfColumns() {
return false;
public LimitHandler getLimitHandler() {
return OffsetFetchLimitHandler.INSTANCE;
}
@Override
public String getFromDual() {
return "from (values(0))";
}
@Override
@ -175,7 +267,12 @@ public class MimerSQLDialect extends Dialect {
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new MimerSQLIdentityColumnSupport();
public String translateDatetimeFormat(String format) {
throw new NotYetImplementedFor6Exception("format() function not supported on Mimer SQL");
}
@Override
public boolean useInputStreamToInsertBlob() {
return false;
}
}

View File

@ -10,11 +10,14 @@ package org.hibernate.dialect;
* An SQL dialect for MySQL 5.5.x specific features.
*
* @author Vlad Mihalcea
*
* @deprecated use {@code MySQLDialect(550)}
*/
public class MySQL55Dialect extends MySQL5Dialect {
@Deprecated
public class MySQL55Dialect extends MySQLDialect {
@Override
protected MySQLStorageEngine getDefaultMySQLStorageEngine() {
return InnoDBStorageEngine.INSTANCE;
public MySQL55Dialect() {
super(550);
}
}

View File

@ -6,27 +6,16 @@
*/
package org.hibernate.dialect;
import org.hibernate.query.spi.QueryEngine;
/**
* @author Gail Badner
*
* @deprecated use {@code MySQLDialect(570)}
*/
public class MySQL57Dialect extends MySQL55Dialect {
@Deprecated
public class MySQL57Dialect extends MySQLDialect {
public MySQL57Dialect() {
upgradeTo57();
super(570);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
upgradeTo57( queryEngine );
}
/**
* @see <a href="https://dev.mysql.com/worklog/task/?id=7019">MySQL 5.7 work log</a>
* @return supports IN clause row value expressions
*/
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
}

View File

@ -6,63 +6,18 @@
*/
package org.hibernate.dialect;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
/**
* An SQL dialect for MySQL 5.x specific features.
*
* @author Steve Ebersole
*
* @deprecated use {@code MySQLDialect(500)}
*/
@Deprecated
public class MySQL5Dialect extends MySQLDialect {
@Override
protected void registerVarcharTypes() {
registerColumnType( Types.VARCHAR, "longtext" );
// registerColumnType( Types.VARCHAR, 16777215, "mediumtext" );
registerColumnType( Types.VARCHAR, 65535, "varchar($l)" );
registerColumnType( Types.LONGVARCHAR, "longtext" );
public MySQL5Dialect() {
super(500);
}
@Override
public boolean supportsColumnCheck() {
return false;
}
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
protected String getEngineKeyword() {
return "engine";
}
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
final int sqlState = Integer.parseInt( JdbcExceptionHelper.extractSqlState( sqle ) );
switch ( sqlState ) {
case 23000:
return extractUsingTemplate( " for key '", "'", sqle.getMessage() );
default:
return null;
}
}
};
@Override
public String getQueryHintString(String query, String hints) {
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
}
@Override
public boolean supportsUnionAll() {
return true;
}
}

View File

@ -6,14 +6,17 @@
*/
package org.hibernate.dialect;
import org.hibernate.LockOptions;
/**
* @author Vlad Mihalcea
*
* @deprecated use {@code MySQLDialect(800)}
*/
public class MySQL8Dialect extends MySQL57Dialect {
@Deprecated
public class MySQL8Dialect extends MySQLDialect {
public MySQL8Dialect() {
super(800);
// MySQL doesn't add the new reserved keywords to their JDBC driver to preserve backward compatibility.
registerKeyword("CUME_DIST");
@ -35,83 +38,4 @@ public class MySQL8Dialect extends MySQL57Dialect {
registerKeyword("ROW_NUMBER");
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return getForUpdateNowaitString();
}
else if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString();
}
return super.getWriteLockString( timeout );
}
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return getForUpdateNowaitString(aliases);
}
else if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString(aliases);
}
return super.getWriteLockString( aliases, timeout );
}
@Override
public String getReadLockString(int timeout) {
String readLockString = " for share";
if ( timeout == LockOptions.NO_WAIT ) {
return readLockString + " nowait ";
}
else if ( timeout == LockOptions.SKIP_LOCKED ) {
return readLockString + " skip locked ";
}
return readLockString;
}
@Override
public String getReadLockString(String aliases, int timeout) {
String readLockString = String.format( " for share of %s ", aliases );
if ( timeout == LockOptions.NO_WAIT ) {
return readLockString + " nowait ";
}
else if ( timeout == LockOptions.SKIP_LOCKED ) {
return readLockString + " skip locked ";
}
return readLockString;
}
@Override
public String getForUpdateSkipLockedString() {
return " for update skip locked";
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
return getForUpdateString() + " of " + aliases + " skip locked";
}
@Override
public String getForUpdateNowaitString() {
return getForUpdateString() + " nowait ";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateString( aliases ) + " nowait ";
}
@Override
public String getForUpdateString(String aliases) {
return getForUpdateString() + " of " + aliases;
}
@Override
public boolean supportsSkipLocked() {
return true;
}
public boolean supportsNoWait() {
return true;
}
}

View File

@ -6,88 +6,21 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.LockOptions;
import org.hibernate.sql.ANSIJoinFragment;
import org.hibernate.sql.JoinFragment;
/**
* A dialect specifically for use with Oracle 10g.
* <p/>
* The main difference between this dialect and {@link Oracle9iDialect}
* is the use of "ANSI join syntax".
* The main difference between this dialect and
* {@link Oracle9iDialect} is the use of
* "ANSI join syntax".
*
* @author Steve Ebersole
*
* @deprecated use {@code OracleDialect(10)}
*/
public class Oracle10gDialect extends Oracle9iDialect {
/**
* Constructs an Oracle10gDialect
*/
@Deprecated
public class Oracle10gDialect extends OracleDialect {
public Oracle10gDialect() {
super();
}
@Override
public JoinFragment createOuterJoinFragment() {
return new ANSIJoinFragment();
}
@Override
public String getCrossJoinSeparator() {
return " cross join ";
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString();
}
else {
return super.getWriteLockString( timeout );
}
}
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString( aliases );
}
else {
return super.getWriteLockString( aliases, timeout );
}
}
@Override
public String getForUpdateSkipLockedString() {
return " for update skip locked";
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
return getForUpdateString() + " of " + aliases + " skip locked";
}
@Override
public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
return (ResultSet) statement.getObject( position );
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException {
statement.registerOutParameter( name, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() );
return 1;
}
@Override
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
return (ResultSet) statement.getObject( name );
}
@Override
public boolean supportsSkipLocked() {
return true;
super(10);
}
}

View File

@ -6,60 +6,17 @@
*/
package org.hibernate.dialect;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Oracle12cIdentityColumnSupport;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.MaterializedBlobType;
import org.hibernate.type.WrappedMaterializedBlobType;
/**
* An SQL dialect for Oracle 12c.
*
* @author zhouyanming (zhouyanming@gmail.com)
*
* @deprecated use {@code OracleDialect(12)}
*/
public class Oracle12cDialect extends Oracle10gDialect {
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
@Deprecated
public class Oracle12cDialect extends OracleDialect {
public Oracle12cDialect() {
super();
getDefaultProperties().setProperty( Environment.BATCH_VERSIONED_DATA, "true" );
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
// account for Oracle's deprecated support for LONGVARBINARY...
// prefer BLOB, unless the user opts out of it
boolean preferLong = serviceRegistry.getService( ConfigurationService.class ).getSetting(
PREFER_LONG_RAW,
StandardConverters.BOOLEAN,
false
);
if ( !preferLong ) {
typeContributions.contributeType( MaterializedBlobType.INSTANCE, "byte[]", byte[].class.getName() );
typeContributions.contributeType( WrappedMaterializedBlobType.INSTANCE, "Byte[]", Byte[].class.getName() );
}
}
@Override
protected void registerDefaultProperties() {
super.registerDefaultProperties();
getDefaultProperties().setProperty( Environment.USE_GET_GENERATED_KEYS, "true" );
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "sequence";
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new Oracle12cIdentityColumnSupport();
super(12);
}
}

View File

@ -1,40 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.jboss.logging.Logger;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
/**
* An SQL dialect for Oracle 9 (uses ANSI-style syntax where possible).
*
* @author Gavin King
* @author David Channon
*
* @deprecated Use either Oracle9iDialect or Oracle10gDialect instead
*/
@SuppressWarnings("deprecation")
@Deprecated
public class Oracle9Dialect extends Oracle9iDialect {
}

View File

@ -6,215 +6,21 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.LockOptions;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ANSICaseFragment;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
/**
* A dialect for Oracle 9i databases.
* <p/>
* Specifies to not use "ANSI join syntax" because 9i does not seem to properly handle it in all cases.
* Specifies to not use "ANSI join syntax" because 9i does not
* seem to properly handle it in all cases.
*
* @author Steve Ebersole
*
* @deprecated use {@code OracleDialect(9)}
*/
public class Oracle9iDialect extends Oracle8iDialect {
@Deprecated
public class Oracle9iDialect extends OracleDialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
sql = sql.trim();
String forUpdateClause = null;
boolean isForUpdate = false;
final int forUpdateIndex = sql.toLowerCase(Locale.ROOT).lastIndexOf( "for update" );
if (forUpdateIndex > -1) {
// save 'for update ...' and then remove it
forUpdateClause = sql.substring( forUpdateIndex );
sql = sql.substring( 0, forUpdateIndex - 1 );
isForUpdate = true;
}
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if (hasOffset) {
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " );
}
else {
pagingSelect.append( "select * from ( " );
}
pagingSelect.append( sql );
if (hasOffset) {
pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" );
}
else {
pagingSelect.append( " ) where rownum <= ?" );
}
if (isForUpdate) {
pagingSelect.append( " " );
pagingSelect.append( forUpdateClause );
}
return pagingSelect.toString();
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
};
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
//Oracle has had coalesce() since 9.0.1
CommonFunctionFactory.coalesce( queryEngine );
public Oracle9iDialect() {
super(9);
}
@Override
protected void registerCharacterTypeMappings() {
registerColumnType( Types.CHAR, "char(1 char)" );
registerColumnType( Types.VARCHAR, 4000, "varchar2($l char)" );
registerColumnType( Types.VARCHAR, "long" );
registerColumnType( Types.NVARCHAR, "nvarchar2($l)" );
registerColumnType( Types.LONGNVARCHAR, "nvarchar2($l)" );
}
@Override
protected void registerDateTimeTypeMappings() {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "date" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
}
@Override
public CaseFragment createCaseFragment() {
// Oracle did add support for ANSI CASE statements in 9i
return new ANSICaseFragment();
}
@Override
public CaseExpressionWalker getCaseExpressionWalker() {
return ANSICaseExpressionWalker.INSTANCE;
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
String forUpdateClause = null;
boolean isForUpdate = false;
final int forUpdateIndex = sql.toLowerCase(Locale.ROOT).lastIndexOf( "for update") ;
if ( forUpdateIndex > -1 ) {
// save 'for update ...' and then remove it
forUpdateClause = sql.substring( forUpdateIndex );
sql = sql.substring( 0, forUpdateIndex-1 );
isForUpdate = true;
}
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if (hasOffset) {
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " );
}
else {
pagingSelect.append( "select * from ( " );
}
pagingSelect.append( sql );
if (hasOffset) {
pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" );
}
else {
pagingSelect.append( " ) where rownum <= ?" );
}
if ( isForUpdate ) {
pagingSelect.append( " " );
pagingSelect.append( forUpdateClause );
}
return pagingSelect.toString();
}
@Override
public String getSelectClauseNullString(int sqlType) {
return getBasicSelectClauseNullString( sqlType );
}
@Override
public String getCurrentTimestampSelectString() {
return "select systimestamp from dual";
}
@Override
public String getCurrentTimestampSQLFunctionName() {
// the standard SQL function name is current_timestamp...
return "current_timestamp";
}
@Override
public String getForUpdateString() {
return " for update";
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return " for update nowait";
}
else if ( timeout > 0 ) {
// convert from milliseconds to seconds
final float seconds = timeout / 1000.0f;
timeout = Math.round( seconds );
return " for update wait " + timeout;
}
else {
return " for update";
}
}
@Override
public String getReadLockString(int timeout) {
return getWriteLockString( timeout );
}
/**
* HHH-4907, I don't know if oracle 8 supports this syntax, so I'd think it is better add this
* method here. Reopen this issue if you found/know 8 supports it.
* <p/>
* {@inheritDoc}
*/
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
}

View File

@ -6,19 +6,12 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.lock.*;
import org.hibernate.persister.entity.Lockable;
import java.sql.Types;
/**
* A Dialect for Pointbase.
*
@ -31,25 +24,16 @@ public class PointbaseDialect extends org.hibernate.dialect.Dialect {
public PointbaseDialect() {
super();
//no pointbase BIT
registerColumnType( Types.BIT, 1, "smallint" );
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.SMALLINT, "smallint" );
//no pointbase TINYINT
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double precision" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
//no precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
//the BLOB type requires a size arguement - this defaults to
//bytes - no arg defaults to 1 whole byte!
//other argument mods include K - kilobyte, M - megabyte, G - gigabyte.
//refer to the PBdevelopers guide for more info.
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
registerColumnType( Types.VARBINARY, "blob($l)" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
}
@Override
@ -75,22 +59,19 @@ public class PointbaseDialect extends org.hibernate.dialect.Dialect {
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// Pointbase has no known variation of a "SELECT ... FOR UPDATE" syntax...
if ( lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode);
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_WRITE) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.PESSIMISTIC_READ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC) {
return new OptimisticLockingStrategy( lockable, lockMode);
}
else if ( lockMode==LockMode.OPTIMISTIC_FORCE_INCREMENT) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode);
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {

View File

@ -1,21 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.PostgreSQL10IdentityColumnSupport;
/**
* An SQL dialect for Postgres 10 and later.
*/
public class PostgreSQL10Dialect extends PostgreSQL95Dialect {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new PostgreSQL10IdentityColumnSupport();
}
}

View File

@ -6,874 +6,15 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.PostgresExtractEmulation;
import org.hibernate.dialect.function.Replacer;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.PostgreSQL81IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.PostgresCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlTreeCreationException;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import static org.hibernate.query.TemporalUnit.DAY;
import static org.hibernate.query.TemporalUnit.EPOCH;
import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.QUARTER;
import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.query.TemporalUnit.conversionFactor;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiDateLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiTimeLiteral;
/**
* An SQL dialect for Postgres
* <p/>
* For discussion of BLOB support in Postgres, as of 8.4, have a peek at
* <a href="http://jdbc.postgresql.org/documentation/84/binary-data.html">http://jdbc.postgresql.org/documentation/84/binary-data.html</a>.
* For the effects in regards to Hibernate see <a href="http://in.relation.to/15492.lace">http://in.relation.to/15492.lace</a>
*
* @author Gavin King
* @deprecated use {@code PostgreSQLDialect(810)}
*/
@SuppressWarnings("deprecation")
public class PostgreSQL81Dialect extends Dialect {
@Deprecated
public class PostgreSQL81Dialect extends PostgreSQLDialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" );
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
};
/**
* Constructs a PostgreSQL81Dialect
*/
public PostgreSQL81Dialect() {
super();
registerColumnType( Types.BIT, "bool" );
registerColumnType( Types.BIGINT, "int8" );
registerColumnType( Types.SMALLINT, "int2" );
registerColumnType( Types.TINYINT, "int2" );
registerColumnType( Types.INTEGER, "int4" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float4" );
registerColumnType( Types.DOUBLE, "float8" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "bytea" );
registerColumnType( Types.BINARY, "bytea" );
registerColumnType( Types.LONGVARCHAR, "text" );
registerColumnType( Types.LONGVARBINARY, "bytea" );
registerColumnType( Types.CLOB, "text" );
registerColumnType( Types.BLOB, "oid" );
registerColumnType( Types.NUMERIC, "numeric($p, $s)" );
registerColumnType( Types.OTHER, "uuid" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.md5( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.rand_random( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
queryEngine.getSqmFunctionRegistry().register( "extract", new PostgresExtractEmulation() );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "cbrt" )
.setInvariantType( StandardBasicTypes.DOUBLE )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_date" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_time" )
.setInvariantType( StandardBasicTypes.TIME )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamp" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 6 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamptz" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 6, 7 )
.register();
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
);
}
@Override
public void timestampadd(
TemporalUnit unit,
Renderer magnitude, Renderer to,
Appender sqlAppender,
boolean timestamp) {
sqlAppender.append( "(" );
to.render();
boolean subtract = false;
//TODO: do something nicer for negative magnitude
// if ( magnitude.startsWith("-") ) {
// subtract = true;
// magnitude = magnitude.substring(1);
// }
sqlAppender.append( subtract ? " - " : " + " );
switch ( unit ) {
case NANOSECOND: {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ")/1e3 * interval '1 microsecond'" );
break;
}
//quarter is not supported in interval literals
case QUARTER: {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ") * interval '3 month'" );
break;
}
default: {
//TODO: do something nicer for literal magnitude
// if ( magnitude.matches("\\d+") ) {
// sqlAppender.append("interval '");
// sqlAppender.append( magnitude );
// }
// else {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ") * interval '1" );
// }
sqlAppender.append( " " );
sqlAppender.append( unit.toString() );
sqlAppender.append( "'" );
}
}
sqlAppender.append( ")" );
}
@Override
public void timestampdiff(
TemporalUnit unit,
Renderer from, Renderer to,
Appender sqlAppender,
boolean fromTimestamp, boolean toTimestamp) {
if ( !toTimestamp && !fromTimestamp && unit == DAY ) {
// special case: subtraction of two dates
// results in an integer number of days
// instead of an INTERVAL
sqlAppender.append( "(" );
to.render();
sqlAppender.append( "-" );
from.render();
sqlAppender.append( ")" );
}
else {
switch ( unit ) {
case YEAR: {
extractField( sqlAppender, from, to, YEAR, fromTimestamp, toTimestamp, unit );
break;
}
case QUARTER: {
sqlAppender.append( "(" );
extractField( sqlAppender, from, to, YEAR, fromTimestamp, toTimestamp, unit );
sqlAppender.append( "+" );
extractField( sqlAppender, from, to, QUARTER, fromTimestamp, toTimestamp, unit );
sqlAppender.append( ")" );
break;
}
case MONTH: {
sqlAppender.append( "(" );
extractField( sqlAppender, from, to, YEAR, fromTimestamp, toTimestamp, unit );
sqlAppender.append( "+" );
extractField( sqlAppender, from, to, MONTH, fromTimestamp, toTimestamp, unit );
sqlAppender.append( ")" );
break;
}
//week is not supported by extract() when the argument is a duration
case WEEK:
case DAY: {
extractField( sqlAppender, from, to, DAY, fromTimestamp, toTimestamp, unit );
break;
}
case HOUR:
case MINUTE:
case SECOND:
case NANOSECOND: {
extractField( sqlAppender, from, to, EPOCH, fromTimestamp, toTimestamp, unit );
break;
}
default: {
throw new SqlTreeCreationException( "unrecognized field: " + unit );
}
}
}
}
private void extractField(
Appender sqlAppender,
Renderer from, Renderer to,
TemporalUnit unit,
boolean fromTimestamp, boolean toTimestamp,
TemporalUnit toUnit) {
sqlAppender.append( "extract(" );
sqlAppender.append( unit.toString() );
sqlAppender.append( " from " );
if ( !toTimestamp && !fromTimestamp ) {
// special case subtraction of two
// dates results in an integer not
// an Interval
sqlAppender.append( "age(" );
to.render();
sqlAppender.append( "," );
from.render();
sqlAppender.append( ")" );
}
else {
switch ( unit ) {
case YEAR:
case MONTH:
case QUARTER: {
sqlAppender.append( "age(" );
to.render();
sqlAppender.append( "," );
from.render();
sqlAppender.append( ")" );
break;
}
case DAY:
case HOUR:
case MINUTE:
case SECOND:
case EPOCH: {
to.render();
sqlAppender.append( "-" );
from.render();
break;
}
default: {
throw new SqlTreeCreationException( unit + " is not a legal field" );
}
}
}
sqlAppender.append( ")" );
sqlAppender.append( conversionFactor( unit, toUnit ) );
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
}
public Replacer datetimeFormat(String format) {
return Oracle8iDialect.datetimeFormat( format, true )
.replace( "SSSSSS", "US" )
.replace( "SSSSS", "US" )
.replace( "SSSS", "US" )
.replace( "SSS", "MS" )
.replace( "SS", "MS" )
.replace( "S", "MS" )
//use ISO day in week, as per DateTimeFormatter
.replace( "ee", "ID" )
.replace( "e", "fmID" )
//TZR is TZ in Postgres
.replace( "zzz", "TZ" )
.replace( "zz", "TZ" )
.replace( "z", "TZ" );
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
//WEEK means the ISO week number on Postgres
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
default: return unit.toString();
}
}
@Override
protected String wrapDateLiteral(String date) {
return wrapAsAnsiDateLiteral( date );
}
@Override
protected String wrapTimeLiteral(String time) {
return wrapAsAnsiTimeLiteral( time );
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "timestamp with time zone '" + timestamp + "'";
}
@Override
public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
SqlTypeDescriptor descriptor;
switch ( sqlCode ) {
case Types.BLOB: {
// Force BLOB binding. Otherwise, byte[] fields annotated
// with @Lob will attempt to use
// BlobTypeDescriptor.PRIMITIVE_ARRAY_BINDING. Since the
// dialect uses oid for Blobs, byte arrays cannot be used.
descriptor = BlobTypeDescriptor.BLOB_BINDING;
break;
}
case Types.CLOB: {
descriptor = ClobTypeDescriptor.CLOB_BINDING;
break;
}
default: {
descriptor = super.getSqlTypeDescriptorOverride( sqlCode );
break;
}
}
return descriptor;
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "nextval ('" + sequenceName + "')";
}
@Override
public String getCreateSequenceString(String sequenceName) {
//starts with 1, implicitly
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
}
@Override
public String getCascadeConstraintsString() {
return " cascade";
}
@Override
public boolean dropConstraints() {
return true;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public String getQuerySequencesString() {
return "select * from information_schema.sequences";
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" );
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public String getForUpdateString(String aliases) {
return getForUpdateString() + " of " + aliases;
}
@Override
public String getForUpdateString(String aliases, LockOptions lockOptions) {
/*
* Parent's implementation for (aliases, lockOptions) ignores aliases.
*/
if ( "".equals( aliases ) ) {
LockMode lockMode = lockOptions.getLockMode();
final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator();
while ( itr.hasNext() ) {
// seek the highest lock mode
final Map.Entry<String, LockMode> entry = itr.next();
final LockMode lm = entry.getValue();
if ( lm.greaterThan( lockMode ) ) {
aliases = entry.getKey();
}
}
}
LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases );
if ( lockMode == null ) {
lockMode = lockOptions.getLockMode();
}
switch ( lockMode ) {
case UPGRADE:
return getForUpdateString( aliases );
case PESSIMISTIC_READ:
return getReadLockString( aliases, lockOptions.getTimeOut() );
case PESSIMISTIC_WRITE:
return getWriteLockString( aliases, lockOptions.getTimeOut() );
case UPGRADE_NOWAIT:
case FORCE:
case PESSIMISTIC_FORCE_INCREMENT:
return getForUpdateNowaitString( aliases );
case UPGRADE_SKIPLOCKED:
return getForUpdateSkipLockedString( aliases );
default:
return "";
}
}
@Override
public String getNoColumnsInsertString() {
return "default values";
}
@Override
public String getCaseInsensitiveLike() {
return "ilike";
}
@Override
public boolean supportsCaseInsensitiveLike() {
return true;
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "sequence";
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public boolean useInputStreamToInsertBlob() {
return false;
}
@Override
public boolean supportsUnionAll() {
return true;
}
/**
* Workaround for postgres bug #1453
* <p/>
* {@inheritDoc}
*/
@Override
public String getSelectClauseNullString(int sqlType) {
String typeName = getTypeName( sqlType, 1, 1, 0 );
//trim off the length/precision/scale
final int loc = typeName.indexOf( '(' );
if ( loc > -1 ) {
typeName = typeName.substring( 0, loc );
}
return "null::" + typeName;
}
@Override
public boolean supportsCommentOn() {
return true;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, base -> "HT_" + base ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
return "create temporary table";
}
@Override
protected String getCreateOptions() {
return "on commit drop";
}
},
AfterUseAction.CLEAN,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select now()";
}
@Override
public boolean requiresParensForTupleDistinctCounts() {
return true;
}
@Override
public String toBooleanValueString(boolean bool) {
return bool ? "true" : "false";
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
/**
* Constraint-name extractor for Postgres constraint violation exceptions.
* Originally contributed by Denny Bartelt.
*/
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
final int sqlState = Integer.parseInt( JdbcExceptionHelper.extractSqlState( sqle ) );
switch ( sqlState ) {
// CHECK VIOLATION
case 23514:
return extractUsingTemplate( "violates check constraint \"", "\"", sqle.getMessage() );
// UNIQUE VIOLATION
case 23505:
return extractUsingTemplate( "violates unique constraint \"", "\"", sqle.getMessage() );
// FOREIGN KEY VIOLATION
case 23503:
return extractUsingTemplate( "violates foreign key constraint \"", "\"", sqle.getMessage() );
// NOT NULL VIOLATION
case 23502:
return extractUsingTemplate(
"null value in column \"",
"\" violates not-null constraint",
sqle.getMessage()
);
// TODO: RESTRICT VIOLATION
case 23001:
return null;
// ALL OTHER
default:
return null;
}
}
};
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
if ( "40P01".equals( sqlState ) ) {
// DEADLOCK DETECTED
return new LockAcquisitionException( message, sqlException, sql );
}
if ( "55P03".equals( sqlState ) ) {
// LOCK NOT AVAILABLE
return new PessimisticLockException( message, sqlException, sql );
}
// returning null allows other delegates to operate
return null;
}
};
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
// Register the type of the out param - PostgreSQL uses Types.OTHER
statement.registerOutParameter( col++, Types.OTHER );
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
ps.execute();
return (ResultSet) ps.getObject( 1 );
}
@Override
public boolean supportsPooledSequences() {
return true;
}
/**
* only necessary for postgre < 7.4 See http://anoncvs.postgresql.org/cvsweb.cgi/pgsql/doc/src/sgml/ref/create_sequence.sgml
* <p/>
* {@inheritDoc}
*/
@Override
protected String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) {
if ( initialValue < 0 && incrementSize > 0 ) {
return
String.format(
"%s minvalue %d start %d increment %d",
getCreateSequenceString( sequenceName ),
initialValue,
initialValue,
incrementSize
);
}
else if ( initialValue > 0 && incrementSize < 0 ) {
return
String.format(
"%s maxvalue %d start %d increment %d",
getCreateSequenceString( sequenceName ),
initialValue,
initialValue,
incrementSize
);
}
else {
return
String.format(
"%s start %d increment %d",
getCreateSequenceString( sequenceName ),
initialValue,
incrementSize
);
}
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean supportsExpectedLobUsagePattern() {
return true;
}
@Override
public boolean supportsLobValueChangePropogation() {
return false;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
return false;
}
@Override
public String getForUpdateString() {
return " for update";
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return " for update nowait";
}
else {
return " for update";
}
}
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return String.format( " for update of %s nowait", aliases );
}
else {
return " for update of " + aliases;
}
}
@Override
public String getReadLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return " for share nowait";
}
else {
return " for share";
}
}
@Override
public String getReadLockString(String aliases, int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return String.format( " for share of %s nowait", aliases );
}
else {
return " for share of " + aliases;
}
}
@Override
public boolean supportsRowValueConstructorSyntax() {
return true;
}
@Override
public String getForUpdateNowaitString() {
return getForUpdateString() + " nowait ";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateString( aliases ) + " nowait ";
}
@Override
public CallableStatementSupport getCallableStatementSupport() {
return PostgresCallableStatementSupport.INSTANCE;
}
@Override
public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
if ( position != 1 ) {
throw new UnsupportedOperationException(
"PostgreSQL only supports REF_CURSOR parameters as the first parameter"
);
}
return (ResultSet) statement.getObject( 1 );
}
@Override
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException( "PostgreSQL only supports accessing REF_CURSOR parameters by position" );
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new PostgreSQL81IdentityColumnSupport();
}
@Override
public boolean supportsNationalizedTypes() {
return false;
}
@Override
public boolean supportsNoWait() {
return true;
}
@Override
public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) {
return false;
}
@Override
public boolean supportsSelectAliasInGroupByClause() {
return true;
super(810);
}
}

View File

@ -6,67 +6,18 @@
*/
package org.hibernate.dialect;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.PostgresUUIDType;
/**
* An SQL dialect for Postgres 8.2 and later, adds support for "if exists" when dropping tables
*
* @author edalquist
*
* @deprecated use {@code PostgreSQLDialect(820)}
*/
public class PostgreSQL82Dialect extends PostgreSQL81Dialect {
@Override
public boolean supportsIfExistsBeforeTableName() {
return true;
@Deprecated
public class PostgreSQL82Dialect extends PostgreSQLDialect {
public PostgreSQL82Dialect() {
super(820);
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
// HHH-9562
typeContributions.contributeType( PostgresUUIDType.INSTANCE );
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
// return new LocalTemporaryTableBulkIdStrategy(
// new IdTableSupportStandardImpl() {
// @Override
// public String getCreateIdTableCommand() {
// return "create temporary table";
// }
//
// @Override
// public String getDropIdTableCommand() {
// return "drop table";
// }
// },
// AfterUseAction.DROP,
// null
// );
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence if exists " + sequenceName;
}
@Override
public boolean supportsValuesList() {
return true;
}
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
}

View File

@ -7,19 +7,18 @@
package org.hibernate.dialect;
/**
* An SQL dialect for Postgres 9.1 and later, adds support for PARTITION BY as a keyword.
* An SQL dialect for Postgres 9.1 and later,
* adds support for PARTITION BY as a keyword.
*
* @author Mark Robinson
*
* @deprecated use {@code PostgreSQLDialect(910)}
*/
public class PostgreSQL91Dialect extends PostgreSQL9Dialect {
@Deprecated
public class PostgreSQL91Dialect extends PostgreSQLDialect {
@Override
public boolean supportsPartitionBy() {
return true;
public PostgreSQL91Dialect() {
super(910);
}
@Override
public boolean supportsNonQueryWithCTE() {
return true;
}
}

View File

@ -6,26 +6,20 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
/**
* An SQL dialect for Postgres 9.2 and later, adds support for JSON data type
* An SQL dialect for Postgres 9.2 and later,
* adds support for JSON data type, and IF EXISTS
* after ALTER TABLE.
*
* @author Mark Robinson
*
* @deprecated use {@code PostgreSQLDialect(920)}
*/
public class PostgreSQL92Dialect extends PostgreSQL91Dialect {
@Deprecated
public class PostgreSQL92Dialect extends PostgreSQLDialect {
/**
* Constructs a PostgreSQL92Dialect
*/
public PostgreSQL92Dialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
@Override
public boolean supportsIfExistsAfterAlterTable() {
return true;
super(920);
}
}

View File

@ -6,18 +6,19 @@
*/
package org.hibernate.dialect;
import java.util.List;
/**
* An SQL Dialect for PostgreSQL 9.3 and later. Adds support for Materialized view.
* An SQL Dialect for PostgreSQL 9.3 and later.
* Adds support for Materialized view.
*
* @author Dionis Argiri
*
* @deprecated use {@code PostgreSQLDialect(810)}
*/
public class PostgreSQL93Dialect extends PostgreSQL92Dialect {
@Deprecated
public class PostgreSQL93Dialect extends PostgreSQLDialect {
@Override
public void augmentRecognizedTableTypes(List<String> tableTypesList) {
super.augmentRecognizedTableTypes( tableTypesList );
tableTypesList.add( "MATERIALIZED VIEW" );
public PostgreSQL93Dialect() {
super(930);
}
}

View File

@ -6,45 +6,17 @@
*/
package org.hibernate.dialect;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
/**
* An SQL dialect for Postgres 9.4 and later. Adds support for various date and time functions
* An SQL dialect for Postgres 9.4 and later.
* Adds support for various date and time functions
*
* @deprecated use {@code PostgreSQLDialect(940)}
*/
public class PostgreSQL94Dialect extends PostgreSQL93Dialect {
@Deprecated
public class PostgreSQL94Dialect extends PostgreSQLDialect {
/**
* Constructs a PostgreSQL94Dialect
*/
@SuppressWarnings("WeakerAccess")
public PostgreSQL94Dialect() {
super();
super(940);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_interval" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 1, 7 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamp" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 6 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamptz" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 6, 7 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_date" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_time" )
.setInvariantType( StandardBasicTypes.TIME )
.setExactArgumentCount( 3 )
.register();
}
}

View File

@ -6,65 +6,17 @@
*/
package org.hibernate.dialect;
import org.hibernate.LockOptions;
/**
* An SQL dialect for Postgres 9.5 and later. Adds support for SKIP LOCKED.
* An SQL dialect for Postgres 9.5 and later.
* Adds support for SKIP LOCKED.
*
* @deprecated use {@code PostgreSQLDialect(950)}
*/
public class PostgreSQL95Dialect extends PostgreSQL94Dialect {
@Deprecated
public class PostgreSQL95Dialect extends PostgreSQLDialect {
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString();
}
else {
return super.getWriteLockString( timeout );
}
public PostgreSQL95Dialect() {
super(950);
}
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString( aliases );
}
else {
return super.getWriteLockString( aliases, timeout );
}
}
@Override
public String getReadLockString(int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return " for share skip locked";
}
else {
return super.getReadLockString( timeout );
}
}
@Override
public String getReadLockString(String aliases, int timeout) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
return String.format( " for share of %s skip locked", aliases );
}
else {
return super.getReadLockString( aliases, timeout );
}
}
@Override
public String getForUpdateSkipLockedString() {
return " for update skip locked";
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
return getForUpdateString() + " of " + aliases + " skip locked";
}
@Override
public boolean supportsSkipLocked() {
return true;
}
}

View File

@ -6,25 +6,19 @@
*/
package org.hibernate.dialect;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.query.spi.QueryEngine;
/**
* An SQL dialect for Postgres 9 and later. Adds support for "if exists" when dropping constraints
* An SQL dialect for Postgres 9 and later.
* Adds support for "if exists" when dropping constraints
*
* @author edalquist
*
* @deprecated use {@code PostgreSQLDialect(900)}
*/
public class PostgreSQL9Dialect extends PostgreSQL82Dialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.soundex( queryEngine );
@Deprecated
public class PostgreSQL9Dialect extends PostgreSQLDialect {
public PostgreSQL9Dialect() {
super(900);
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return true;
}
}

View File

@ -6,17 +6,874 @@
*/
package org.hibernate.dialect;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.PostgreSQLIdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.PostgresCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import java.sql.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.hibernate.query.TemporalUnit.*;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiDateLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiTimeLiteral;
/**
* An SQL dialect for Postgres
* <p/>
* For discussion of BLOB support in Postgres, as of 8.4, have a peek at
* <a href="http://jdbc.postgresql.org/documentation/84/binary-data.html">http://jdbc.postgresql.org/documentation/84/binary-data.html</a>.
* For the effects in regards to Hibernate see <a href="http://in.relation.to/15492.lace">http://in.relation.to/15492.lace</a>
* An SQL dialect for Postgres 8 and above.
*
* @author Gavin King
*
* @deprecated use {@link PostgreSQL82Dialect} instead
*/
@Deprecated
public class PostgreSQLDialect extends PostgreSQL82Dialect {
public class PostgreSQLDialect extends Dialect {
private final int version;
int getVersion() {
return version;
}
public PostgreSQLDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
public PostgreSQLDialect() {
this(800);
}
public PostgreSQLDialect(int version) {
super();
this.version = version;
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint, not even in Postgres 11
registerColumnType( Types.VARBINARY, "bytea" );
registerColumnType( Types.BINARY, "bytea" );
registerColumnType( Types.BLOB, "bytea" );
registerColumnType( Types.CLOB, "text" );
//there are no nchar/nvarchar types in Postgres
registerColumnType( Types.NCHAR, "char($l)" );
registerColumnType( Types.NVARCHAR, "varchar($l)" );
//since there's no real difference between
//TEXT and VARCHAR, except for the length limit,
//we can just use 'text' for the "long" types
registerColumnType( Types.LONGVARCHAR, "text" );
registerColumnType( Types.LONGNVARCHAR, "text" );
if ( getVersion() >= 920 ) {
registerColumnType( Types.JAVA_OBJECT, "json" );
}
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" );
}
/**
* The {@code extract()} function returns {@link TemporalUnit#DAY_OF_WEEK}
* numbered from 0 to 6. This isn't consistent with what most other
* databases do, so here we adjust the result by generating
* {@code (extract(dow,arg)+1))}.
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch ( unit ) {
case DAY_OF_WEEK:
return "(" + super.extractPattern(unit) + "+1)";
default:
return super.extractPattern(unit);
}
}
/**
* {@code microsecond} is the smallest unit for an {@code interval},
* and the highest precision for a {@code timestamp}, so we could
* use it as the "native" precision, but it's more convenient to use
* whole seconds (with the fractional part), since we want to use
* {@code extract(epoch from ...)} in our emulation of
* {@code timestampdiff()}.
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000_000_000; //seconds
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e3 * interval '1 microsecond')";
case NATIVE:
return "(?3 + (?2) * interval '1 second')";
case QUARTER: //quarter is not supported in interval literals
return "(?3 + (?2) * interval '3 month')";
case WEEK: //week is not supported in interval literals
return "(?3 + (?2) * interval '7 day')";
default:
return "(?3 + (?2) * interval '1 ?1')";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
if ( !toTimestamp && !fromTimestamp && unit==DAY ) {
// special case: subtraction of two dates
// results in an integer number of days
// instead of an INTERVAL
return "(?3-?2)";
}
else {
StringBuilder pattern = new StringBuilder();
switch (unit) {
case YEAR:
extractField(pattern, YEAR, fromTimestamp, toTimestamp, unit);
break;
case QUARTER:
pattern.append("(");
extractField(pattern, YEAR, fromTimestamp, toTimestamp, unit);
pattern.append("+");
extractField(pattern, QUARTER, fromTimestamp, toTimestamp, unit);
pattern.append(")");
break;
case MONTH:
pattern.append("(");
extractField(pattern, YEAR, fromTimestamp, toTimestamp, unit);
pattern.append("+");
extractField(pattern, MONTH, fromTimestamp, toTimestamp, unit);
pattern.append(")");
break;
case WEEK: //week is not supported by extract() when the argument is a duration
case DAY:
extractField(pattern, DAY, fromTimestamp, toTimestamp, unit);
break;
//in order to avoid multiple calls to extract(),
//we use extract(epoch from x - y) * factor for
//all the following units:
case HOUR:
case MINUTE:
case SECOND:
case NANOSECOND:
case NATIVE:
extractField(pattern, EPOCH, fromTimestamp, toTimestamp, unit);
break;
default:
throw new SemanticException("unrecognized field: " + unit);
}
return pattern.toString();
}
}
private void extractField(
StringBuilder pattern,
TemporalUnit unit,
boolean fromTimestamp, boolean toTimestamp,
TemporalUnit toUnit) {
pattern.append("extract(");
pattern.append( translateDurationField(unit) );
pattern.append(" from ");
if ( !toTimestamp && !fromTimestamp ) {
// special case subtraction of two
// dates results in an integer not
// an Interval
pattern.append("age(?3,?2)");
}
else {
switch (unit) {
case YEAR:
case MONTH:
case QUARTER:
pattern.append("age(?3,?2)");
break;
case DAY:
case HOUR:
case MINUTE:
case SECOND:
case EPOCH:
pattern.append("?3-?2");
break;
default:
throw new SemanticException(unit + " is not a legal field");
}
}
pattern.append(")").append( unit.conversionFactor( toUnit, this ) );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.radians( queryEngine );
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.cbrt( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.md5( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.localtimeLocaltimestamp( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.bitandorxornot_operator( queryEngine );
CommonFunctionFactory.bitAndOr( queryEngine );
CommonFunctionFactory.everyAny_boolAndOr( queryEngine );
CommonFunctionFactory.median_percentileCont( queryEngine, false );
CommonFunctionFactory.stddev( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.variance( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
CommonFunctionFactory.insert_overlay( queryEngine );
CommonFunctionFactory.overlay( queryEngine );
CommonFunctionFactory.soundex( queryEngine ); //was introduced in Postgres 9 apparently
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
).setArgumentListSignature("(pattern, string[, start])");
if ( getVersion() >= 940 ) {
CommonFunctionFactory.makeDateTimeTimestamp( queryEngine );
}
}
@Override
public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
// For discussion of BLOB support in Postgres, as of 8.4, have a peek at
// <a href="http://jdbc.postgresql.org/documentation/84/binary-data.html">http://jdbc.postgresql.org/documentation/84/binary-data.html</a>.
// For the effects in regards to Hibernate see <a href="http://in.relation.to/15492.lace">http://in.relation.to/15492.lace</a>
switch ( sqlCode ) {
case Types.BLOB:
// Force BLOB binding. Otherwise, byte[] fields annotated
// with @Lob will attempt to use
// BlobTypeDescriptor.PRIMITIVE_ARRAY_BINDING. Since the
// dialect uses oid for Blobs, byte arrays cannot be used.
return BlobTypeDescriptor.BLOB_BINDING;
case Types.CLOB:
return ClobTypeDescriptor.CLOB_BINDING;
default:
return super.getSqlTypeDescriptorOverride( sqlCode );
}
}
@Override
public boolean supportsIfExistsBeforeTableName() {
return getVersion() >= 820;
}
@Override
public boolean supportsIfExistsBeforeConstraintName() {
return getVersion() >= 900;
}
@Override
public boolean supportsIfExistsAfterAlterTable() {
return getVersion() >= 920;
}
@Override
public boolean supportsValuesList() {
return getVersion() >= 820;
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return getVersion() >= 820;
}
@Override
public boolean supportsPartitionBy() {
return getVersion() >= 910;
}
@Override
public boolean supportsNonQueryWithCTE() {
return getVersion() >= 910;
}
@Override
public SequenceSupport getSequenceSupport() {
return getVersion() < 820
? PostgreSQLSequenceSupport.LEGACY_INSTANCE
: PostgreSQLSequenceSupport.INSTANCE;
}
@Override
public String getCascadeConstraintsString() {
return " cascade";
}
@Override
public String getQuerySequencesString() {
return "select * from information_schema.sequences";
}
@Override
public LimitHandler getLimitHandler() {
return getVersion() < 840
? LimitOffsetLimitHandler.INSTANCE
: OffsetFetchLimitHandler.INSTANCE;
}
@Override
public String getForUpdateString(String aliases) {
return getForUpdateString() + " of " + aliases;
}
@Override
public String getForUpdateString(String aliases, LockOptions lockOptions) {
/*
* Parent's implementation for (aliases, lockOptions) ignores aliases.
*/
if ( aliases.isEmpty() ) {
LockMode lockMode = lockOptions.getLockMode();
final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator();
while ( itr.hasNext() ) {
// seek the highest lock mode
final Map.Entry<String, LockMode> entry = itr.next();
final LockMode lm = entry.getValue();
if ( lm.greaterThan( lockMode ) ) {
aliases = entry.getKey();
}
}
}
LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases );
if (lockMode == null ) {
lockMode = lockOptions.getLockMode();
}
switch ( lockMode ) {
//noinspection deprecation
case UPGRADE:
return getForUpdateString(aliases);
case PESSIMISTIC_READ:
return getReadLockString( aliases, lockOptions.getTimeOut() );
case PESSIMISTIC_WRITE:
return getWriteLockString( aliases, lockOptions.getTimeOut() );
case UPGRADE_NOWAIT:
//noinspection deprecation
case FORCE:
case PESSIMISTIC_FORCE_INCREMENT:
return getForUpdateNowaitString(aliases);
case UPGRADE_SKIPLOCKED:
return getForUpdateSkipLockedString(aliases);
default:
return "";
}
}
@Override
public String getNoColumnsInsertString() {
return "default values";
}
@Override
public String getCaseInsensitiveLike(){
return "ilike";
}
@Override
public boolean supportsCaseInsensitiveLike() {
return true;
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return "sequence";
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public boolean useInputStreamToInsertBlob() {
return false;
}
@Override
public boolean supportsUnionAll() {
return true;
}
/**
* Workaround for postgres bug #1453
* <p/>
* {@inheritDoc}
*/
@Override
public String getSelectClauseNullString(int sqlType) {
return "null::" + getRawTypeName( sqlType );
}
@Override
public boolean supportsCommentOn() {
return true;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select now()";
}
@Override
public boolean requiresParensForTupleDistinctCounts() {
return true;
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
}
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, base -> "HT_" + base ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
return "create temporary table";
}
@Override
protected String getCreateOptions() {
return "on commit drop";
}
},
AfterUseAction.CLEAN,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
/**
* Constraint-name extractor for Postgres constraint violation exceptions.
* Orginally contributed by Denny Bartelt.
*/
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
final int sqlState = Integer.valueOf( JdbcExceptionHelper.extractSqlState( sqle ) );
switch (sqlState) {
// CHECK VIOLATION
case 23514: return extractUsingTemplate( "violates check constraint \"","\"", sqle.getMessage() );
// UNIQUE VIOLATION
case 23505: return extractUsingTemplate( "violates unique constraint \"","\"", sqle.getMessage() );
// FOREIGN KEY VIOLATION
case 23503: return extractUsingTemplate( "violates foreign key constraint \"","\"", sqle.getMessage() );
// NOT NULL VIOLATION
case 23502: return extractUsingTemplate( "null value in column \"","\" violates not-null constraint", sqle.getMessage() );
// TODO: RESTRICT VIOLATION
case 23001: return null;
// ALL OTHER
default: return null;
}
}
};
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
switch ( sqlState ) {
case "40P01":
// DEADLOCK DETECTED
return new LockAcquisitionException(message, sqlException, sql);
case "55P03":
// LOCK NOT AVAILABLE
return new PessimisticLockException(message, sqlException, sql);
default:
// returning null allows other delegates to operate
return null;
}
}
};
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
// Register the type of the out param - PostgreSQL uses Types.OTHER
statement.registerOutParameter( col++, Types.OTHER );
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
ps.execute();
return (ResultSet) ps.getObject( 1 );
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean supportsLobValueChangePropogation() {
return false;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
return false;
}
@Override
public boolean supportsRowValueConstructorSyntax() {
return true;
}
@Override
public String getForUpdateNowaitString() {
return getForUpdateString() + " nowait ";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateString( aliases ) + " nowait ";
}
@Override
public CallableStatementSupport getCallableStatementSupport() {
return PostgresCallableStatementSupport.INSTANCE;
}
@Override
public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
if ( position != 1 ) {
throw new UnsupportedOperationException( "PostgreSQL only supports REF_CURSOR parameters as the first parameter" );
}
return (ResultSet) statement.getObject( 1 );
}
@Override
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException( "PostgreSQL only supports accessing REF_CURSOR parameters by position" );
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new PostgreSQLIdentityColumnSupport();
}
@Override
public boolean supportsNationalizedTypes() {
return false;
}
@Override
public boolean supportsNoWait() {
return true;
}
@Override
public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) {
return false;
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
}
public Replacer datetimeFormat(String format) {
return OracleDialect.datetimeFormat(format, true)
.replace("SSSSSS", "US")
.replace("SSSSS", "US")
.replace("SSSS", "US")
.replace("SSS", "MS")
.replace("SS", "MS")
.replace("S", "MS")
//use ISO day in week, as per DateTimeFormatter
.replace("ee", "ID")
.replace("e", "fmID")
//TZR is TZ in Postgres
.replace("zzz", "TZ")
.replace("zz", "TZ")
.replace("z", "TZ");
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
//WEEK means the ISO week number on Postgres
case DAY_OF_MONTH: return "day";
case DAY_OF_YEAR: return "doy";
case DAY_OF_WEEK: return "dow";
default: return super.translateExtractField( unit );
}
}
@Override
protected String wrapDateLiteral(String date) {
return wrapAsAnsiDateLiteral(date);
}
@Override
protected String wrapTimeLiteral(String time) {
return wrapAsAnsiTimeLiteral(time);
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "timestamp with time zone '" + timestamp + "'";
}
@Override
public String getWriteLockString(int timeout) {
if ( getVersion() >= 950 && timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString();
}
else if ( timeout == LockOptions.NO_WAIT ) {
return " for update nowait";
}
else {
return " for update";
}
}
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( getVersion() >= 950 && timeout == LockOptions.SKIP_LOCKED ) {
return getForUpdateSkipLockedString( aliases );
}
else if ( timeout == LockOptions.NO_WAIT ) {
return String.format( " for update of %s nowait", aliases );
}
else {
return " for update of " + aliases;
}
}
@Override
public String getReadLockString(int timeout) {
if ( getVersion() >= 950 && timeout == LockOptions.SKIP_LOCKED ) {
return " for share skip locked";
}
else if ( timeout == LockOptions.NO_WAIT ) {
return " for share nowait";
}
else {
return " for share";
}
}
@Override
public String getReadLockString(String aliases, int timeout) {
if ( getVersion() >= 950 && timeout == LockOptions.SKIP_LOCKED ) {
return String.format( " for share of %s skip locked", aliases );
}
else if ( timeout == LockOptions.NO_WAIT ) {
return String.format( " for share of %s nowait", aliases );
}
else {
return " for share of " + aliases;
}
}
@Override
public String getForUpdateSkipLockedString() {
return getVersion() >= 940
? " for update skip locked"
: super.getForUpdateSkipLockedString();
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
return getVersion() >= 940
? getForUpdateString() + " of " + aliases + " skip locked"
: super.getForUpdateSkipLockedString( aliases );
}
@Override
public boolean supportsSkipLocked() {
return getVersion() >= 940;
}
@Override
public void augmentRecognizedTableTypes(List<String> tableTypesList) {
super.augmentRecognizedTableTypes( tableTypesList );
if ( getVersion() >= 930 ) {
tableTypesList.add( "MATERIALIZED VIEW" );
}
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions, serviceRegistry);
if ( getVersion() >= 820 ) {
// HHH-9562
typeContributions.contributeSqlTypeDescriptor( PostgresUUIDType.INSTANCE );
}
}
private static class PostgresUUIDType implements SqlTypeDescriptor {
/**
* Singleton access
*/
private static final PostgresUUIDType INSTANCE = new PostgresUUIDType();
/**
* Postgres reports its UUID type as {@link java.sql.Types#OTHER}. Unfortunately
* it reports a lot of its types as {@link java.sql.Types#OTHER}, making that
* value useless for distinguishing one SqlTypeDescriptor from another.
* So here we define a "magic value" that is a (hopefully no collisions)
* unique key within the {@link org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry}
*/
private static final int JDBC_TYPE_CODE = 3975;
@Override
public int getSqlType() {
return JDBC_TYPE_CODE;
}
@Override
public int getJdbcTypeCode() {
return getSqlType();
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <J> BasicJavaDescriptor<J> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<J>) typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( UUID.class );
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
return null;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions wrapperOptions) throws SQLException {
st.setObject( index, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions.getSession() ), Types.OTHER );
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions wrapperOptions) throws SQLException {
st.setObject( name, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions.getSession() ), Types.OTHER );
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( rs.getObject( position ), wrapperOptions.getSession() );
}
@Override
protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( statement.getObject( position ), wrapperOptions.getSession() );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( statement.getObject( name ), wrapperOptions.getSession() );
}
};
}
}
}

View File

@ -5,7 +5,6 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -19,7 +18,6 @@ import org.hibernate.query.spi.QueryEngine;
*
* @author Jim Mlodgenski
*/
@SuppressWarnings("deprecation")
public class PostgresPlusDialect extends PostgreSQLDialect {
/**
* Constructs a PostgresPlusDialect
@ -34,9 +32,11 @@ public class PostgresPlusDialect extends PostgreSQLDialect {
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.rownumRowid( queryEngine );
CommonFunctionFactory.sysdateSystimestamp( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
CommonFunctionFactory.systimestamp( queryEngine );
// queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() );
}
@Override
@ -45,6 +45,7 @@ public class PostgresPlusDialect extends PostgreSQLDialect {
}
@Override
@SuppressWarnings("deprecation")
public String getCurrentTimestampSQLFunctionName() {
return "sysdate";
}

View File

@ -30,20 +30,27 @@ public class ProgressDialect extends Dialect {
*/
public ProgressDialect() {
super();
registerColumnType( Types.BIT, "bit" );
registerColumnType( Types.BIGINT, "numeric" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.CHAR, "character(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "real" );
registerColumnType( Types.DOUBLE, "double precision" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.BOOLEAN, "bit" );
//'float' is a synonym for 'double precision'
//TODO: return single-precision 'real' when
// precision <= 24
//note: unnecessary in Progress 10
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "float" );
//note: unnecessary in Progress 10
registerColumnType( Types.BIGINT, "numeric(19,0)" );
//no precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "varbinary($l)" );
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp with time zone" );
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
@ -51,11 +58,6 @@ public class ProgressDialect extends Dialect {
return false;
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public boolean qualifyIndexName() {
return false;

View File

@ -6,36 +6,23 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.RDMSExtractEmulation;
import org.hibernate.dialect.function.TransactSQLTrimEmulation;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.lock.*;
import org.hibernate.dialect.pagination.FetchLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.dialect.sequence.RDMSSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.TrimSpec;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DecodeCaseFragment;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.DecodeCaseExpressionWalker;
import org.jboss.logging.Logger;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import java.sql.Types;
/**
* This is the Hibernate dialect for the Unisys 2200 Relational Database (RDMS).
@ -49,61 +36,12 @@ import static org.hibernate.query.TemporalUnit.NANOSECOND;
*
* @author Ploski and Hanson
*/
@SuppressWarnings("deprecation")
public class RDMSOS2200Dialect extends Dialect {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
RDMSOS2200Dialect.class.getName()
);
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
if (hasOffset) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only ";
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
private static final AbstractLimitHandler LEGACY_LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
return sql + " fetch first " + getMaxOrLimit( selection ) + " rows only ";
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
};
/**
* Constructs a RDMSOS2200Dialect
*/
@ -135,32 +73,38 @@ public class RDMSOS2200Dialect extends Dialect {
* The TIMESTAMP literal format is: YYYY-MM-DD HH:MM:SS[.[FFFFFF]]
*
* Note that $l (dollar-L) will use the length value if provided.
* Also new for Hibernate3 is the $p precision and $s (scale) parameters
* Also new for Hibernate3 is the $p percision and $s (scale) parameters
*/
registerColumnType( Types.BIT, "SMALLINT" );
registerColumnType( Types.TINYINT, "SMALLINT" );
registerColumnType( Types.BIGINT, "NUMERIC(21,0)" );
registerColumnType( Types.SMALLINT, "SMALLINT" );
registerColumnType( Types.CHAR, "CHARACTER(1)" );
registerColumnType( Types.DOUBLE, "DOUBLE PRECISION" );
registerColumnType( Types.FLOAT, "FLOAT" );
registerColumnType( Types.REAL, "REAL" );
registerColumnType( Types.INTEGER, "INTEGER" );
registerColumnType( Types.NUMERIC, "NUMERIC(21,$l)" );
registerColumnType( Types.DECIMAL, "NUMERIC(21,$l)" );
registerColumnType( Types.DATE, "DATE" );
registerColumnType( Types.TIME, "TIME" );
registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
registerColumnType( Types.VARCHAR, "CHARACTER($l)" );
registerColumnType( Types.BLOB, "BLOB($l)" );
/*
* The following types are not supported in RDMS/JDBC and therefore commented out.
* However, in some cases, mapping them to CHARACTER columns works
* for many applications, but does not work for all cases.
*/
// registerColumnType(Types.VARBINARY, "CHARACTER($l)");
// registerColumnType(Types.BLOB, "CHARACTER($l)" ); // For use prior to CP 11.0
// registerColumnType(Types.CLOB, "CHARACTER($l)" );
registerColumnType( Types.BIT, 1, "smallint" );
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.BOOLEAN, "smallint" );
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.BIGINT, "numeric(19,0)" );
registerColumnType( Types.BLOB, "blob($l)" );
//no 'binary' nor 'varbinary' so use 'blob'
registerColumnType( Types.BINARY, "blob($l)");
registerColumnType( Types.VARBINARY, "blob($l)");
//'varchar' is not supported in RDMS for OS 2200
//(but it is for other flavors of RDMS)
//'character' means ASCII by default, 'unicode(n)'
//means 'character(n) character set "UCS-2"'
registerColumnType( Types.CHAR, "unicode($l)");
registerColumnType( Types.VARCHAR, "unicode($l)");
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)");
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public int getDefaultDecimalPrecision() {
//the (really low) maximum
return 21;
}
@Override
@ -176,14 +120,15 @@ public class RDMSOS2200Dialect extends Dialect {
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.rand( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.space( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
// CommonFunctionFactory.replicate( queryEngine ); //synonym for more common repeat()
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.yearMonthDay( queryEngine );
CommonFunctionFactory.hourMinuteSecond( queryEngine );
@ -192,81 +137,77 @@ public class RDMSOS2200Dialect extends Dialect {
CommonFunctionFactory.daynameMonthname( queryEngine );
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.leftRight( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
CommonFunctionFactory.insert( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
// RDMS does not directly support the trim() function, we use rtrim() and ltrim()
queryEngine.getSqmFunctionRegistry().register( "trim", new TransactSQLTrimEmulation() );
queryEngine.getSqmFunctionRegistry().register( "extract", new RDMSExtractEmulation() );
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
if ( unit == NANOSECOND ) {
sqlAppender.append("timestampadd('SQL_TSI_FRAC_SECOND'"); //micros
}
else {
sqlAppender.append("dateadd('");
sqlAppender.append( unit.toString() );
sqlAppender.append("'");
}
sqlAppender.append(", ");
if ( unit == NANOSECOND ) {
sqlAppender.append("(");
}
magnitude.render();
if ( unit == NANOSECOND ) {
sqlAppender.append(")/1e3");
}
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
public long getFractionalSecondPrecisionInNanos() {
return 1_000; //microseconds
}
/**
* RDMS supports a limited list of temporal fields in the
* extract() function, but we can emulate some of them by
* using the appropriate named functions instead of
* extract().
*
* Thus, the additional supported fields are
* {@link TemporalUnit#DAY_OF_YEAR},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*
* In addition, the field {@link TemporalUnit#SECOND} is
* redefined to include microseconds.
*/
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
if ( unit == NANOSECOND ) {
sqlAppender.append("timestampdiff('SQL_TSI_FRAC_SECOND'"); //micros
}
else {
sqlAppender.append("datediff('");
sqlAppender.append( unit.toString() );
sqlAppender.append("'");
}
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
if ( unit == NANOSECOND ) {
sqlAppender.append("*1e3");
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case SECOND:
return "(second(?2)+microsecond(?2)/1e6)";
case DAY_OF_WEEK:
return "dayofweek(?2)";
case DAY_OF_MONTH:
return "dayofmonth(?2)";
case DAY_OF_YEAR:
return "dayofyear(?2)";
default:
return "?1(?2)";
}
}
@Override
public String translateDatetimeFormat(String format) {
return Oracle8iDialect.datetimeFormat( format, true ) //Does it really support FM?
.replace("SSSSSS", "MLS")
.replace("SSSSS", "MLS")
.replace("SSSS", "MLS")
.replace("SSS", "MLS")
.replace("SS", "MLS")
.replace("S", "MLS")
.result();
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NANOSECOND:
return "timestampadd('SQL_TSI_FRAC_SECOND', (?2)/1e3, ?3)";
case NATIVE:
return "timestampadd('SQL_TSI_FRAC_SECOND', ?2, ?3)";
default:
return "dateadd('?1', ?2, ?3)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NANOSECOND:
return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)*1e3";
case NATIVE:
return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)";
default:
return "dateadd('?1', ?2, ?3)";
}
}
// Dialect method overrides ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* RDMS does not support qualifying index names with the schema name.
* RDMS does not support qualifing index names with the schema name.
* <p/>
* {@inheritDoc}
*/
@ -338,28 +279,8 @@ public class RDMSOS2200Dialect extends Dialect {
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public String getSequenceNextValString(String sequenceName) {
// The where clause was added to eliminate this statement from Brute Force Searches.
return "select permuted_id('NEXT',31) from rdms.rdms_dummy where key_col = 1 ";
}
@Override
public String getCreateSequenceString(String sequenceName) {
// We must return a valid RDMS/RSA command from this method to
// prevent RDMS/RSA from issuing *ERROR 400
return "";
}
@Override
public String getDropSequenceString(String sequenceName) {
// We must return a valid RDMS/RSA command from this method to
// prevent RDMS/RSA from issuing *ERROR 400
return "";
public SequenceSupport getSequenceSupport() {
return RDMSSequenceSupport.INSTANCE;
}
@Override
@ -369,44 +290,14 @@ public class RDMSOS2200Dialect extends Dialect {
}
@Override
@SuppressWarnings("deprecation")
public CaseFragment createCaseFragment() {
return new DecodeCaseFragment();
}
@Override
public CaseExpressionWalker getCaseExpressionWalker() {
return DecodeCaseExpressionWalker.INSTANCE;
}
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return LEGACY_LIMIT_HANDLER;
}
return LIMIT_HANDLER;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public String getLimitString(String sql, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return sql + " fetch first " + limit + " rows only ";
}
@Override
public boolean supportsVariableLimit() {
return false;
return FetchLimitHandler.INSTANCE;
}
@Override
@ -415,29 +306,48 @@ public class RDMSOS2200Dialect extends Dialect {
return true;
}
@Override
public String getFromDual() {
return "from rdms.rdms_dummy where key_col = 1";
}
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// RDMS has no known variation of a "SELECT ... FOR UPDATE" syntax...
if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode );
switch (lockMode) {
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
case OPTIMISTIC:
return new OptimisticLockingStrategy(lockable, lockMode);
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
else if ( lockMode == LockMode.PESSIMISTIC_WRITE ) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.PESSIMISTIC_READ ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC ) {
return new OptimisticLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT ) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode );
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {
return new SelectLockingStrategy( lockable, lockMode );
}
}
@Override
public String translateDatetimeFormat(String format) {
return OracleDialect.datetimeFormat( format, true ) //Does it really support FM?
.replace("SSSSSS", "MLS")
.replace("SSSSS", "MLS")
.replace("SSSS", "MLS")
.replace("SSS", "MLS")
.replace("SS", "MLS")
.replace("S", "MLS")
.result();
}
@Override
public String trimPattern(TrimSpec specification, char character) {
return AbstractTransactSQLDialect.replaceLtrimRtrim(specification, character);
}
}

View File

@ -1,27 +1,24 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect.function;
package org.hibernate.dialect;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Internal;
/**
* @author Gavin King
*/
@Internal
public class Replacer {
private String[] chunks;
private String quote;
private String delimiter;
private List<Replacement> replacements = new ArrayList<>();
public static class Replacement {
class Replacement {
String placeholder;
String replacement;
@ -48,7 +45,7 @@ public class Replacer {
}
}
public Replacer(String format, String quote, String delimiter) {
Replacer(String format, String quote, String delimiter) {
this.delimiter = delimiter;
this.chunks = format.split( quote );
this.quote = quote;

View File

@ -25,7 +25,7 @@ public enum ResultColumnReferenceStrategy {
* approaches. One is to reference the result column by the alias it is given in the
* result source (if it is given an alias). This strategy says to use this approach.
* <p/>
* The other ANSI SQL compliant approach is {@link #ORDINAL}.
* The other QNSI SQL compliant approach is {@link #ORDINAL}.
*/
ALIAS,
/**
@ -33,7 +33,7 @@ public enum ResultColumnReferenceStrategy {
* approaches. One is to reference the result column by the ordinal position at which
* it appears in the result source. This strategy says to use this approach.
* <p/>
* The other ANSI SQL compliant approach is {@link #ALIAS}.
* The other QNSI SQL compliant approach is {@link #ALIAS}.
*/
ORDINAL;

View File

@ -6,25 +6,25 @@
*/
package org.hibernate.dialect;
import java.sql.DatabaseMetaData;
import java.sql.Types;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.TransactSQLTrimEmulation;
import org.hibernate.dialect.sequence.SAPDBSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TrimSpec;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DecodeCaseFragment;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.DecodeCaseExpressionWalker;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorSAPDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.DatabaseMetaData;
import java.sql.Types;
/**
* An SQL dialect compatible with SAP DB.
*
@ -36,20 +36,20 @@ public class SAPDBDialect extends Dialect {
*/
public SAPDBDialect() {
super();
registerColumnType( Types.BIT, "boolean" );
registerColumnType( Types.BIT, 1, "boolean" ); //no BIT type
registerColumnType( Types.TINYINT, "smallint" );
registerColumnType( Types.BIGINT, "fixed(19,0)" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.TINYINT, "fixed(3,0)" );
registerColumnType( Types.INTEGER, "int" );
registerColumnType( Types.CHAR, "char(1)" );
registerColumnType( Types.VARCHAR, "varchar($l)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double precision" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.VARBINARY, "long byte" );
registerColumnType( Types.NUMERIC, "fixed($p,$s)" );
registerColumnType( Types.DECIMAL, "fixed($p,$s)" );
//no explicit precision
registerColumnType(Types.TIMESTAMP, "timestamp");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp");
registerColumnType( Types.VARBINARY, "long byte" );
registerColumnType( Types.CLOB, "long varchar" );
registerColumnType( Types.BLOB, "long byte" );
@ -71,6 +71,7 @@ public class SAPDBDialect extends Dialect {
CommonFunctionFactory.degrees( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
@ -82,7 +83,7 @@ public class SAPDBDialect extends Dialect {
CommonFunctionFactory.dateTimeTimestamp( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.week_weekofyear( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.coalesce_value( queryEngine );
//since lpad/rpad are not actually useful padding
//functions, map them to lfill/rfill
@ -93,19 +94,24 @@ public class SAPDBDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "?1(?2)", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "case ?1 when ?2 then null else ?1 end" )
.setExactArgumentCount( 2 )
.register( "nullif" );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "nullif", "case ?1 when ?2 then null else ?1 end" )
.setExactArgumentCount(2)
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "index" )
.setInvariantType( StandardBasicTypes.INTEGER )
.setArgumentCountBetween( 2, 4 )
.register();
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("locate", StandardBasicTypes.INTEGER, "index(?2, ?1)", "index(?2, ?1, ?3)");
queryEngine.getSqmFunctionRegistry().register( "trim", new TransactSQLTrimEmulation() );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER, "index(?2, ?1)", "index(?2, ?1, ?3)"
).setArgumentListSignature("(pattern, string[, start])");
}
@Override
public String trimPattern(TrimSpec specification, char character) {
return AbstractTransactSQLDialect.replaceLtrimRtrim(specification, character);
}
@Override
@ -159,23 +165,8 @@ public class SAPDBDialect extends Dialect {
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return sequenceName + ".nextval";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
public SequenceSupport getSequenceSupport() {
return SAPDBSequenceSupport.INSTANCE;
}
@Override
@ -189,19 +180,16 @@ public class SAPDBDialect extends Dialect {
}
@Override
public boolean supportsSequences() {
return true;
public String getFromDual() {
return "from dual";
}
@Override
@SuppressWarnings("deprecation")
public CaseFragment createCaseFragment() {
return new DecodeCaseFragment();
}
@Override
public CaseExpressionWalker getCaseExpressionWalker() {
return DecodeCaseExpressionWalker.INSTANCE;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(

View File

@ -6,122 +6,19 @@
*/
package org.hibernate.dialect;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryTimeoutException;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.SQLServer2005LimitHandler;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.type.StandardBasicTypes;
/**
* A dialect for Microsoft SQL 2005. (HHH-3936 fix)
* A dialect for Microsoft SQL Server 2005.
*
* @author Yoryos Valotasios
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*
* @deprecated use {@code SQLServerDialect(9)}
*/
@SuppressWarnings("deprecation")
@Deprecated
public class SQLServer2005Dialect extends SQLServerDialect {
private static final int MAX_LENGTH = 8000;
/**
* Constructs a SQLServer2005Dialect
*/
public SQLServer2005Dialect() {
// HHH-3965 fix
// As per http://www.sql-server-helper.com/faq/sql-server-2005-varchar-max-p01.aspx
// use varchar(max) and varbinary(max) instead of TEXT and IMAGE types
registerColumnType( Types.BLOB, "varbinary(MAX)" );
registerColumnType( Types.VARBINARY, "varbinary(MAX)" );
registerColumnType( Types.VARBINARY, MAX_LENGTH, "varbinary($l)" );
registerColumnType( Types.LONGVARBINARY, "varbinary(MAX)" );
registerColumnType( Types.CLOB, "varchar(MAX)" );
registerColumnType( Types.LONGVARCHAR, "varchar(MAX)" );
registerColumnType( Types.VARCHAR, "varchar(MAX)" );
registerColumnType( Types.VARCHAR, MAX_LENGTH, "varchar($l)" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.BIT, "bit" );
// HHH-8435 fix
registerColumnType( Types.NCLOB, "nvarchar(MAX)" );
super(9);
}
@Override
protected LimitHandler getDefaultLimitHandler() {
return new SQLServer2005LimitHandler();
}
@Override
public String appendLockHint(LockOptions lockOptions, String tableName) {
LockMode lockMode = lockOptions.getAliasSpecificLockMode( tableName );
if(lockMode == null) {
lockMode = lockOptions.getLockMode();
}
final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock";
final String readLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock";
final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ", nowait" : "";
final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ", readpast" : "";
switch ( lockMode ) {
case UPGRADE:
case PESSIMISTIC_WRITE:
case WRITE: {
return tableName + " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
}
case PESSIMISTIC_READ: {
return tableName + " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
}
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast" + noWaitStr + ")";
case UPGRADE_NOWAIT:
return tableName + " with (updlock, holdlock, rowlock, nowait)";
default: {
return tableName;
}
}
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if ( "HY008".equals( sqlState ) ) {
throw new QueryTimeoutException( message, sqlException, sql );
}
if (1222 == errorCode ) {
throw new LockTimeoutException( message, sqlException, sql );
}
return null;
}
};
}
@Override
public boolean supportsNonQueryWithCTE() {
return true;
}
@Override
public boolean supportsSkipLocked() {
return true;
}
@Override
public boolean supportsNoWait() {
return true;
}
}

View File

@ -6,73 +6,18 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.NullPrecedence;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
/**
* A dialect for Microsoft SQL Server 2008 with JDBC Driver 3.0 and above
*
* @author Gavin King
*
* @deprecated use {@code SQLServerDialect(10)}
*/
public class SQLServer2008Dialect extends SQLServer2005Dialect {
@Deprecated
public class SQLServer2008Dialect extends SQLServerDialect {
private static final int NVARCHAR_MAX_LENGTH = 4000;
/**
* Constructs a SQLServer2008Dialect
*/
public SQLServer2008Dialect() {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "datetime2" );
registerColumnType( Types.NVARCHAR, NVARCHAR_MAX_LENGTH, "nvarchar($l)" );
registerColumnType( Types.NVARCHAR, "nvarchar(MAX)" );
super(10);
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
CommonFunctionFactory.locate_charindex( queryEngine );
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "row_number" )
.setInvariantType( StandardBasicTypes.LONG )
.setUseParenthesesWhenNoArgs( true )
.register();
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "rank" )
.setInvariantType( StandardBasicTypes.LONG )
.setUseParenthesesWhenNoArgs( true )
.register();
}
@Override
public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) {
final StringBuilder orderByElement = new StringBuilder();
if ( nulls != null && !NullPrecedence.NONE.equals( nulls ) ) {
// Workaround for NULLS FIRST / LAST support.
orderByElement.append( "case when " ).append( expression ).append( " is null then " );
if ( NullPrecedence.FIRST.equals( nulls ) ) {
orderByElement.append( "0 else 1" );
}
else {
orderByElement.append( "1 else 0" );
}
orderByElement.append( " end, " );
}
// Nulls precedence has already been handled so passing NONE value.
orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) );
return orderByElement.toString();
}
@Override
public boolean supportsValuesList() {
return true;
}
}

View File

@ -6,118 +6,18 @@
*/
package org.hibernate.dialect;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.SQLServer2012LimitHandler;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
/**
* Microsoft SQL Server 2012 Dialect
* A dialect for Microsoft SQL Server 2012
*
* @author Brett Meyer
*
* @deprecated use {@code SQLServerDialect(11)}
*/
public class SQLServer2012Dialect extends SQLServer2008Dialect {
@Deprecated
public class SQLServer2012Dialect extends SQLServerDialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
//actually translate() was added in 2017 but
//it's not worth adding a new dialect for that!
CommonFunctionFactory.translate( queryEngine );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datefromparts" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timefromparts" )
.setInvariantType( StandardBasicTypes.TIME )
.setExactArgumentCount( 5 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "smalldatetimefromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 5 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimefromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 7 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetime2fromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 8 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimeoffsetfromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 10 )
.register();
public SQLServer2012Dialect() {
super(11);
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return "next value for " + sequenceName;
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
@Override
public String getQuerySequencesString() {
// The upper-case name should work on both case-sensitive and case-insensitive collations.
return "select * from INFORMATION_SCHEMA.SEQUENCES";
}
@Override
public String getQueryHintString(String sql, String hints) {
final StringBuilder buffer = new StringBuilder(
sql.length()
+ hints.length() + 12
);
final int pos = sql.indexOf( ';' );
if ( pos > -1 ) {
buffer.append( sql.substring( 0, pos ) );
}
else {
buffer.append( sql );
}
buffer.append( " OPTION (" ).append( hints ).append( ")" );
if ( pos > -1 ) {
buffer.append( ";" );
}
sql = buffer.toString();
return sql;
}
@Override
public boolean supportsLimitOffset() {
return true;
}
@Override
protected LimitHandler getDefaultLimitHandler() {
return new SQLServer2012LimitHandler();
}
}

View File

@ -6,111 +6,186 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.*;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.Replacer;
import org.hibernate.dialect.function.TransactSQLTrimEmulation;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.SQLServerIdentityColumnSupport;
import org.hibernate.dialect.pagination.LegacyLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.SQLServer2005LimitHandler;
import org.hibernate.dialect.pagination.SQLServer2012LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.dialect.sequence.ANSISequenceSupport;
import org.hibernate.dialect.sequence.NoSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.SQLException;
import java.sql.Types;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.compile;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
/**
* A dialect for Microsoft SQL Server 2000
* A dialect for Microsoft SQL Server 2000 and above
*
* @author Gavin King
*/
@SuppressWarnings("deprecation")
public class SQLServerDialect extends AbstractTransactSQLDialect {
private static final int PARAM_LIST_SIZE_LIMIT = 2100;
private final LimitHandler limitHandler;
private final int version;
int getVersion() {
return version;
}
public SQLServerDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() );
}
/**
* Constructs a SQLServerDialect
*/
public SQLServerDialect() {
registerColumnType( Types.VARBINARY, "image" );
this(8);
}
public SQLServerDialect(int version) {
super();
this.version = version;
//there is no 'double' type in SQL server
//but 'float' is double precision by default
registerColumnType( Types.DOUBLE, "float" );
if ( getVersion() >= 10 ) {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "datetime2($p)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetimeoffset($p)" );
}
registerColumnType( Types.VARCHAR, 8000, "varchar($l)" );
registerColumnType( Types.NVARCHAR, 4000, "nvarchar($l)" );
registerColumnType( Types.VARBINARY, 8000, "varbinary($l)" );
registerColumnType( Types.LONGVARBINARY, "image" );
registerColumnType( Types.LONGVARCHAR, "text" );
registerColumnType( Types.BOOLEAN, "bit" );
if ( getVersion() < 9 ) {
registerColumnType( Types.VARBINARY, "image" );
registerColumnType( Types.VARCHAR, "text" );
}
else {
// Use 'varchar(max)' and 'varbinary(max)' instead
// the deprecated TEXT and IMAGE types. Note that
// the length of a VARCHAR or VARBINARY column must
// be either between 1 and 8000 or exactly MAX, and
// the length of an NVARCHAR column must be either
// between 1 and 4000 or exactly MAX.
// See http://www.sql-server-helper.com/faq/sql-server-2005-varchar-max-p01.aspx
// See HHH-3965
registerColumnType( Types.BLOB, "varbinary(max)" );
registerColumnType( Types.VARBINARY, "varbinary(max)" );
registerColumnType( Types.CLOB, "varchar(max)" );
registerColumnType( Types.NCLOB, "nvarchar(max)" ); // HHH-8435 fix
registerColumnType( Types.VARCHAR, "varchar(max)" );
registerColumnType( Types.NVARCHAR, "nvarchar(max)" );
}
registerKeyword( "top" );
registerKeyword( "key" );
}
this.limitHandler = new TopLimitHandler( false, false );
@Override
public long getDefaultLobLength() {
// this is essentially the only legal length for
// a "lob" in SQL Server, i.e. the value of MAX
// (caveat: for NVARCHAR it is half this value)
return 2_147_483_647;
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.TINYINT
? SmallIntTypeDescriptor.INSTANCE
: super.getSqlTypeDescriptorOverride( sqlCode );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
//note: this function was introduced in SQL Server 2012
CommonFunctionFactory.formatdatetime_format( queryEngine );
CommonFunctionFactory.truncate_round( queryEngine );
CommonFunctionFactory.everyAny_sumIif( queryEngine );
queryEngine.getSqmFunctionRegistry().register( "trim", new TransactSQLTrimEmulation() );
}
if ( getVersion() >= 10 ) {
CommonFunctionFactory.locate_charindex( queryEngine );
CommonFunctionFactory.stddevPopSamp_stdevp( queryEngine );
CommonFunctionFactory.varPopSamp_varp( queryEngine );
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case WEEK: return "isowk"; //the ISO week number (behavior of "week" depends on a system property)
default: return super.translateExtractField(unit);
if ( getVersion() >= 11 ) {
CommonFunctionFactory.format_format( queryEngine );
//actually translate() was added in 2017 but
//it's not worth adding a new dialect for that!
CommonFunctionFactory.translate( queryEngine );
CommonFunctionFactory.median_percentileCont( queryEngine, true );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datefromparts" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timefromparts" )
.setInvariantType( StandardBasicTypes.TIME )
.setExactArgumentCount( 5 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "smalldatetimefromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 5 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimefromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 7 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetime2fromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 8 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimeoffsetfromparts" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 10 )
.register();
}
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat(format).result();
public String currentTimestamp() {
return "sysdatetime()";
}
public static Replacer datetimeFormat(String format) {
return new Replacer( format, "'", "\"" )
//era
.replace("G", "g")
@Override
public String currentTime() {
return currentTimestamp();
}
//y nothing to do
//M nothing to do
@Override
public String currentDate() {
return currentTimestamp();
}
//w no equivalent
//W no equivalent
//Y no equivalent
//day of week
.replace("EEEE", "dddd")
.replace("EEE", "ddd")
//e no equivalent
//d nothing to do
//D no equivalent
//am pm
.replace("aa", "tt")
.replace("a", "tt")
//h nothing to do
//H nothing to do
//m nothing to do
//s nothing to do
//fractional seconds
.replace("S", "F")
//timezones
.replace("XXX", "K") //UTC represented as "Z"
.replace("xxx", "zzz")
.replace("x", "zz");
@Override
public String currentTimestampWithTimeZone() {
return "sysdatetimeoffset()";
}
@Override
@ -118,53 +193,24 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return "default values";
}
static int getAfterSelectInsertPoint(String sql) {
final int selectIndex = sql.toLowerCase(Locale.ROOT).indexOf( "select" );
final int selectDistinctIndex = sql.toLowerCase(Locale.ROOT).indexOf( "select distinct" );
return selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6);
}
@Override
public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return new StringBuilder( querySelect.length() + 8 )
.append( querySelect )
.insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )
.toString();
}
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return new LegacyLimitHandler( this );
if ( getVersion() >= 11 ) {
return SQLServer2012LimitHandler.INSTANCE;
}
else if ( getVersion() >= 9 ) {
//this is a stateful class, don't cache
//it in the Dialect!
return new SQLServer2005LimitHandler();
}
else {
return new TopLimitHandler(false);
}
return getDefaultLimitHandler();
}
protected LimitHandler getDefaultLimitHandler() {
return limitHandler;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean supportsVariableLimit() {
return false;
public boolean supportsValuesList() {
return getVersion() >= 10;
}
@Override
@ -184,19 +230,49 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
@Override
public String appendLockHint(LockOptions lockOptions, String tableName) {
final LockMode mode = lockOptions.getLockMode();
switch ( mode ) {
case UPGRADE:
case UPGRADE_NOWAIT:
case PESSIMISTIC_WRITE:
case WRITE:
return tableName + " with (updlock, rowlock)";
case PESSIMISTIC_READ:
return tableName + " with (holdlock, rowlock)";
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast)";
default:
return tableName;
if ( getVersion() >= 9 ) {
LockMode lockMode = lockOptions.getAliasSpecificLockMode( tableName );
if (lockMode == null) {
lockMode = lockOptions.getLockMode();
}
final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock";
final String readLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock";
final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ", nowait" : "";
final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ", readpast" : "";
switch ( lockMode ) {
//noinspection deprecation
case UPGRADE:
case PESSIMISTIC_WRITE:
case WRITE:
return tableName + " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
case PESSIMISTIC_READ:
return tableName + " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast" + noWaitStr + ")";
case UPGRADE_NOWAIT:
return tableName + " with (updlock, holdlock, rowlock, nowait)";
default:
return tableName;
}
}
else {
switch ( lockOptions.getLockMode() ) {
//noinspection deprecation
case UPGRADE:
case UPGRADE_NOWAIT:
case PESSIMISTIC_WRITE:
case WRITE:
return tableName + " with (updlock, rowlock)";
case PESSIMISTIC_READ:
return tableName + " with (holdlock, rowlock)";
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast)";
default:
return tableName;
}
}
}
@ -250,13 +326,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return false;
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.TINYINT ?
SmallIntTypeDescriptor.INSTANCE :
super.getSqlTypeDescriptorOverride( sqlCode );
}
@Override
public int getInExpressionCountLimit() {
return PARAM_LIST_SIZE_LIMIT;
@ -266,4 +335,273 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
public IdentityColumnSupport getIdentityColumnSupport() {
return new SQLServerIdentityColumnSupport();
}
@Override
public boolean supportsNonQueryWithCTE() {
return getVersion() >= 9;
}
@Override
public boolean supportsSkipLocked() {
return getVersion() >= 9;
}
@Override
public boolean supportsNoWait() {
return getVersion() >= 9;
}
@Override
public SequenceSupport getSequenceSupport() {
return getVersion() < 11
? NoSequenceSupport.INSTANCE
: ANSISequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return getVersion() < 11
? super.getQuerySequencesString() //null
// The upper-case name should work on both case-sensitive
// and case-insensitive collations.
: "select * from INFORMATION_SCHEMA.SEQUENCES";
}
@Override
public String getQueryHintString(String sql, String hints) {
if ( getVersion() < 11 ) {
return super.getQueryHintString( sql, hints );
}
final StringBuilder buffer = new StringBuilder(
sql.length() + hints.length() + 12
);
final int pos = sql.indexOf( ";" );
if ( pos > -1 ) {
buffer.append( sql.substring( 0, pos ) );
}
else {
buffer.append( sql );
}
buffer.append( " OPTION (" ).append( hints ).append( ")" );
if ( pos > -1 ) {
buffer.append( ";" );
}
sql = buffer.toString();
return sql;
}
@Override
public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) {
if ( getVersion() < 10 ) {
return super.renderOrderByElement( expression, collation, order, nulls );
}
final StringBuilder orderByElement = new StringBuilder();
if ( nulls != null && !NullPrecedence.NONE.equals( nulls ) ) {
// Workaround for NULLS FIRST / LAST support.
orderByElement.append( "case when " ).append( expression ).append( " is null then " );
if ( NullPrecedence.FIRST.equals( nulls ) ) {
orderByElement.append( "0 else 1" );
}
else {
orderByElement.append( "1 else 0" );
}
orderByElement.append( " end, " );
}
// Nulls precedence has already been handled so passing NONE value.
orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) );
return orderByElement.toString();
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
if ( getVersion() < 9 ) {
return super.buildSQLExceptionConversionDelegate(); //null
}
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if ( "HY008".equals( sqlState ) ) {
throw new QueryTimeoutException( message, sqlException, sql );
}
if ( 1222 == errorCode ) {
throw new LockTimeoutException( message, sqlException, sql );
}
return null;
}
};
}
/**
* SQL server supports up to 7 decimal digits of
* fractional second precision in a datetime2,
* but since its duration arithmetic functions
* try to fit durations into an int,
* which is impossible with such high precision,
* so default to generating {@code datetime2(3)}
* columns.
*/
@Override
public int getDefaultTimestampPrecision() {
return 6; //microseconds!
}
/**
* SQL server supports up to 7 decimal digits of
* fractional second precision in a datetime2,
* but unfortunately its duration arithmetic
* functions have a nasty habit of overflowing.
* So to give ourselves a little extra headroom,
* we will use {@code microsecond} as the native
* unit of precision (but even then we have to
* use tricks when calling {@code dateadd()}).
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000; //microseconds!
}
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
//currently Dialect.extract() doesn't need
//to handle NANOSECOND (might change that?)
// case NANOSECOND:
// //this should evaluate to a bigint type
// return "(datepart(second,?2,?3)*1000000000+datepart(nanosecond,?2,?3))";
case SECOND:
//this should evaluate to a floating point type
return "(datepart(second,?2,?3)+datepart(nanosecond,?2,?3)/1e9)";
default:
return "datepart(?1,?2,?3)";
}
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
// dateadd() supports only especially small magnitudes
// since it casts its argument to int (and unfortunately
// there's no dateadd_big()) so here we need to use two
// calls to dateadd() to add a whole duration
switch (unit) {
case NANOSECOND:
//Java Durations are usually the only thing
//we find expressed in nanosecond precision,
//and they can easily be very large
return "dateadd(nanosecond, ?2%1000000000, dateadd(second, ?2/1000000000, ?3))";
case NATIVE:
//microsecond is the "native" precision
return "dateadd(microsecond, ?2%1000000, dateadd(second, ?2/1000000, ?3))";
default:
return "dateadd(?1, ?2, ?3)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NATIVE:
//use microsecond as the "native" precision
return "datediff_big(microsecond, ?2, ?3)";
default:
//datediff() returns an int, and can easily
//overflow when dealing with "physical"
//durations, so use datediff_big()
return unit.normalized() == NANOSECOND
? "datediff_big(?1, ?2, ?3)"
: "datediff(?1, ?2, ?3)";
}
}
@Override
public String translateDurationField(TemporalUnit unit) {
switch (unit) {
//use microsecond as the "native" precision
case NATIVE: return "microsecond";
default: return super.translateDurationField(unit);
}
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
//the ISO week number (behavior of "week" depends on a system property)
case WEEK: return "isowk";
default: return super.translateExtractField(unit);
}
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat(format).result();
}
public static Replacer datetimeFormat(String format) {
return new Replacer( format, "'", "\"" )
//era
.replace("G", "g")
//y nothing to do
//M nothing to do
//w no equivalent
//W no equivalent
//Y no equivalent
//day of week
.replace("EEEE", "dddd")
.replace("EEE", "ddd")
//e no equivalent
//d nothing to do
//D no equivalent
//am pm
.replace("aa", "tt")
.replace("a", "tt")
//h nothing to do
//H nothing to do
//m nothing to do
//s nothing to do
//fractional seconds
.replace("S", "F")
//timezones
.replace("XXX", "K") //UTC represented as "Z"
.replace("xxx", "zzz")
.replace("x", "zz");
}
private static final Pattern OFFSET_PATTERN = compile(".*[-+]\\d{2}(:\\d{2})?$");
@Override
protected String wrapTimestampLiteral(String timestamp) {
//needed because the {ts ... } JDBC escape chokes on microseconds
return OFFSET_PATTERN.matcher( timestamp ).matches()
? "cast('" + timestamp + "' as datetimeoffset)"
: "cast('" + timestamp + "' as datetime2)";
}
@Override
protected String wrapTimeLiteral(String time) {
//needed because the {t ... } JDBC is just buggy
return "cast('" + time + "' as time)";
}
@Override
protected String wrapDateLiteral(String date) {
//possibly not needed
return "cast('" + date + "' as date)";
}
}

View File

@ -0,0 +1,839 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.StaleObjectStateException;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.Exportable;
import org.hibernate.boot.model.relational.Sequence;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.LockingStrategyException;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.StandardBasicTypes;
import java.sql.Types;
import java.util.Map;
/**
* Hibernate Dialect implementation for Cloud Spanner.
*
* @author Mike Eltsufin
* @author Chengyuan Zhao
* @author Daniel Zou
* @author Dmitry Solomakha
*/
public class SpannerDialect extends Dialect {
private final Exporter<Table> spannerTableExporter = new SpannerDialectTableExporter( this );
private static final LockingStrategy LOCKING_STRATEGY = new DoNothingLockingStrategy();
private static final EmptyExporter NOOP_EXPORTER = new EmptyExporter();
private static final UniqueDelegate NOOP_UNIQUE_DELEGATE = new DoNothingUniqueDelegate();
public SpannerDialect() {
registerColumnType( Types.BOOLEAN, "bool" );
registerColumnType( Types.BIT, 1, "bool" );
registerColumnType( Types.BIT, "int64" );
registerColumnType( Types.TINYINT, "int64" );
registerColumnType( Types.SMALLINT, "int64" );
registerColumnType( Types.INTEGER, "int64" );
registerColumnType( Types.BIGINT, "int64" );
registerColumnType( Types.REAL, "float64" );
registerColumnType( Types.FLOAT, "float64" );
registerColumnType( Types.DOUBLE, "float64" );
registerColumnType( Types.DECIMAL, "float64" );
registerColumnType( Types.NUMERIC, "float64" );
//timestamp does not accept precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
//there is no time type of any kind
registerColumnType( Types.TIME, "timestamp" );
final int stringMaxLength = 2_621_440;
final int bytesMaxLength = 10_485_760;
registerColumnType( Types.CHAR, stringMaxLength, "string($l)" );
registerColumnType( Types.VARCHAR, stringMaxLength, "string($l)" );
registerColumnType( Types.NCHAR, stringMaxLength, "string($l)" );
registerColumnType( Types.NVARCHAR, stringMaxLength, "string($l)" );
registerColumnType( Types.BINARY, bytesMaxLength, "bytes($l)" );
registerColumnType( Types.VARBINARY, bytesMaxLength, "bytes($l)" );
registerColumnType( Types.CLOB, "string(max)" );
registerColumnType( Types.NCLOB, "string(max)" );
registerColumnType( Types.BLOB, "bytes(max)" );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
// Aggregate Functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "any_value" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_agg" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "countif" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "logical_and" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "logical_or" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "string_agg" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 1, 2 )
.register();
// Mathematical Functions
CommonFunctionFactory.log( queryEngine );
CommonFunctionFactory.log10( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.cosh( queryEngine );
CommonFunctionFactory.sinh( queryEngine );
CommonFunctionFactory.tanh( queryEngine );
CommonFunctionFactory.moreHyperbolic( queryEngine );
CommonFunctionFactory.bitandorxornot_bitAndOrXorNot( queryEngine );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "is_inf" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "is_nan" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ieee_divide" )
.setInvariantType( StandardBasicTypes.DOUBLE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "div" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 2 )
.register();
CommonFunctionFactory.sha1( queryEngine );
// Hash Functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "farm_fingerprint" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sha256" )
.setInvariantType( StandardBasicTypes.BINARY )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sha512" )
.setInvariantType( StandardBasicTypes.BINARY )
.setExactArgumentCount( 1 )
.register();
// String Functions
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.reverse( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "byte_length" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "code_points_to_bytes" )
.setInvariantType( StandardBasicTypes.BINARY )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "code_points_to_string" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ends_with" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 2 )
.register();
// queryEngine.getSqmFunctionRegistry().namedTemplateBuilder( "format" )
// .setInvariantType( StandardBasicTypes.STRING )
// .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "from_base64" )
.setInvariantType( StandardBasicTypes.BINARY )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "from_hex" )
.setInvariantType( StandardBasicTypes.BINARY )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "regexp_contains" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "regexp_extract" )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "regexp_extract_all" )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "regexp_replace" )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "safe_convert_bytes_to_string" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "split" )
.setArgumentCountBetween( 1, 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "starts_with" )
.setInvariantType( StandardBasicTypes.BOOLEAN )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "strpos" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "to_base64" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "to_code_points" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "to_hex" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 1 )
.register();
// JSON Functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "json_query" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "json_value" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.register();
// Array Functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array" )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_concat" )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_length" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_to_string" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 2, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_reverse" )
.setExactArgumentCount( 1 )
.register();
// Date functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date" )
.setInvariantType( StandardBasicTypes.DATE )
.setArgumentCountBetween( 1, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date_add" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date_sub" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date_diff" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date_trunc" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date_from_unix_date" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format_date" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "parse_date" )
.setInvariantType( StandardBasicTypes.DATE )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "unix_date" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
// Timestamp functions
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "string" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 1, 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 1, 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_add" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_sub" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_diff" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_trunc" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 2, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format_timestamp" )
.setInvariantType( StandardBasicTypes.STRING )
.setArgumentCountBetween( 2, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "parse_timestamp" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setArgumentCountBetween( 2, 3 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_seconds" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_millis" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp_micros" )
.setInvariantType( StandardBasicTypes.TIMESTAMP )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "unix_seconds" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "unix_millis" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "unix_micros" )
.setInvariantType( StandardBasicTypes.LONG )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder("format", "format_timestamp(?2,?1)")
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.setArgumentListSignature("(datetime as pattern)")
.register();
}
@Override
public Exporter<Table> getTableExporter() {
return this.spannerTableExporter;
}
/* SELECT-related functions */
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp() as now";
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch (unit) {
case WEEK:
return "isoweek";
case DAY_OF_MONTH:
return "day";
case DAY_OF_WEEK:
return "dayofweek";
case DAY_OF_YEAR:
return "dayofyear";
default:
return super.translateExtractField(unit);
}
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
if ( timestamp ) {
switch (unit) {
case YEAR:
case QUARTER:
case MONTH:
throw new SemanticException("illegal unit for timestamp_add(): " + unit);
default:
return "timestamp_add(?3, interval ?2 ?1)";
}
}
else {
switch (unit) {
case NANOSECOND:
case SECOND:
case MINUTE:
case HOUR:
case NATIVE:
throw new SemanticException("illegal unit for date_add(): " + unit);
default:
return "date_add(?3, interval ?2 ?1)";
}
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
if ( toTimestamp || fromTimestamp ) {
switch (unit) {
case YEAR:
case QUARTER:
case MONTH:
throw new SemanticException("illegal unit for timestamp_diff(): " + unit);
default:
return "timestamp_diff(?3, ?2, ?1)";
}
}
else {
switch (unit) {
case NANOSECOND:
case SECOND:
case MINUTE:
case HOUR:
case NATIVE:
throw new SemanticException("illegal unit for date_diff(): " + unit);
default:
return "date_diff(?3, ?2, ?1)";
}
}
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
}
public static Replacer datetimeFormat(String format) {
return MySQLDialect.datetimeFormat(format)
//day of week
.replace("EEEE", "%A")
.replace("EEE", "%a")
//minute
.replace("mm", "%M")
.replace("m", "%M")
//month of year
.replace("MMMM", "%B")
.replace("MMM", "%b")
.replace("MM", "%m")
.replace("M", "%m")
//week of year
.replace("ww", "%V")
.replace("w", "%V")
//year for week
.replace("YYYY", "%G")
.replace("YYY", "%G")
.replace("YY", "%g")
.replace("Y", "%g")
//timezones
.replace("zzz", "%Z")
.replace("zz", "%Z")
.replace("z", "%Z")
.replace("ZZZ", "%z")
.replace("ZZ", "%z")
.replace("Z", "%z")
.replace("xxx", "%Ez")
.replace("xx", "%z"); //note special case
}
/* DDL-related functions */
@Override
public boolean canCreateSchema() {
return false;
}
@Override
public String[] getCreateSchemaCommand(String schemaName) {
throw new UnsupportedOperationException(
"No create schema syntax supported by " + getClass().getName() );
}
@Override
public String[] getDropSchemaCommand(String schemaName) {
throw new UnsupportedOperationException(
"No drop schema syntax supported by " + getClass().getName() );
}
@Override
public String getCurrentSchemaCommand() {
throw new UnsupportedOperationException(
"No current schema syntax supported by " + getClass().getName() );
}
@Override
public SchemaNameResolver getSchemaNameResolver() {
throw new UnsupportedOperationException(
"No schema name resolver supported by " + getClass().getName() );
}
@Override
public boolean dropConstraints() {
return false;
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public String getDropForeignKeyString() {
throw new UnsupportedOperationException(
"Cannot drop foreign-key constraint because Cloud Spanner does not support foreign keys." );
}
@Override
public String getAddForeignKeyConstraintString(
String constraintName,
String[] foreignKey,
String referencedTable,
String[] primaryKey,
boolean referencesPrimaryKey) {
throw new UnsupportedOperationException(
"Cannot add foreign-key constraint because Cloud Spanner does not support foreign keys." );
}
@Override
public String getAddForeignKeyConstraintString(
String constraintName,
String foreignKeyDefinition) {
throw new UnsupportedOperationException(
"Cannot add foreign-key constraint because Cloud Spanner does not support foreign keys." );
}
@Override
public String getAddPrimaryKeyConstraintString(String constraintName) {
throw new UnsupportedOperationException( "Cannot add primary key constraint in Cloud Spanner." );
}
/* Lock acquisition functions */
@Override
public boolean supportsLockTimeouts() {
return false;
}
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
return LOCKING_STRATEGY;
}
@Override
public String getForUpdateString(LockOptions lockOptions) {
return "";
}
@Override
public String getForUpdateString() {
return "";
}
@Override
public String getForUpdateString(String aliases) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getForUpdateString(String aliases, LockOptions lockOptions) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getWriteLockString(int timeout) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getWriteLockString(String aliases, int timeout) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getReadLockString(int timeout) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getReadLockString(String aliases, int timeout) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
@Override
public String getForUpdateNowaitString() {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getForUpdateNowaitString(String aliases) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getForUpdateSkipLockedString() {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
throw new UnsupportedOperationException(
"Cloud Spanner does not support selecting for lock acquisition." );
}
/* Unsupported Hibernate Exporters */
@Override
public Exporter<Sequence> getSequenceExporter() {
return NOOP_EXPORTER;
}
@Override
public Exporter<ForeignKey> getForeignKeyExporter() {
return NOOP_EXPORTER;
}
@Override
public Exporter<Constraint> getUniqueKeyExporter() {
return NOOP_EXPORTER;
}
@Override
public String applyLocksToSql(
String sql,
LockOptions aliasedLockOptions,
Map<String, String[]> keyColumnNames) {
return sql;
}
@Override
public UniqueDelegate getUniqueDelegate() {
return NOOP_UNIQUE_DELEGATE;
}
/**
* The Cloud Spanner Hibernate Dialect does not currently support UNIQUE restrictions.
*
* @return {@code false}.
*/
@Override
@SuppressWarnings("deprecation")
public boolean supportsUnique() {
return false;
}
/**
* The Cloud Spanner Hibernate Dialect does not currently support UNIQUE restrictions.
*
* @return {@code false}.
*/
@Override
@SuppressWarnings("deprecation")
public boolean supportsNotNullUnique() {
return false;
}
/**
* The Cloud Spanner Hibernate Dialect does not currently support UNIQUE restrictions.
*
* @return {@code false}.
*/
@Override
@SuppressWarnings("deprecation")
public boolean supportsUniqueConstraintInCreateAlterTable() {
return false;
}
@Override
@SuppressWarnings("deprecation")
public String getAddUniqueConstraintString(String constraintName) {
return "";
}
@Override
public boolean supportsCircularCascadeDeleteConstraints() {
return false;
}
@Override
public boolean supportsCascadeDelete() {
return false;
}
@Override
public char openQuote() {
return '`';
}
@Override
public char closeQuote() {
return '`';
}
@Override
public LimitHandler getLimitHandler() {
return new LimitOffsetLimitHandler();
}
/* Type conversion and casting */
@Override
public String getCastTypeName(SqlExpressable type, Long length, Integer precision, Integer scale) {
//Spanner doesn't let you specify a length in cast() types
return super.getRawTypeName( type.getJdbcMapping().getSqlTypeDescriptor() );
}
/**
* A no-op {@link Exporter} which is responsible for returning empty Create and Drop SQL strings.
*
* @author Daniel Zou
*/
static class EmptyExporter<T extends Exportable> implements Exporter<T> {
@Override
public String[] getSqlCreateStrings(T exportable, Metadata metadata) {
return new String[0];
}
@Override
public String[] getSqlDropStrings(T exportable, Metadata metadata) {
return new String[0];
}
}
/**
* A locking strategy for the Cloud Spanner dialect that does nothing. Cloud Spanner does not
* support locking.
*
* @author Chengyuan Zhao
*/
static class DoNothingLockingStrategy implements LockingStrategy {
@Override
public void lock(
Object id, Object version, Object object, int timeout, SharedSessionContractImplementor session)
throws StaleObjectStateException, LockingStrategyException {
// Do nothing. Cloud Spanner doesn't have have locking strategies.
}
}
/**
* A no-op delegate for generating Unique-Constraints. Cloud Spanner offers unique-restrictions
* via interleaved indexes with the "UNIQUE" option. This is not currently supported.
*
* @author Chengyuan Zhao
*/
static class DoNothingUniqueDelegate implements UniqueDelegate {
@Override
public String getColumnDefinitionUniquenessFragment(Column column) {
return "";
}
@Override
public String getTableCreationUniqueConstraintsFragment(Table table) {
return "";
}
@Override
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
return "";
}
@Override
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
return "";
}
}
}

View File

@ -0,0 +1,120 @@
package org.hibernate.dialect;
import org.hibernate.boot.Metadata;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.tool.schema.spi.Exporter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* The exporter for Cloud Spanner CREATE and DROP table statements.
*
* @author Chengyuan Zhao
* @author Daniel Zou
*/
class SpannerDialectTableExporter implements Exporter<Table> {
private final SpannerDialect spannerDialect;
private final String createTableTemplate;
/**
* Constructor.
*
* @param spannerDialect a Cloud Spanner dialect.
*/
public SpannerDialectTableExporter(SpannerDialect spannerDialect) {
this.spannerDialect = spannerDialect;
this.createTableTemplate =
this.spannerDialect.getCreateTableString() + " {0} ({1}) PRIMARY KEY ({2})";
}
@Override
public String[] getSqlCreateStrings(Table table, Metadata metadata) {
Collection<Column> keyColumns;
if ( table.hasPrimaryKey() ) {
// a typical table that corresponds to an entity type
keyColumns = table.getPrimaryKey().getColumns();
}
else if ( table.getForeignKeys().size() > 0 ) {
// a table with no PK's but has FK's; often corresponds to element collection properties
keyColumns = new ArrayList<>();
for (Iterator<Column> column = table.getColumnIterator(); column.hasNext();) {
keyColumns.add( column.next() );
}
}
else {
// the case corresponding to a sequence-table that will only have 1 row.
keyColumns = Collections.emptyList();
}
return getTableString( table, keyColumns );
}
private String[] getTableString(Table table, Iterable<Column> keyColumns) {
String primaryKeyColNames = StreamSupport.stream( keyColumns.spliterator(), false )
.map( Column::getName )
.collect( Collectors.joining( "," ) );
StringJoiner colsAndTypes = new StringJoiner( "," );
for (Iterator<Column> column = table.getColumnIterator(); column.hasNext();) {
Column col = column.next();
String columnDeclaration =
col.getName()
+ " " + col.getSqlType()
+ ( col.isNullable() ? this.spannerDialect.getNullColumnString() : " not null" );
colsAndTypes.add( columnDeclaration );
}
ArrayList<String> statements = new ArrayList<>();
statements.add(
MessageFormat.format(
this.createTableTemplate,
table.getQualifiedTableName().render(),
colsAndTypes.toString(),
primaryKeyColNames
) );
// Hibernate requires the special hibernate_sequence table to be populated with an initial val.
if ( table.getName().equals( SequenceStyleGenerator.DEF_SEQUENCE_NAME ) ) {
statements.add( "INSERT INTO " + SequenceStyleGenerator.DEF_SEQUENCE_NAME + " ("
+ SequenceStyleGenerator.DEF_VALUE_COLUMN + ") VALUES(1)" );
}
return statements.toArray( new String[0] );
}
@Override
public String[] getSqlDropStrings(Table table, Metadata metadata) {
/* Cloud Spanner requires examining the metadata to find all indexes and interleaved tables.
* These must be dropped before the given table can be dropped.
* The current implementation does not support interleaved tables.
*/
ArrayList<String> dropStrings = new ArrayList<>();
;
for (Iterator<Index> index = table.getIndexIterator(); index.hasNext();) {
dropStrings.add( "drop index " + index.next().getName() );
}
dropStrings.add( this.spannerDialect.getDropTableString( table.getQualifiedTableName().render() ) );
return dropStrings.toArray( new String[0] );
}
}

View File

@ -6,29 +6,16 @@
*/
package org.hibernate.dialect;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.Sybase11JoinFragment;
/**
* A SQL dialect suitable for use with Sybase 11.9.2 (specifically: avoids ANSI JOIN syntax)
* A SQL dialect suitable for use with Sybase 11.9.2
* (specifically: avoids ANSI JOIN syntax)
*
* @author Colm O' Flaherty
* @deprecated use {@link SybaseASEDialect} instead
*/
public class Sybase11Dialect extends SybaseDialect {
/**
* Constructs a Sybase11Dialect
*/
@Deprecated
public class Sybase11Dialect extends SybaseASEDialect {
public Sybase11Dialect() {
super();
}
@Override
public JoinFragment createOuterJoinFragment() {
return new Sybase11JoinFragment();
}
@Override
public String getCrossJoinSeparator() {
return ", ";
}
}

View File

@ -6,103 +6,18 @@
*/
package org.hibernate.dialect;
import java.sql.SQLException;
import java.util.Map;
import org.hibernate.JDBCException;
import org.hibernate.LockOptions;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.SybaseASE157LimitHandler;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.sql.ForUpdateFragment;
/**
* An SQL dialect targeting Sybase Adaptive Server Enterprise (ASE) 15.7 and higher.
* <p/>
*
* @author Junyan Ren
*
* @deprecated use {@code SybaseASEDialect(1570)}
*/
public class SybaseASE157Dialect extends SybaseASE15Dialect {
@Deprecated
public class SybaseASE157Dialect extends SybaseASEDialect {
private static final SybaseASE157LimitHandler LIMIT_HANDLER = new SybaseASE157LimitHandler();
@Override
public String getTableTypeString() {
//HHH-7298 I don't know if this would break something or cause some side affects
//but it is required to use 'select for update'
return " lock datarows";
public SybaseASE157Dialect() {
super(1570);
}
@Override
public boolean supportsExpectedLobUsagePattern() {
return true;
}
@Override
public boolean supportsLobValueChangePropogation() {
return false;
}
@Override
public boolean forUpdateOfColumns() {
return true;
}
@Override
public String getForUpdateString() {
return " for update";
}
@Override
public String getForUpdateString(String aliases) {
return getForUpdateString() + " of " + aliases;
}
@Override
public String appendLockHint(LockOptions mode, String tableName) {
return tableName;
}
@Override
public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map<String, String[]> keyColumnNames) {
return sql + new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString();
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if("JZ0TO".equals( sqlState ) || "JZ006".equals( sqlState )){
throw new LockTimeoutException( message, sqlException, sql );
}
if ( 515 == errorCode && "ZZZZZ".equals( sqlState ) ) {
// Attempt to insert NULL value into column; column does not allow nulls.
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
}
return null;
}
};
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
}

View File

@ -6,316 +6,19 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.TinyIntTypeDescriptor;
/**
* An SQL dialect targeting Sybase Adaptive Server Enterprise (ASE) 15 and higher.
* <p/>
* TODO : verify if this also works with 12/12.5
*
* @author Gavin King
*
* @deprecated use {@code SybaseASEDialect(1500)}
*/
public class SybaseASE15Dialect extends SybaseDialect {
/**
* Constructs a SybaseASE15Dialect
*/
@Deprecated
public class SybaseASE15Dialect extends SybaseASEDialect {
public SybaseASE15Dialect() {
super();
registerColumnType( Types.LONGVARBINARY, "image" );
registerColumnType( Types.LONGVARCHAR, "text" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.DECIMAL, "numeric($p,$s)" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.REAL, "real" );
registerColumnType( Types.BOOLEAN, "tinyint" );
registerSybaseKeywords();
super(1500);
}
private void registerSybaseKeywords() {
registerKeyword( "add" );
registerKeyword( "all" );
registerKeyword( "alter" );
registerKeyword( "and" );
registerKeyword( "any" );
registerKeyword( "arith_overflow" );
registerKeyword( "as" );
registerKeyword( "asc" );
registerKeyword( "at" );
registerKeyword( "authorization" );
registerKeyword( "avg" );
registerKeyword( "begin" );
registerKeyword( "between" );
registerKeyword( "break" );
registerKeyword( "browse" );
registerKeyword( "bulk" );
registerKeyword( "by" );
registerKeyword( "cascade" );
registerKeyword( "case" );
registerKeyword( "char_convert" );
registerKeyword( "check" );
registerKeyword( "checkpoint" );
registerKeyword( "close" );
registerKeyword( "clustered" );
registerKeyword( "coalesce" );
registerKeyword( "commit" );
registerKeyword( "compute" );
registerKeyword( "confirm" );
registerKeyword( "connect" );
registerKeyword( "constraint" );
registerKeyword( "continue" );
registerKeyword( "controlrow" );
registerKeyword( "convert" );
registerKeyword( "count" );
registerKeyword( "count_big" );
registerKeyword( "create" );
registerKeyword( "current" );
registerKeyword( "cursor" );
registerKeyword( "database" );
registerKeyword( "dbcc" );
registerKeyword( "deallocate" );
registerKeyword( "declare" );
registerKeyword( "decrypt" );
registerKeyword( "default" );
registerKeyword( "delete" );
registerKeyword( "desc" );
registerKeyword( "determnistic" );
registerKeyword( "disk" );
registerKeyword( "distinct" );
registerKeyword( "drop" );
registerKeyword( "dummy" );
registerKeyword( "dump" );
registerKeyword( "else" );
registerKeyword( "encrypt" );
registerKeyword( "end" );
registerKeyword( "endtran" );
registerKeyword( "errlvl" );
registerKeyword( "errordata" );
registerKeyword( "errorexit" );
registerKeyword( "escape" );
registerKeyword( "except" );
registerKeyword( "exclusive" );
registerKeyword( "exec" );
registerKeyword( "execute" );
registerKeyword( "exist" );
registerKeyword( "exit" );
registerKeyword( "exp_row_size" );
registerKeyword( "external" );
registerKeyword( "fetch" );
registerKeyword( "fillfactor" );
registerKeyword( "for" );
registerKeyword( "foreign" );
registerKeyword( "from" );
registerKeyword( "goto" );
registerKeyword( "grant" );
registerKeyword( "group" );
registerKeyword( "having" );
registerKeyword( "holdlock" );
registerKeyword( "identity" );
registerKeyword( "identity_gap" );
registerKeyword( "identity_start" );
registerKeyword( "if" );
registerKeyword( "in" );
registerKeyword( "index" );
registerKeyword( "inout" );
registerKeyword( "insensitive" );
registerKeyword( "insert" );
registerKeyword( "install" );
registerKeyword( "intersect" );
registerKeyword( "into" );
registerKeyword( "is" );
registerKeyword( "isolation" );
registerKeyword( "jar" );
registerKeyword( "join" );
registerKeyword( "key" );
registerKeyword( "kill" );
registerKeyword( "level" );
registerKeyword( "like" );
registerKeyword( "lineno" );
registerKeyword( "load" );
registerKeyword( "lock" );
registerKeyword( "materialized" );
registerKeyword( "max" );
registerKeyword( "max_rows_per_page" );
registerKeyword( "min" );
registerKeyword( "mirror" );
registerKeyword( "mirrorexit" );
registerKeyword( "modify" );
registerKeyword( "national" );
registerKeyword( "new" );
registerKeyword( "noholdlock" );
registerKeyword( "nonclustered" );
registerKeyword( "nonscrollable" );
registerKeyword( "non_sensitive" );
registerKeyword( "not" );
registerKeyword( "null" );
registerKeyword( "nullif" );
registerKeyword( "numeric_truncation" );
registerKeyword( "of" );
registerKeyword( "off" );
registerKeyword( "offsets" );
registerKeyword( "on" );
registerKeyword( "once" );
registerKeyword( "online" );
registerKeyword( "only" );
registerKeyword( "open" );
registerKeyword( "option" );
registerKeyword( "or" );
registerKeyword( "order" );
registerKeyword( "out" );
registerKeyword( "output" );
registerKeyword( "over" );
registerKeyword( "artition" );
registerKeyword( "perm" );
registerKeyword( "permanent" );
registerKeyword( "plan" );
registerKeyword( "prepare" );
registerKeyword( "primary" );
registerKeyword( "print" );
registerKeyword( "privileges" );
registerKeyword( "proc" );
registerKeyword( "procedure" );
registerKeyword( "processexit" );
registerKeyword( "proxy_table" );
registerKeyword( "public" );
registerKeyword( "quiesce" );
registerKeyword( "raiserror" );
registerKeyword( "read" );
registerKeyword( "readpast" );
registerKeyword( "readtext" );
registerKeyword( "reconfigure" );
registerKeyword( "references" );
registerKeyword( "remove" );
registerKeyword( "reorg" );
registerKeyword( "replace" );
registerKeyword( "replication" );
registerKeyword( "reservepagegap" );
registerKeyword( "return" );
registerKeyword( "returns" );
registerKeyword( "revoke" );
registerKeyword( "role" );
registerKeyword( "rollback" );
registerKeyword( "rowcount" );
registerKeyword( "rows" );
registerKeyword( "rule" );
registerKeyword( "save" );
registerKeyword( "schema" );
registerKeyword( "scroll" );
registerKeyword( "scrollable" );
registerKeyword( "select" );
registerKeyword( "semi_sensitive" );
registerKeyword( "set" );
registerKeyword( "setuser" );
registerKeyword( "shared" );
registerKeyword( "shutdown" );
registerKeyword( "some" );
registerKeyword( "statistics" );
registerKeyword( "stringsize" );
registerKeyword( "stripe" );
registerKeyword( "sum" );
registerKeyword( "syb_identity" );
registerKeyword( "syb_restree" );
registerKeyword( "syb_terminate" );
registerKeyword( "top" );
registerKeyword( "table" );
registerKeyword( "temp" );
registerKeyword( "temporary" );
registerKeyword( "textsize" );
registerKeyword( "to" );
registerKeyword( "tracefile" );
registerKeyword( "tran" );
registerKeyword( "transaction" );
registerKeyword( "trigger" );
registerKeyword( "truncate" );
registerKeyword( "tsequal" );
registerKeyword( "union" );
registerKeyword( "unique" );
registerKeyword( "unpartition" );
registerKeyword( "update" );
registerKeyword( "use" );
registerKeyword( "user" );
registerKeyword( "user_option" );
registerKeyword( "using" );
registerKeyword( "values" );
registerKeyword( "varying" );
registerKeyword( "view" );
registerKeyword( "waitfor" );
registerKeyword( "when" );
registerKeyword( "where" );
registerKeyword( "while" );
registerKeyword( "with" );
registerKeyword( "work" );
registerKeyword( "writetext" );
registerKeyword( "xmlextract" );
registerKeyword( "xmlparse" );
registerKeyword( "xmltest" );
registerKeyword( "xmlvalidate" );
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsCascadeDelete() {
return false;
}
@Override
public int getMaxAliasLength() {
return 30;
}
/**
* By default, Sybase string comparisons are case-insensitive.
* <p/>
* If the DB is configured to be case-sensitive, then this return
* value will be incorrect.
* <p/>
* {@inheritDoc}
*/
@Override
public boolean areStringComparisonsCaseInsensitive() {
return true;
}
@Override
public String getCurrentTimestampSQLFunctionName() {
return "getdate()";
}
/**
* Actually Sybase does not support LOB locators at al.
*
* @return false.
* <p/>
* {@inheritDoc}
*/
@Override
public boolean supportsExpectedLobUsagePattern() {
return false;
}
@Override
public String getCrossJoinSeparator() {
return ", ";
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.BOOLEAN ? TinyIntTypeDescriptor.INSTANCE : super.getSqlTypeDescriptorOverride( sqlCode );
}
@Override
public boolean supportsLockTimeouts() {
return false;
}
@Override
public boolean supportsPartitionBy() {
return false;
}
}

View File

@ -0,0 +1,477 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.JDBCException;
import org.hibernate.LockOptions;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.query.TrimSpec;
import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.Sybase11JoinFragment;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.TinyIntTypeDescriptor;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
/**
* Dialect for Sybase Adaptive Server Enterprise for
* Sybase 11.9.2 and above.
*/
public class SybaseASEDialect extends SybaseDialect {
private final int version;
int getVersion() {
return version;
}
public SybaseASEDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
}
public SybaseASEDialect() {
this(1100);
}
public SybaseASEDialect(int version) {
super();
this.version = version;
//On Sybase ASE, the 'bit' type cannot be null,
//and cannot have indexes (while we don't use
//tinyint to store signed bytes, we can use it
//to store boolean values)
registerColumnType( Types.BOOLEAN, "tinyint" );
registerColumnType( Types.BIT, 1, "tinyint" );
if ( getVersion() >= 1500 ) {
//bigint was added in version 15
registerColumnType( Types.BIGINT, "bigint" );
}
if ( getVersion() >= 1200 ) {
//date / date were introduced in version 12
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
}
// the maximum length of a VARCHAR or VARBINARY
// depends on the page size, and also on the
// version of Sybase ASE, and can be quite small,
// so use 'image' and 'text' as the "long" types
registerColumnType( Types.LONGVARBINARY, "image" );
registerColumnType( Types.LONGVARCHAR, "text" );
registerSybaseKeywords();
}
/**
* The Sybase ASE {@code BIT} type does not allow
* null values, so we don't use it.
*
* @return false
*/
@Override
public boolean supportsBitType() {
return false;
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.BOOLEAN
? TinyIntTypeDescriptor.INSTANCE
: super.getSqlTypeDescriptorOverride( sqlCode );
}
@Override
public String currentDate() {
return "current_date()";
}
@Override
public String currentTime() {
return "current_time()";
}
@Override
public String currentTimestamp() {
return "current_bigdatetime()";
}
private void registerSybaseKeywords() {
registerKeyword( "add" );
registerKeyword( "all" );
registerKeyword( "alter" );
registerKeyword( "and" );
registerKeyword( "any" );
registerKeyword( "arith_overflow" );
registerKeyword( "as" );
registerKeyword( "asc" );
registerKeyword( "at" );
registerKeyword( "authorization" );
registerKeyword( "avg" );
registerKeyword( "begin" );
registerKeyword( "between" );
registerKeyword( "break" );
registerKeyword( "browse" );
registerKeyword( "bulk" );
registerKeyword( "by" );
registerKeyword( "cascade" );
registerKeyword( "case" );
registerKeyword( "char_convert" );
registerKeyword( "check" );
registerKeyword( "checkpoint" );
registerKeyword( "close" );
registerKeyword( "clustered" );
registerKeyword( "coalesce" );
registerKeyword( "commit" );
registerKeyword( "compute" );
registerKeyword( "confirm" );
registerKeyword( "connect" );
registerKeyword( "constraint" );
registerKeyword( "continue" );
registerKeyword( "controlrow" );
registerKeyword( "convert" );
registerKeyword( "count" );
registerKeyword( "count_big" );
registerKeyword( "create" );
registerKeyword( "current" );
registerKeyword( "cursor" );
registerKeyword( "database" );
registerKeyword( "dbcc" );
registerKeyword( "deallocate" );
registerKeyword( "declare" );
registerKeyword( "decrypt" );
registerKeyword( "default" );
registerKeyword( "delete" );
registerKeyword( "desc" );
registerKeyword( "determnistic" );
registerKeyword( "disk" );
registerKeyword( "distinct" );
registerKeyword( "drop" );
registerKeyword( "dummy" );
registerKeyword( "dump" );
registerKeyword( "else" );
registerKeyword( "encrypt" );
registerKeyword( "end" );
registerKeyword( "endtran" );
registerKeyword( "errlvl" );
registerKeyword( "errordata" );
registerKeyword( "errorexit" );
registerKeyword( "escape" );
registerKeyword( "except" );
registerKeyword( "exclusive" );
registerKeyword( "exec" );
registerKeyword( "execute" );
registerKeyword( "exist" );
registerKeyword( "exit" );
registerKeyword( "exp_row_size" );
registerKeyword( "external" );
registerKeyword( "fetch" );
registerKeyword( "fillfactor" );
registerKeyword( "for" );
registerKeyword( "foreign" );
registerKeyword( "from" );
registerKeyword( "goto" );
registerKeyword( "grant" );
registerKeyword( "group" );
registerKeyword( "having" );
registerKeyword( "holdlock" );
registerKeyword( "identity" );
registerKeyword( "identity_gap" );
registerKeyword( "identity_start" );
registerKeyword( "if" );
registerKeyword( "in" );
registerKeyword( "index" );
registerKeyword( "inout" );
registerKeyword( "insensitive" );
registerKeyword( "insert" );
registerKeyword( "install" );
registerKeyword( "intersect" );
registerKeyword( "into" );
registerKeyword( "is" );
registerKeyword( "isolation" );
registerKeyword( "jar" );
registerKeyword( "join" );
registerKeyword( "key" );
registerKeyword( "kill" );
registerKeyword( "level" );
registerKeyword( "like" );
registerKeyword( "lineno" );
registerKeyword( "load" );
registerKeyword( "lock" );
registerKeyword( "materialized" );
registerKeyword( "max" );
registerKeyword( "max_rows_per_page" );
registerKeyword( "min" );
registerKeyword( "mirror" );
registerKeyword( "mirrorexit" );
registerKeyword( "modify" );
registerKeyword( "national" );
registerKeyword( "new" );
registerKeyword( "noholdlock" );
registerKeyword( "nonclustered" );
registerKeyword( "nonscrollable" );
registerKeyword( "non_sensitive" );
registerKeyword( "not" );
registerKeyword( "null" );
registerKeyword( "nullif" );
registerKeyword( "numeric_truncation" );
registerKeyword( "of" );
registerKeyword( "off" );
registerKeyword( "offsets" );
registerKeyword( "on" );
registerKeyword( "once" );
registerKeyword( "online" );
registerKeyword( "only" );
registerKeyword( "open" );
registerKeyword( "option" );
registerKeyword( "or" );
registerKeyword( "order" );
registerKeyword( "out" );
registerKeyword( "output" );
registerKeyword( "over" );
registerKeyword( "artition" );
registerKeyword( "perm" );
registerKeyword( "permanent" );
registerKeyword( "plan" );
registerKeyword( "prepare" );
registerKeyword( "primary" );
registerKeyword( "print" );
registerKeyword( "privileges" );
registerKeyword( "proc" );
registerKeyword( "procedure" );
registerKeyword( "processexit" );
registerKeyword( "proxy_table" );
registerKeyword( "public" );
registerKeyword( "quiesce" );
registerKeyword( "raiserror" );
registerKeyword( "read" );
registerKeyword( "readpast" );
registerKeyword( "readtext" );
registerKeyword( "reconfigure" );
registerKeyword( "references" );
registerKeyword( "remove" );
registerKeyword( "reorg" );
registerKeyword( "replace" );
registerKeyword( "replication" );
registerKeyword( "reservepagegap" );
registerKeyword( "return" );
registerKeyword( "returns" );
registerKeyword( "revoke" );
registerKeyword( "role" );
registerKeyword( "rollback" );
registerKeyword( "rowcount" );
registerKeyword( "rows" );
registerKeyword( "rule" );
registerKeyword( "save" );
registerKeyword( "schema" );
registerKeyword( "scroll" );
registerKeyword( "scrollable" );
registerKeyword( "select" );
registerKeyword( "semi_sensitive" );
registerKeyword( "set" );
registerKeyword( "setuser" );
registerKeyword( "shared" );
registerKeyword( "shutdown" );
registerKeyword( "some" );
registerKeyword( "statistics" );
registerKeyword( "stringsize" );
registerKeyword( "stripe" );
registerKeyword( "sum" );
registerKeyword( "syb_identity" );
registerKeyword( "syb_restree" );
registerKeyword( "syb_terminate" );
registerKeyword( "top" );
registerKeyword( "table" );
registerKeyword( "temp" );
registerKeyword( "temporary" );
registerKeyword( "textsize" );
registerKeyword( "to" );
registerKeyword( "tracefile" );
registerKeyword( "tran" );
registerKeyword( "transaction" );
registerKeyword( "trigger" );
registerKeyword( "truncate" );
registerKeyword( "tsequal" );
registerKeyword( "union" );
registerKeyword( "unique" );
registerKeyword( "unpartition" );
registerKeyword( "update" );
registerKeyword( "use" );
registerKeyword( "user" );
registerKeyword( "user_option" );
registerKeyword( "using" );
registerKeyword( "values" );
registerKeyword( "varying" );
registerKeyword( "view" );
registerKeyword( "waitfor" );
registerKeyword( "when" );
registerKeyword( "where" );
registerKeyword( "while" );
registerKeyword( "with" );
registerKeyword( "work" );
registerKeyword( "writetext" );
registerKeyword( "xmlextract" );
registerKeyword( "xmlparse" );
registerKeyword( "xmltest" );
registerKeyword( "xmlvalidate" );
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@SuppressWarnings("deprecation")
public JoinFragment createOuterJoinFragment() {
return getVersion() < 1400
? new Sybase11JoinFragment()
: super.createOuterJoinFragment();
}
@Override
public boolean supportsCascadeDelete() {
return false;
}
@Override
public int getMaxAliasLength() {
return 30;
}
/**
* By default, Sybase string comparisons are case-insensitive.
* <p/>
* If the DB is configured to be case-sensitive, then this return
* value will be incorrect.
* <p/>
* {@inheritDoc}
*/
@Override
public boolean areStringComparisonsCaseInsensitive() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public String getCurrentTimestampSQLFunctionName() {
return "getdate()";
}
@Override
public String getCrossJoinSeparator() {
return ", ";
}
@Override
public boolean supportsLockTimeouts() {
return false;
}
@Override
public String getTableTypeString() {
//HHH-7298 I don't know if this would break something or cause some side affects
//but it is required to use 'select for update'
return getVersion() < 1570 ? super.getTableTypeString() : " lock datarows";
}
@Override
public boolean supportsExpectedLobUsagePattern() {
// Earlier Sybase did not support LOB locators at all
return getVersion() >= 1570;
}
@Override
public boolean supportsLobValueChangePropogation() {
return false;
}
@Override
public boolean forUpdateOfColumns() {
return getVersion() >= 1570;
}
@Override
public String getForUpdateString() {
return getVersion() < 1570 ? super.getForUpdateString() : " for update";
}
@Override
public String getForUpdateString(String aliases) {
return getVersion() < 1570
? super.getForUpdateString( aliases )
: getForUpdateString() + " of " + aliases;
}
@Override
public String appendLockHint(LockOptions mode, String tableName) {
//TODO: is this really necessary??!
return getVersion() < 1570 ? super.appendLockHint( mode, tableName ) : tableName;
}
@Override
@SuppressWarnings("deprecation")
public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map<String, String[]> keyColumnNames) {
//TODO: is this really correct?
return getVersion() < 1570
? super.applyLocksToSql( sql, aliasedLockOptions, keyColumnNames )
: sql + new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString();
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
if ( getVersion() < 1570 ) {
return null;
}
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
switch ( sqlState ) {
case "JZ0TO":
case "JZ006":
throw new LockTimeoutException( message, sqlException, sql );
case "ZZZZZ":
if (515 == errorCode) {
// Attempt to insert NULL value into column; column does not allow nulls.
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
}
break;
}
return null;
}
};
}
@Override
public LimitHandler getLimitHandler() {
if ( getVersion() < 1250 ) {
//support for SELECT TOP was introduced in Sybase ASE 12.5.3
return super.getLimitHandler();
}
return new TopLimitHandler(false);
}
@Override
public String trimPattern(TrimSpec specification, char character) {
return super.trimPattern(specification, character)
.replace("replace", "str_replace");
}
}

View File

@ -7,16 +7,17 @@
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.SybaseAnywhereIdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.type.descriptor.sql.BitTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.Types;
/**
* SQL Dialect for Sybase Anywhere
* extending Sybase (Enterprise) Dialect
* (Tested on ASA 8.x)
*/
public class SybaseAnywhereDialect extends SybaseDialect {
@ -24,7 +25,48 @@ public class SybaseAnywhereDialect extends SybaseDialect {
public SybaseAnywhereDialect() {
super();
registerColumnType( Types.BOOLEAN, "bit" );
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp with time zone" );
final int maxStringLength = 32_767;
registerColumnType( Types.CHAR, maxStringLength, "char($l)" );
registerColumnType( Types.VARCHAR, maxStringLength, "varchar($l)" );
registerColumnType( Types.VARCHAR, "long varchar)" );
registerColumnType( Types.NCHAR, maxStringLength, "nchar($l)" );
registerColumnType( Types.NVARCHAR, maxStringLength, "nvarchar($l)" );
registerColumnType( Types.NVARCHAR, "long nvarchar)" );
//note: 'binary' is actually a synonym for 'varbinary'
registerColumnType( Types.BINARY, maxStringLength, "binary($l)" );
registerColumnType( Types.VARBINARY, maxStringLength, "varbinary($l)" );
registerColumnType( Types.VARBINARY, "long binary)" );
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.BOOLEAN
? BitTypeDescriptor.INSTANCE
: super.getSqlTypeDescriptorOverride( sqlCode );
}
@Override
public String currentDate() {
return "current date";
}
@Override
public String currentTime() {
return "current time";
}
@Override
public String currentTimestamp() {
return "current timestamp";
}
/**
@ -51,13 +93,22 @@ public class SybaseAnywhereDialect extends SybaseDialect {
return false;
}
@Override
public String getFromDual() {
return "from sys.dummy";
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new SybaseAnywhereIdentityColumnSupport();
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.BOOLEAN ? BitTypeDescriptor.INSTANCE : super.getSqlTypeDescriptorOverride( sqlCode );
public LimitHandler getLimitHandler() {
//TODO: support 'TOP ? START AT ?'
//Note: Sybase Anywhere also supports LIMIT OFFSET,
// but it looks like this syntax is not enabled
// by default
return TopLimitHandler.INSTANCE;
}
}

View File

@ -6,86 +6,31 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.TransactSQLTrimEmulation;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.Types;
/**
* All Sybase dialects share an IN list size limit.
* Superclass for all Sybase dialects.
*
* @author Brett Meyer
*/
public class SybaseDialect extends AbstractTransactSQLDialect {
//All Sybase dialects share an IN list size limit.
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
public SybaseDialect() {
super();
//this doesn't work 100% on earlier versions of Sybase
//which were missing the third parameter in charindex()
//TODO: we could emulate it with substring() like in Postgres
CommonFunctionFactory.locate_charindex( queryEngine );
CommonFunctionFactory.replace_strReplace( queryEngine );
queryEngine.getSqmFunctionRegistry().register(
"trim", new TransactSQLTrimEmulation(
TransactSQLTrimEmulation.LTRIM,
TransactSQLTrimEmulation.RTRIM,
"str_replace"
)
);
//these functions need parens
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_date" )
.setInvariantType( StandardBasicTypes.DATE )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register();
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_time" )
.setInvariantType( StandardBasicTypes.DATE )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register();
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_timestamp" )
.setInvariantType( StandardBasicTypes.DATE )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register();
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_timestamp" )
.setInvariantType( StandardBasicTypes.INSTANT )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register( "current_instant" );
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_time" )
.setInvariantType( StandardBasicTypes.LOCAL_TIME )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register( "current time" );
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_date" )
.setInvariantType( StandardBasicTypes.LOCAL_DATE )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register( "current date" );
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_timestamp" )
.setInvariantType( StandardBasicTypes.LOCAL_DATE_TIME )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register( "current datetime" );
queryEngine.getSqmFunctionRegistry().noArgsBuilder( "current_timestamp" )
.setInvariantType( StandardBasicTypes.INSTANT )
.setUseParenthesesWhenNoArgs(true)
.setExactArgumentCount( 0 )
.register( "current instant" );
//Sybase ASE didn't introduce bigint until version 15.0
registerColumnType( Types.BIGINT, "numeric(19,0)" );
}
@Override
@ -105,7 +50,19 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
return super.getSqlTypeDescriptorOverride( sqlCode );
}
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);
//this doesn't work 100% on earlier versions of Sybase
//which were missing the third parameter in charindex()
//TODO: we could emulate it with substring() like in Postgres
CommonFunctionFactory.locate_charindex( queryEngine );
CommonFunctionFactory.replace_strReplace( queryEngine );
}
@Override
public String getNullColumnString() {
return " null";
@ -115,4 +72,31 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
public String getCurrentSchemaCommand() {
return "select db_name()";
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch ( unit ) {
case WEEK: return "calweekofyear"; //the ISO week number I think
default: return super.translateExtractField(unit);
}
}
@Override
public String extractPattern(TemporalUnit unit) {
//TODO!!
return "datepart(?1, ?2)";
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
//TODO!!
return "dateadd(?1, ?2, ?3)";
}
@Override
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
//TODO!!
return "datediff(?1, ?2, ?3)";
}
}

View File

@ -6,260 +6,16 @@
*/
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.QualifiedNameImpl;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Teradata14IdentityColumnSupport;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Index;
import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.tool.schema.internal.StandardIndexExporter;
import org.hibernate.tool.schema.spi.Exporter;
/**
* A dialect for the Teradata database
* A dialect for the Teradata 14
*
* @deprecated use {@code TeradataDialect(14)}
*/
@Deprecated
public class Teradata14Dialect extends TeradataDialect {
/**
* Constructor
*/
StandardIndexExporter TeraIndexExporter = null;
public Teradata14Dialect() {
super();
//registerColumnType data types
registerColumnType( Types.BIGINT, "BIGINT" );
registerColumnType( Types.BINARY, "VARBYTE(100)" );
registerColumnType( Types.LONGVARBINARY, "VARBYTE(32000)" );
registerColumnType( Types.LONGVARCHAR, "VARCHAR(32000)" );
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
TeraIndexExporter = new TeradataIndexExporter( this );
super(14);
}
@Override
public String getAddColumnString() {
return "Add";
}
/**
* Get the name of the database type associated with the given
* <tt>java.sql.Types</tt> typecode.
*
* @param code <tt>java.sql.Types</tt> typecode
* @param length the length or precision of the column
* @param precision the precision of the column
* @param scale the scale of the column
*
* @return the database type name
*
* @throws HibernateException
*/
public String getTypeName(int code, int length, int precision, int scale) throws HibernateException {
/*
* We might want a special case for 19,2. This is very common for money types
* and here it is converted to 18,1
*/
float f = precision > 0 ? (float) scale / (float) precision : 0;
int p = ( precision > 38 ? 38 : precision );
int s = ( precision > 38 ? (int) ( 38.0 * f ) : ( scale > 38 ? 38 : scale ) );
return super.getTypeName( code, length, p, s );
}
@Override
public boolean areStringComparisonsCaseInsensitive() {
return false;
}
@Override
public boolean supportsExpectedLobUsagePattern() {
return true;
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public boolean supportsExistsInSelect() {
return false;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
return false;
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
statement.registerOutParameter( col, Types.REF );
col++;
return col;
}
@Override
public ResultSet getResultSet(CallableStatement cs) throws SQLException {
boolean isResultSet = cs.execute();
while ( !isResultSet && cs.getUpdateCount() != -1 ) {
isResultSet = cs.getMoreResults();
}
return cs.getResultSet();
}
private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
/**
* Extract the name of the violated constraint from the given SQLException.
*
* @param sqle The exception that was the result of the constraint violation.
* @return The extracted constraint name.
*/
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
int errorCode = sqle.getErrorCode();
if ( errorCode == 27003 ) {
constraintName = extractUsingTemplate( "Unique constraint (", ") violated.", sqle.getMessage() );
}
else if ( errorCode == 2700 ) {
constraintName = extractUsingTemplate( "Referential constraint", "violation:", sqle.getMessage() );
}
else if ( errorCode == 5317 ) {
constraintName = extractUsingTemplate( "Check constraint (", ") violated.", sqle.getMessage() );
}
if ( constraintName != null ) {
int i = constraintName.indexOf( '.' );
if ( i != -1 ) {
constraintName = constraintName.substring( i + 1 );
}
}
return constraintName;
}
};
@Override
public String getWriteLockString(int timeout) {
String sMsg = " Locking row for write ";
if ( timeout == LockOptions.NO_WAIT ) {
return sMsg + " nowait ";
}
return sMsg;
}
@Override
public String getReadLockString(int timeout) {
String sMsg = " Locking row for read ";
if ( timeout == LockOptions.NO_WAIT ) {
return sMsg + " nowait ";
}
return sMsg;
}
@Override
public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map keyColumnNames) {
return new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString() + " " + sql;
}
@Override
public boolean useFollowOnLocking(QueryParameters parameters) {
return true;
}
@Override
public boolean supportsLockTimeouts() {
return false;
}
@Override
public Exporter<Index> getIndexExporter() {
return TeraIndexExporter;
}
private static class TeradataIndexExporter extends StandardIndexExporter implements Exporter<Index> {
public TeradataIndexExporter(Dialect dialect) {
super(dialect);
}
@Override
public String[] getSqlCreateStrings(Index index, Metadata metadata) {
final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment();
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
index.getTable().getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
final String indexNameForCreation;
if ( getDialect().qualifyIndexName() ) {
indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
new QualifiedNameImpl(
index.getTable().getQualifiedTableName().getCatalogName(),
index.getTable().getQualifiedTableName().getSchemaName(),
jdbcEnvironment.getIdentifierHelper().toIdentifier( index.getName() )
),
jdbcEnvironment.getDialect()
);
}
else {
indexNameForCreation = index.getName();
}
StringBuilder colBuf = new StringBuilder("");
boolean first = true;
Iterator<Column> columnItr = index.getColumnIterator();
while ( columnItr.hasNext() ) {
final Column column = columnItr.next();
if ( first ) {
first = false;
}
else {
colBuf.append( ", " );
}
colBuf.append( ( column.getQuotedName( jdbcEnvironment.getDialect() )) );
}
colBuf.append( ")" );
final StringBuilder buf = new StringBuilder()
.append( "create index " )
.append( indexNameForCreation )
.append( '(' )
.append( colBuf )
.append( " on " )
.append( tableName );
return new String[] { buf.toString() };
}
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new Teradata14IdentityColumnSupport();
}
}

View File

@ -6,20 +6,31 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.Teradata14IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.type.StandardBasicTypes;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
/**
* A dialect for the Teradata database created by MCR as part of the
@ -29,35 +40,42 @@ import static org.hibernate.query.TemporalUnit.NANOSECOND;
*/
public class TeradataDialect extends Dialect {
private int version;
int getVersion() {
return version;
}
private static final int PARAM_LIST_SIZE_LIMIT = 1024;
/**
* Constructor
*/
public TeradataDialect() {
super();
public TeradataDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() );
}
//registerColumnType data types
registerColumnType( Types.NUMERIC, "NUMERIC($p,$s)" );
registerColumnType( Types.DOUBLE, "DOUBLE PRECISION" );
registerColumnType( Types.BIGINT, "NUMERIC(18,0)" );
registerColumnType( Types.BIT, "BYTEINT" );
registerColumnType( Types.TINYINT, "BYTEINT" );
registerColumnType( Types.VARBINARY, "VARBYTE($l)" );
registerColumnType( Types.BINARY, "BYTEINT" );
registerColumnType( Types.LONGVARCHAR, "LONG VARCHAR" );
registerColumnType( Types.CHAR, "CHAR(1)" );
registerColumnType( Types.DECIMAL, "DECIMAL" );
registerColumnType( Types.INTEGER, "INTEGER" );
registerColumnType( Types.SMALLINT, "SMALLINT" );
registerColumnType( Types.FLOAT, "FLOAT" );
registerColumnType( Types.VARCHAR, "VARCHAR($l)" );
registerColumnType( Types.DATE, "DATE" );
registerColumnType( Types.TIME, "TIME" );
registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
registerColumnType( Types.BOOLEAN, "BYTEINT" ); // hibernate seems to ignore this type...
registerColumnType( Types.BLOB, "BLOB" );
registerColumnType( Types.CLOB, "CLOB" );
public TeradataDialect() {
this(12);
}
public TeradataDialect(int version) {
super();
this.version = version;
registerColumnType( Types.BOOLEAN, "byteint" );
registerColumnType( Types.BIT, 1, "byteint" );
registerColumnType( Types.BIT, "byteint" );
registerColumnType( Types.TINYINT, "byteint" );
registerColumnType( Types.BINARY, "byte($l)" );
registerColumnType( Types.VARBINARY, "varbyte($l)" );
if ( getVersion() < 13 ) {
registerColumnType( Types.BIGINT, "numeric(19,0)" );
}
else {
//'bigint' has been there since at least version 13
registerColumnType( Types.BIGINT, "bigint" );
}
registerKeyword( "password" );
registerKeyword( "type" );
@ -72,129 +90,122 @@ public class TeradataDialect extends Dialect {
registerKeyword( "account" );
registerKeyword( "class" );
// Tell hibernate to use getBytes instead of getBinaryStream
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
if ( getVersion() < 14 ) {
// use getBytes instead of getBinaryStream
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
// no batch statements
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
else {
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
}
// No batch statements
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public int getDefaultDecimalPrecision() {
return getVersion() < 14 ? 18 : 38;
}
@Override
public long getFractionalSecondPrecisionInNanos() {
// Do duration arithmetic in a seconds, but
// with the fractional part
return 1_000_000_000; //seconds!!
}
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
StringBuilder pattern = new StringBuilder();
//TODO: TOTALLY UNTESTED CODE!
pattern.append("cast((?3 - ?2) ");
switch (unit) {
case NANOSECOND:
case NATIVE:
//default fractional precision is 6, the maximum
pattern.append("second");
break;
case WEEK:
pattern.append("day");
break;
case QUARTER:
pattern.append("month");
break;
default:
pattern.append( "?1" );
}
pattern.append("(4) as bigint)");
switch (unit) {
case WEEK:
pattern.append("/7");
break;
case QUARTER:
pattern.append("/3");
break;
case NANOSECOND:
pattern.append("*1e9");
break;
}
return pattern.toString();
}
@Override
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
//TODO: TOTALLY UNTESTED CODE!
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e9 * interval '1' second)";
case NATIVE:
return "(?3 + (?2) * interval '1' second)";
case QUARTER:
return "(?3 + (?2) * interval '3' month)";
case WEEK:
return "(?3 + (?2) * interval '7' day)";
default:
return "(?3 + (?2) * interval '1' ?1)";
}
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.concat_operator( queryEngine );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.moreHyperbolic( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.position( queryEngine );
queryEngine.getSqmFunctionRegistry().registerPattern(
"substring",
"substring(?1 from ?2 for ?3)",
StandardBasicTypes.STRING
);
queryEngine.getSqmFunctionRegistry().registerPattern( "mod", "(?1 mod ?2)", StandardBasicTypes.STRING );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "mod", "(?1 mod ?2)" )
.setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 )
.register();
}
@Override
public void timestampdiff(
TemporalUnit unit,
Renderer from,
Renderer to,
Appender sqlAppender,
boolean fromTimestamp,
boolean toTimestamp) {
//TODO: TOTALLY UNTESTED CODE!
if ( unit == NANOSECOND ) {
sqlAppender.append( "1e9*" );
if ( getVersion() >= 14 ) {
//list actually taken from Teradata 15 docs
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.initcap( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.ascii( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.moreHyperbolic( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
}
sqlAppender.append( "((" );
to.render();
sqlAppender.append( " - " );
from.render();
sqlAppender.append( ") " );
switch ( unit ) {
case NANOSECOND: {
sqlAppender.append( "second(19,9)" );
break;
}
case WEEK: {
sqlAppender.append( "day(19,0)" );
break;
}
case QUARTER: {
sqlAppender.append( "month(19,0)" );
break;
}
default: {
sqlAppender.append( unit.toString() );
sqlAppender.append( "(19,0)" );
}
}
sqlAppender.append( ")" );
switch ( unit ) {
case WEEK: {
sqlAppender.append( "/7" );
break;
}
case QUARTER: {
sqlAppender.append( "/3" );
break;
}
}
}
@Override
public void timestampadd(
TemporalUnit unit,
Renderer magnitude,
Renderer to,
Appender sqlAppender,
boolean timestamp) {
//TODO: TOTALLY UNTESTED CODE!
sqlAppender.append( "(" );
to.render();
boolean subtract = false;
// if ( magnitude.startsWith("-") ) {
// subtract = true;
// magnitude = magnitude.substring(1);
// }
sqlAppender.append( subtract ? " - " : " + " );
switch ( unit ) {
case NANOSECOND: {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ")/1e9 * interval '1' second" );
break;
}
case QUARTER: {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ") * interval '3' month" );
break;
}
case WEEK: {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ") * interval '7' day" );
break;
}
default: {
// if ( magnitude.matches("\\d+") ) {
// sqlAppender.append("interval '");
// sqlAppender.append( magnitude );
// sqlAppender.append("'");
// }
// else {
sqlAppender.append( "(" );
magnitude.render();
sqlAppender.append( ") * interval '1'" );
// }
sqlAppender.append( " " );
sqlAppender.append( unit.toString() );
}
}
sqlAppender.append( ")" );
}
/**
@ -207,14 +218,9 @@ public class TeradataDialect extends Dialect {
return "";
}
@Override
public boolean supportsSequences() {
return false;
}
@Override
public String getAddColumnString() {
return "Add Column";
return getVersion() < 14 ? super.getAddColumnString() : "add";
}
@Override
@ -250,29 +256,6 @@ public class TeradataDialect extends Dialect {
// return "delete from";
// }
/**
* Get the name of the database type associated with the given
* <tt>java.sql.Types</tt> typecode.
*
* @param code <tt>java.sql.Types</tt> typecode
* @param length the length or precision of the column
* @param precision the precision of the column
* @param scale the scale of the column
* @return the database type name
* @throws HibernateException
*/
public String getTypeName(int code, int length, int precision, int scale) throws HibernateException {
/*
* We might want a special case for 19,2. This is very common for money types
* and here it is converted to 18,1
*/
float f = precision > 0 ? (float) scale / (float) precision : 0;
int p = ( precision > 18 ? 18 : precision );
int s = ( precision > 18 ? (int) ( 18.0 * f ) : ( scale > 18 ? 18 : scale ) );
return super.getTypeName( code, length, p, s );
}
@Override
public boolean supportsCascadeDelete() {
return false;
@ -283,9 +266,19 @@ public class TeradataDialect extends Dialect {
return false;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public boolean supportsExistsInSelect() {
return false;
}
@Override
public boolean areStringComparisonsCaseInsensitive() {
return true;
return getVersion() < 14;
}
@Override
@ -318,6 +311,7 @@ public class TeradataDialect extends Dialect {
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
v = "cast(null as timestamp)";
break;
case Types.BINARY:
@ -339,6 +333,11 @@ public class TeradataDialect extends Dialect {
return v;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
return false;
}
@Override
public String getCreateMultisetTableString() {
return "create multiset table ";
@ -368,4 +367,168 @@ public class TeradataDialect extends Dialect {
public int getInExpressionCountLimit() {
return PARAM_LIST_SIZE_LIMIT;
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
statement.registerOutParameter( col, Types.REF );
col++;
return col;
}
@Override
public ResultSet getResultSet(CallableStatement cs) throws SQLException {
boolean isResultSet = cs.execute();
while ( !isResultSet && cs.getUpdateCount() != -1 ) {
isResultSet = cs.getMoreResults();
}
return cs.getResultSet();
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return getVersion() < 14 ? super.getViolatedConstraintNameExtracter() : EXTRACTER;
}
private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
/**
* Extract the name of the violated constraint from the given SQLException.
*
* @param sqle The exception that was the result of the constraint violation.
* @return The extracted constraint name.
*/
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
String constraintName = null;
int errorCode = sqle.getErrorCode();
switch (errorCode) {
case 27003:
constraintName = extractUsingTemplate( "Unique constraint (", ") violated.", sqle.getMessage() );
break;
case 2700:
constraintName = extractUsingTemplate( "Referential constraint", "violation:", sqle.getMessage() );
break;
case 5317:
constraintName = extractUsingTemplate( "Check constraint (", ") violated.", sqle.getMessage() );
break;
}
if ( constraintName != null ) {
int i = constraintName.indexOf( '.' );
if ( i != -1 ) {
constraintName = constraintName.substring( i + 1 );
}
}
return constraintName;
}
};
@Override
public boolean supportsLockTimeouts() {
return false;
}
@Override
public boolean useFollowOnLocking(String sql, QueryOptions queryOptions) {
return getVersion() >= 14;
}
@Override
public String getWriteLockString(int timeout) {
if ( getVersion() < 14 ) {
return super.getWriteLockString( timeout );
}
String sMsg = " Locking row for write ";
if ( timeout == LockOptions.NO_WAIT ) {
return sMsg + " nowait ";
}
return sMsg;
}
@Override
public String getReadLockString(int timeout) {
if ( getVersion() < 14 ) {
return super.getReadLockString( timeout );
}
String sMsg = " Locking row for read ";
if ( timeout == LockOptions.NO_WAIT ) {
return sMsg + " nowait ";
}
return sMsg;
}
// @Override
// public Exporter<Index> getIndexExporter() {
// return new TeradataIndexExporter(this);
// }
//
// private static class TeradataIndexExporter extends StandardIndexExporter implements Exporter<Index> {
//
// private TeradataIndexExporter(Dialect dialect) {
// super(dialect);
// }
//
// @Override
// public String[] getSqlCreateStrings(Index index, JdbcServices jdbcServices) {
// final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
// QualifiedTableName qualifiedTableName = index.getTable().getQualifiedTableName();
// final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
// qualifiedTableName,
// jdbcEnvironment.getDialect()
// );
//
// final String indexNameForCreation;
// if ( getDialect().qualifyIndexName() ) {
// indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
// new QualifiedNameImpl(
// qualifiedTableName.getCatalogName(),
// qualifiedTableName.getSchemaName(),
// index.getName()
// ),
// jdbcEnvironment.getDialect()
// );
// }
// else {
// indexNameForCreation = index.getName().render( jdbcEnvironment.getDialect() );
// }
//
// StringBuilder columnList = new StringBuilder();
// boolean first = true;
// for ( PhysicalColumn column : index.getColumns() ) {
// if ( first ) {
// first = false;
// }
// else {
// columnList.append( ", " );
// }
// columnList.append( column.getName().render( jdbcEnvironment.getDialect() ) );
// }
//
// return new String[] {
// "create index " + indexNameForCreation
// + "(" + columnList + ") on " + tableName
// };
// }
// }
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return getVersion() < 14
? super.getIdentityColumnSupport()
: new Teradata14IdentityColumnSupport();
}
@Override
@SuppressWarnings("deprecation")
public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map<String, String[]> keyColumnNames) {
return getVersion() < 14
? super.applyLocksToSql( sql, aliasedLockOptions, keyColumnNames )
: new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString() + " " + sql;
}
@Override
public LimitHandler getLimitHandler() {
//TODO: is this right?!
return TopLimitHandler.INSTANCE;
}
}

View File

@ -6,33 +6,26 @@
*/
package org.hibernate.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.pagination.FirstLimitHandler;
import org.hibernate.dialect.pagination.LegacyFirstLimitHandler;
import org.hibernate.dialect.lock.*;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TimesTenLimitHandler;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.sequence.TimesTenSequenceSupport;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.OracleJoinFragment;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorTimesTenDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import java.sql.Types;
/**
* A SQL dialect for TimesTen 5.1.
@ -47,91 +40,106 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
* No Calendar support
* No support for updating primary keys.
*
* @author Sherry Listgarten and Max Andersen
* @author Sherry Listgarten, Max Andersen, Chris Jenkins
*/
@SuppressWarnings("deprecation")
public class TimesTenDialect extends Dialect {
/**
* Constructs a TimesTenDialect
*/
public TimesTenDialect() {
super();
registerColumnType( Types.BIT, "TINYINT" );
registerColumnType( Types.BIGINT, "BIGINT" );
registerColumnType( Types.SMALLINT, "SMALLINT" );
registerColumnType( Types.TINYINT, "TINYINT" );
registerColumnType( Types.INTEGER, "INTEGER" );
registerColumnType( Types.CHAR, "CHAR(1)" );
registerColumnType( Types.VARCHAR, "VARCHAR($l)" );
registerColumnType( Types.FLOAT, "FLOAT" );
registerColumnType( Types.DOUBLE, "DOUBLE" );
registerColumnType( Types.DATE, "DATE" );
registerColumnType( Types.TIME, "TIME" );
registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
registerColumnType( Types.VARBINARY, "VARBINARY($l)" );
registerColumnType( Types.NUMERIC, "DECIMAL($p, $s)" );
// TimesTen has no BLOB/CLOB support, but these types may be suitable
// for some applications. The length is limited to 4 million bytes.
registerColumnType( Types.BLOB, "VARBINARY(4000000)" );
registerColumnType( Types.CLOB, "VARCHAR(4000000)" );
//Note: these are the correct type mappings
// for the default Oracle type mode
// TypeMode=0
registerColumnType( Types.BIT, 1, "tt_tinyint" );
registerColumnType( Types.BIT, "tt_tinyint" );
registerColumnType( Types.BOOLEAN, "tt_tinyint" );
registerColumnType(Types.TINYINT, "tt_tinyint");
registerColumnType(Types.SMALLINT, "tt_smallint");
registerColumnType(Types.INTEGER, "tt_integer");
registerColumnType(Types.BIGINT, "tt_bigint");
//note that 'binary_float'/'binary_double' might
//be better mappings for Java Float/Double
//'numeric'/'decimal' are synonyms for 'number'
registerColumnType(Types.NUMERIC, "number($p,$s)");
registerColumnType(Types.DECIMAL, "number($p,$s)" );
registerColumnType( Types.VARCHAR, "varchar2($l)" );
registerColumnType( Types.NVARCHAR, "nvarchar2($l)" );
//do not use 'date' because it's a datetime
registerColumnType(Types.DATE, "tt_date");
//'time' and 'tt_time' are synonyms
registerColumnType(Types.TIME, "tt_time");
//`timestamp` has more precision than `tt_timestamp`
// registerColumnType(Types.TIMESTAMP, "tt_timestamp");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)");
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public int getDefaultDecimalPrecision() {
//the maximum
return 40;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory.pad( queryEngine );
CommonFunctionFactory.trim2( queryEngine );
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.toCharNumberDateTimestamp( queryEngine );
CommonFunctionFactory.ceiling_ceil( queryEngine );
CommonFunctionFactory.instr( queryEngine );
CommonFunctionFactory.substr( queryEngine );
CommonFunctionFactory.substring_substr( queryEngine );
CommonFunctionFactory.leftRight_substr( queryEngine );
CommonFunctionFactory.char_chr( queryEngine );
CommonFunctionFactory.rownumRowid( queryEngine );
CommonFunctionFactory.sysdate( queryEngine );
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
).setArgumentListSignature("(pattern, string[, start])");
}
@Override
public void timestampadd(TemporalUnit unit, Renderer magnitude, Renderer to, Appender sqlAppender, boolean timestamp) {
sqlAppender.append("timestampadd(sql_tsi_");
if (unit == TemporalUnit.NANOSECOND) {
sqlAppender.append("frac_second");
public String timestampaddPattern(TemporalUnit unit, boolean timestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampadd(sql_tsi_frac_second, ?2, ?3)";
default:
return "timestampadd(sql_tsi_?1, ?2, ?3)";
}
else {
sqlAppender.append(unit.toString());
}
//TODO: millisecond, microsecond
sqlAppender.append(", ");
magnitude.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public void timestampdiff(TemporalUnit unit, Renderer from, Renderer to, Appender sqlAppender, boolean fromTimestamp, boolean toTimestamp) {
sqlAppender.append("timestampdiff(sql_tsi_");
if (unit == TemporalUnit.NANOSECOND) {
sqlAppender.append("frac_second");
public String timestampdiffPattern(TemporalUnit unit, boolean fromTimestamp, boolean toTimestamp) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampdiff(sql_tsi_frac_second, ?2, ?3)";
default:
return "timestampdiff(sql_tsi_?1, ?2, ?3)";
}
else {
sqlAppender.append(unit.toString());
}
sqlAppender.append(", ");
from.render();
sqlAppender.append(", ");
to.render();
sqlAppender.append(")");
}
@Override
public boolean dropConstraints() {
return true;
}
@Override
@ -145,33 +153,13 @@ public class TimesTenDialect extends Dialect {
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public String getSelectSequenceNextValString(String sequenceName) {
return sequenceName + ".nextval";
}
@Override
public String getSequenceNextValString(String sequenceName) {
return "select first 1 " + sequenceName + ".nextval from sys.tables";
}
@Override
public String getCreateSequenceString(String sequenceName) {
return "create sequence " + sequenceName;
}
@Override
public String getDropSequenceString(String sequenceName) {
return "drop sequence " + sequenceName;
public SequenceSupport getSequenceSupport() {
return TimesTenSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select * from sys.sequences";
return "select name from sys.sequences";
}
@Override
@ -179,19 +167,19 @@ public class TimesTenDialect extends Dialect {
return SequenceInformationExtractorTimesTenDatabaseImpl.INSTANCE;
}
@Override
public JoinFragment createOuterJoinFragment() {
return new OracleJoinFragment();
}
@Override
public String getCrossJoinSeparator() {
return ", ";
}
@Override
public String getForUpdateString() {
return "";
public boolean supportsNoWait() {
return true;
}
@Override
public String getForUpdateNowaitString() {
return " for update nowait";
}
@Override
@ -206,41 +194,7 @@ public class TimesTenDialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
if ( isLegacyLimitHandlerBehaviorEnabled() ) {
return LegacyFirstLimitHandler.INSTANCE;
}
return FirstLimitHandler.INSTANCE;
}
@Override
public boolean supportsLimitOffset() {
return false;
}
@Override
public boolean supportsVariableLimit() {
return false;
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
@Override
public String getLimitString(String querySelect, int offset, int limit) {
if ( offset > 0 ) {
throw new UnsupportedOperationException( "query result offset is not supported" );
}
return new StringBuilder( querySelect.length() + 8 )
.append( querySelect )
.insert( 6, " first " + limit )
.toString();
return TimesTenLimitHandler.INSTANCE;
}
@Override
@ -250,7 +204,7 @@ public class TimesTenDialect extends Dialect {
@Override
public String getCurrentTimestampSelectString() {
return "select first 1 sysdate from sys.tables";
return "select sysdate from sys.dual";
}
@Override
@ -289,22 +243,19 @@ public class TimesTenDialect extends Dialect {
@Override
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
// TimesTen has no known variation of a "SELECT ... FOR UPDATE" syntax...
if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode );
switch ( lockMode ) {
case OPTIMISTIC:
return new OptimisticLockingStrategy( lockable, lockMode );
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode );
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode );
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode );
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.PESSIMISTIC_WRITE ) {
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.PESSIMISTIC_READ ) {
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC ) {
return new OptimisticLockingStrategy( lockable, lockMode );
}
else if ( lockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT ) {
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode );
}
else if ( lockMode.greaterThan( LockMode.READ ) ) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {
@ -312,10 +263,37 @@ public class TimesTenDialect extends Dialect {
}
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public boolean supportsEmptyInList() {
public boolean supportsCircularCascadeDeleteConstraints() {
return false;
}
@Override
public boolean supportsUniqueConstraintInCreateAlterTable() {
return false;
}
@Override
public String getSelectClauseNullString(int sqlType) {
switch (sqlType) {
case Types.VARCHAR:
case Types.CHAR:
return "to_char(null)";
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
return "to_date(null)";
default:
return "to_number(null)";
}
}
}

View File

@ -6,13 +6,12 @@
*/
package org.hibernate.dialect;
import org.hibernate.internal.util.StringHelper;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.hibernate.MappingException;
import org.hibernate.internal.util.StringHelper;
/**
* This class maps a type to names. Associations may be marked with a capacity. Calling the get()
* method with a type and actual size n will return the associated name with smallest capacity >= n,
@ -60,17 +59,11 @@ public final class TypeNames {
*
* @param typeCode the type key
*
* @return the default type name associated with specified key
*
* @throws MappingException Indicates that no registrations were made for that typeCode
* @return the default type name associated with specified key, or
* null if there was no type name associated with the key
*/
public String get(final int typeCode) throws MappingException {
final Integer integer = Integer.valueOf( typeCode );
final String result = defaults.get( integer );
if ( result == null ) {
throw new MappingException( "No Dialect mapping for JDBC type: " + typeCode );
}
return result;
public String get(final int typeCode) {
return defaults.get( typeCode );
}
/**
@ -82,12 +75,9 @@ public final class TypeNames {
* @param precision the SQL precision
*
* @return the associated name with smallest capacity >= size, if available and the default type name otherwise
*
* @throws MappingException Indicates that no registrations were made for that typeCode
*/
public String get(int typeCode, long size, int precision, int scale) throws MappingException {
final Integer integer = Integer.valueOf( typeCode );
final Map<Long, String> map = weighted.get( integer );
public String get(int typeCode, Long size, Integer precision, Integer scale) {
final Map<Long, String> map = weighted.get( typeCode );
if ( map != null && map.size() > 0 ) {
// iterate entries ordered by capacity to find first fit
for ( Map.Entry<Long, String> entry: map.entrySet() ) {
@ -103,10 +93,17 @@ public final class TypeNames {
return replace( get( typeCode ), size, precision, scale );
}
private static String replace(String type, long size, int precision, int scale) {
type = StringHelper.replaceOnce( type, "$s", Integer.toString( scale ) );
type = StringHelper.replaceOnce( type, "$l", Long.toString( size ) );
return StringHelper.replaceOnce( type, "$p", Integer.toString( precision ) );
private static String replace(String type, Long size, Integer precision, Integer scale) {
if ( scale != null ) {
type = StringHelper.replaceOnce( type, "$s", Integer.toString( scale ) );
}
if ( size != null ) {
type = StringHelper.replaceOnce( type, "$l", Long.toString( size ) );
}
if ( precision != null ) {
type = StringHelper.replaceOnce( type, "$p", Integer.toString( precision ) );
}
return type;
}
/**
@ -117,14 +114,8 @@ public final class TypeNames {
* @param value The mapping (type name)
*/
public void put(int typeCode, long capacity, String value) {
final Integer integer = Integer.valueOf( typeCode );
Map<Long, String> map = weighted.get( integer );
if ( map == null ) {
// add new ordered map
map = new TreeMap<Long, String>();
weighted.put( integer, map );
}
map.put( capacity, value );
weighted.computeIfAbsent( typeCode, k -> new TreeMap<>() )
.put( capacity, value );
}
/**
@ -134,8 +125,7 @@ public final class TypeNames {
* @param value The mapping (type name)
*/
public void put(int typeCode, String value) {
final Integer integer = Integer.valueOf( typeCode );
defaults.put( integer, value );
defaults.put( typeCode, value );
}
/**

View File

@ -1,95 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/**
* CUBRID supports a limited list of temporal fields in the
* extract() function, but we can emulate some of them by
* using the appropriate named functions instead of
* extract().
*
* Thus, the additional supported fields are
* {@link TemporalUnit#DAY_OF_YEAR},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*
* In addition, the field {@link TemporalUnit#SECOND} is
* redefined to include milliseconds.
*
* @author Gavin King
*/
public class CUBRIDExtractEmulation implements SqmFunctionDescriptor {
private final static ArgumentsValidator argsValidator = StandardArgumentsValidators.exactly( 2 );
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> sqmArguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
argsValidator.validate( sqmArguments );
final SqmExtractUnit<?> extractUnit = (SqmExtractUnit<?>) sqmArguments.get( 0 );
final TemporalUnit unit = extractUnit.getTemporalUnit();
final String pattern;
switch ( unit ) {
case SECOND: {
pattern = "(second(?2)+extract(millisecond from ?2)/1e3)";
break;
}
case DAY_OF_WEEK: {
pattern = "dayofweek(?2)";
break;
}
case DAY_OF_MONTH: {
pattern = "dayofmonth(?2)";
break;
}
case DAY_OF_YEAR: {
pattern = "dayofyear(?2)";
break;
}
case WEEK: {
pattern = "week(?2,3)"; //mode 3 is the ISO week
break;
}
default: {
pattern = unit + "(?2)";
break;
}
}
final SqmFunctionDescriptor extract = creationState.getCreationContext()
.getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.patternDescriptorBuilder( pattern )
.setReturnTypeResolver( useArgType( 1 ) )
.setExactArgumentCount( 2 )
.build();
return extract.generateSqlExpression( functionName, sqmArguments, inferableTypeAccess, converter, creationState );
}
}

View File

@ -0,0 +1,73 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.CastType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/**
* @author Gavin King
*/
public class CastFunction
extends AbstractSqmFunctionDescriptor {
private Dialect dialect;
public CastFunction(Dialect dialect) {
super(
"cast",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 2 )
);
this.dialect = dialect;
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
SqmCastTarget<?> targetType = (SqmCastTarget<?>) arguments.get(1);
SqmExpression<?> arg = (SqmExpression<?>) arguments.get(0);
CastType to = CastType.from( targetType.getType() );
CastType from = CastType.from( arg.getNodeType() );
return queryEngine.getSqmFunctionRegistry()
.patternDescriptorBuilder( "cast", dialect.castPattern( from, to ) )
.setExactArgumentCount( 2 )
.setReturnTypeResolver( useArgType( 2 ) )
.descriptor()
.generateSqmExpression(
arguments,
impliedResultType,
queryEngine,
typeConfiguration
);
}
@Override
public String getArgumentListSignature() {
return "(arg as Type)";
}
}

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
import static java.util.Arrays.asList;
/**
* @author Gavin King
*/
public class CastStrEmulation
extends AbstractSqmFunctionDescriptor {
public CastStrEmulation() {
super(
"str",
StandardArgumentsValidators.exactly( 1 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
);
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
SqmTypedNode<?> argument = arguments.get(0);
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( "cast" )
.generateSqmExpression(
asList(
argument,
new SqmCastTarget<>(
impliedResultType,
argument.nodeBuilder()
)
),
impliedResultType,
queryEngine,
typeConfiguration
);
}
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
/**
* @author Gavin King
*/
public class CoalesceIfnullEmulation
extends AbstractSqmFunctionDescriptor {
public CoalesceIfnullEmulation() {
super(
"ifnull",
StandardArgumentsValidators.exactly( 2 )
);
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( "coalesce" )
.generateSqmExpression(
arguments,
impliedResultType,
queryEngine,
typeConfiguration
);
}
}

View File

@ -0,0 +1,73 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionRenderingSupport;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
/**
* @author Gavin King
*/
public class CurrentFunction
extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport {
private final String name;
private final String sql;
public CurrentFunction(String name, String sql, BasicType type) {
super(
name,
StandardArgumentsValidators.NO_ARGS,
StandardFunctionReturnTypeResolvers.invariant( type )
);
this.name = name;
this.sql = sql;
}
@Override
public void render(
SqlAppender sqlAppender,
List<SqlAstNode> arguments,
SqlAstWalker walker) {
sqlAppender.appendSql(sql);
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
return new SelfRenderingSqlFunctionExpression<T>(
this, this,
arguments,
impliedResultType,
getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(),
name
);
}
@Override
public String getArgumentListSignature() {
return "";
}
}

View File

@ -6,14 +6,24 @@
*/
package org.hibernate.dialect.function;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionRenderingSupport;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
/**
* DB2's varchar_format() can't handle quoted literal strings in
@ -23,50 +33,75 @@ import org.hibernate.type.StandardBasicTypes;
*
* @author Gavin King
*/
public class DB2FormatEmulation extends AbstractSqmFunctionDescriptor {
public class DB2FormatEmulation
extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport {
public DB2FormatEmulation() {
super(
"format",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
);
}
@Override
public FunctionRenderingSupport getRenderingSupport() {
return (sqlAppender, functionName, sqlAstArguments, walker, sessionFactory) -> {
final Expression datetime = (Expression) sqlAstArguments.get( 0 );
final Format format = (Format) sqlAstArguments.get( 1 );
public void render(
SqlAppender sqlAppender,
List<SqlAstNode> arguments,
SqlAstWalker walker) {
Expression datetime = (Expression) arguments.get(0);
Format format = (Format) arguments.get(1);
sqlAppender.appendSql("(");
String[] bits = Oracle8iDialect.datetimeFormat( format.getFormat(), false ).result().split( "\"");
boolean first = true;
for ( int i=0; i<bits.length; i++ ) {
String bit = bits[i];
if ( !bit.isEmpty() ) {
if ( first ) {
first = false;
}
else {
sqlAppender.appendSql("||");
}
if ( i % 2 == 0 ) {
sqlAppender.appendSql("varchar_format(");
datetime.accept(walker);
sqlAppender.appendSql(",'");
sqlAppender.appendSql( bit );
sqlAppender.appendSql("')");
}
else {
sqlAppender.appendSql("'");
sqlAppender.appendSql( bit );
sqlAppender.appendSql("'");
}
sqlAppender.appendSql("(");
String[] bits = OracleDialect.datetimeFormat( format.getFormat(), false ).result().split("\"");
boolean first = true;
for ( int i=0; i<bits.length; i++ ) {
String bit = bits[i];
if ( !bit.isEmpty() ) {
if ( first ) {
first = false;
}
else {
sqlAppender.appendSql("||");
}
if ( i % 2 == 0 ) {
sqlAppender.appendSql("varchar_format(");
datetime.accept(walker);
sqlAppender.appendSql(",'");
sqlAppender.appendSql( bit );
sqlAppender.appendSql("')");
}
else {
sqlAppender.appendSql("'");
sqlAppender.appendSql( bit );
sqlAppender.appendSql("'");
}
}
if ( first ) {
sqlAppender.appendSql("''");
}
sqlAppender.appendSql(")");
};
}
if ( first ) {
sqlAppender.appendSql("''");
}
sqlAppender.appendSql(")");
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
return new SelfRenderingSqlFunctionExpression<T>(
this, this,
arguments,
impliedResultType,
getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(),
"format"
);
}
@Override
public String getArgumentListSignature() {
return "(datetime as pattern)";
}
}

View File

@ -6,34 +6,71 @@
*/
package org.hibernate.dialect.function;
import org.hibernate.query.sqm.produce.function.SqmFunctionAsExpressionDescriptor;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionRenderingSupport;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.StandardBasicTypes;
import java.util.List;
/**
* A specialized concat() function definition in which:<ol>
* <li>we translate to use the concat operator ('||')</li>
* <li>wrap dynamic parameters in CASTs to VARCHAR</li>
* </ol>
* <p/>
* This last spec is to deal with a limitation on DB2 and variants (e.g. Derby)
* where dynamic parameters cannot be used in concatenation unless they are being
* concatenated with at least one non-dynamic operand. And even then, the rules
* are so convoluted as to what is allowed and when the CAST is needed and when
* it is not that we just go ahead and do the CASTing.
* Casts query parameters using the Derby varchar() function
* before concatenating them using the || operator.
*
* @author Steve Ebersole
* @author Christian Beikov
*/
public class DerbyConcatEmulation extends SqmFunctionAsExpressionDescriptor {
public class DerbyConcatEmulation
extends AbstractSqmSelfRenderingFunctionDescriptor
implements FunctionRenderingSupport {
public DerbyConcatEmulation() {
super(
"(",
"||",
")",
StandardArgumentsValidators.min( 2 ),
"concat",
StandardArgumentsValidators.min( 1 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
);
}
@Override
public FunctionRenderingSupport getRenderingSupport() {
return this;
}
@Override
public void render(
SqlAppender sqlAppender,
List<SqlAstNode> arguments,
SqlAstWalker walker) {
int numberOfArguments = arguments.size();
if ( numberOfArguments > 1 ) {
sqlAppender.appendSql("(");
}
for ( int i = 0; i < numberOfArguments; i++ ) {
SqlAstNode argument = arguments.get( i );
if ( i > 0 ) {
sqlAppender.appendSql("||");
}
boolean param = false; //TODO: argument instanceof GenericParameter;
if ( param ) {
sqlAppender.appendSql("cast(");
}
argument.accept(walker);
if ( param ) {
sqlAppender.appendSql(" as long varchar)");
}
}
if ( numberOfArguments > 1 ) {
sqlAppender.appendSql(")");
}
}
@Override
public String getArgumentListSignature() {
return "(string0[, string1[, ...]])";
}
}

View File

@ -0,0 +1,262 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.*;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import java.time.ZoneOffset;
import java.util.List;
import static java.util.Arrays.asList;
import static org.hibernate.query.BinaryArithmeticOperator.*;
import static org.hibernate.query.TemporalUnit.*;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/**
* @author Gavin King
*/
public class ExtractFunction
extends AbstractSqmFunctionDescriptor {
private Dialect dialect;
public ExtractFunction(Dialect dialect) {
super(
"extract",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 1 )
);
this.dialect = dialect;
}
@Override
protected <T> SelfRenderingSqlFunctionExpression generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
SqmExtractUnit<?> field = (SqmExtractUnit<?>) arguments.get(0);
SqmExpression<?> expression = (SqmExpression<?>) arguments.get(1);
TemporalUnit unit = field.getUnit();
switch ( unit ) {
case NANOSECOND:
return extractNanoseconds( expression, queryEngine, typeConfiguration );
case NATIVE:
throw new SemanticException("can't extract() the field TemporalUnit.NATIVE");
case OFFSET:
// use format(arg, 'xxx') to get the offset
return extractOffsetUsingFormat( expression, queryEngine, typeConfiguration );
case DATE:
case TIME:
// use cast(arg as Type) to get the date or time part
// which might be javax.sql.Date / javax.sql.Time or
// java.time.LocalDate / java.time.LocalTime depending
// on the type of the expression we're extracting from
return extractDateOrTimeUsingCast( expression, field.getType(), queryEngine, typeConfiguration );
case WEEK_OF_MONTH:
// use ceiling(extract(day of month, arg)/7.0)
return extractWeek( expression, field, DAY_OF_MONTH, queryEngine, typeConfiguration);
case WEEK_OF_YEAR:
// use ceiling(extract(day of year, arg)/7.0)
return extractWeek( expression, field, DAY_OF_YEAR, queryEngine, typeConfiguration);
default:
// otherwise it's something we expect the SQL dialect
// itself to understand, either natively, or via the
// method Dialect.extract()
String pattern = dialect.extractPattern( unit );
return queryEngine.getSqmFunctionRegistry()
.patternDescriptorBuilder( "extract", pattern )
.setExactArgumentCount( 2 )
.setReturnTypeResolver( useArgType( 1 ) )
.descriptor()
.generateSqmExpression(
arguments,
impliedResultType,
queryEngine,
typeConfiguration
);
}
}
private SelfRenderingSqlFunctionExpression<Integer> extractWeek(
SqmExpression<?> expressionToExtract,
SqmExtractUnit<?> field,
TemporalUnit dayOf,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
NodeBuilder builder = field.nodeBuilder();
BasicType<Integer> intType = typeConfiguration.getBasicTypeForJavaType( Integer.class );
BasicType<Float> floatType = typeConfiguration.getBasicTypeForJavaType( Float.class );
SqmExtractUnit<Integer> dayOfUnit = new SqmExtractUnit<>( dayOf, intType, builder );
SqmExpression<Integer> extractDayOf
= queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("extract")
.generateSqmExpression(
asList( dayOfUnit, expressionToExtract ),
intType,
queryEngine,
typeConfiguration
);
SqmExtractUnit<Integer> dayOfWeekUnit = new SqmExtractUnit<>( DAY_OF_WEEK, intType, builder );
SqmExpression<Integer> extractDayOfWeek
= queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("extract")
.generateSqmExpression(
asList( dayOfWeekUnit, expressionToExtract ),
intType,
queryEngine,
typeConfiguration
);
SqmLiteral<Float> seven = new SqmLiteral<>( 7.0f, floatType, builder );
SqmLiteral<Integer> one = new SqmLiteral<>( 1, intType, builder );
return queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("ceiling")
.generateSqmExpression(
new SqmBinaryArithmetic<>(
ADD,
new SqmBinaryArithmetic<>(
DIVIDE,
new SqmBinaryArithmetic<>(
SUBTRACT,
extractDayOf,
extractDayOfWeek,
intType,
builder
),
seven,
floatType,
builder
),
one,
intType,
builder
),
intType,
queryEngine,
typeConfiguration
);
}
private SelfRenderingSqlFunctionExpression<Long> toLong(
SqmExpression<?> arg,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
//Not every database supports round() (looking at you Derby)
//so use floor() instead, which is perfectly fine for this
// return getFunctionTemplate("round").makeSqmFunctionExpression(
// asList( arg, integerLiteral("0") ),
// basicType( Long.class ),
// creationContext.getQueryEngine(),
// creationContext.getDomainModel().getTypeConfiguration()
// );
BasicType<Long> longType = typeConfiguration.getBasicTypeForJavaType(Long.class);
return queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("floor")
.generateSqmExpression(
arg,
longType,
queryEngine,
typeConfiguration
);
}
private SelfRenderingSqlFunctionExpression<Long> extractNanoseconds(
SqmExpression<?> expressionToExtract,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
NodeBuilder builder = expressionToExtract.nodeBuilder();
BasicType<Float> floatType = typeConfiguration.getBasicTypeForJavaType(Float.class);
SqmExtractUnit<Float> extractSeconds = new SqmExtractUnit<>( SECOND, floatType, builder );
SqmLiteral<Float> billion = new SqmLiteral<>( 1e9f, floatType, builder );
return toLong(
new SqmBinaryArithmetic<>(
MULTIPLY,
generateSqmExpression(
asList( extractSeconds, expressionToExtract ),
floatType,
queryEngine,
typeConfiguration
),
billion,
floatType,
builder
),
queryEngine,
typeConfiguration
);
}
private SelfRenderingSqlFunctionExpression<ZoneOffset> extractOffsetUsingFormat(
SqmExpression<?> expressionToExtract,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
NodeBuilder builder = expressionToExtract.nodeBuilder();
BasicType<ZoneOffset> offsetType = typeConfiguration.getBasicTypeForJavaType(ZoneOffset.class);
BasicType<String> stringType = typeConfiguration.getBasicTypeForJavaType(String.class);
SqmFormat offsetFormat = new SqmFormat(
"xxx", //pattern for timezone offset
stringType,
builder
);
return queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("format")
.generateSqmExpression(
asList( expressionToExtract, offsetFormat ),
offsetType,
queryEngine,
typeConfiguration
);
}
private SelfRenderingSqlFunctionExpression<?> extractDateOrTimeUsingCast(
SqmExpression<?> expressionToExtract,
AllowableFunctionReturnType<?> type,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
NodeBuilder builder = expressionToExtract.nodeBuilder();
SqmCastTarget<?> target = new SqmCastTarget<>( type, builder );
return queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor("cast")
.generateSqmExpression(
asList( expressionToExtract, target ),
type,
queryEngine,
typeConfiguration
);
}
@Override
public String getArgumentListSignature() {
return "(field from arg)";
}
}

View File

@ -1,59 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/**
* In H2, the extract() function does not return
* fractional seconds for the the field
* {@link TemporalUnit#SECOND}. We work around
* this here with two calls to extract().
*
* @author Gavin King
*/
public class H2ExtractEmulation implements SqmFunctionDescriptor {
private static final ArgumentsValidator ARGS_VALIDATOR = StandardArgumentsValidators.exactly( 2 );
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> arguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
ARGS_VALIDATOR.validate( arguments );
final SqmExtractUnit<?> extractUnit = (SqmExtractUnit<?>) arguments.get( 0 );
final TemporalUnit unit = extractUnit.getTemporalUnit();
final String pattern = unit == TemporalUnit.SECOND
? "(extract(second from ?2)+extract(nanosecond from ?2)/1e9)"
: "extract(?1 from ?2)";
final SqmFunctionDescriptor sqmPattern = converter.getCreationContext().getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.patternDescriptorBuilder( pattern )
.setReturnTypeResolver( useArgType( 1 ) )
.build();
return sqmPattern.generateSqlExpression( functionName, arguments, inferableTypeAccess, converter, creationState );
}
}

View File

@ -1,85 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/**
* HANA supports a limited list of temporal fields in the
* extract() function, but we can emulate some of them by
* using the appropriate named functions instead of
* extract().
*
* Thus, the additional supported fields are
* {@link TemporalUnit#DAY_OF_YEAR},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_YEAR}.
*
* @author Gavin King
*/
public class HANAExtractEmulation implements SqmFunctionDescriptor {
private static final ArgumentsValidator ARGS_VALIDATOR = StandardArgumentsValidators.exactly( 2 );
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> arguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
ARGS_VALIDATOR.validate( arguments );
final SqmExtractUnit<?> extractUnit = (SqmExtractUnit<?>) arguments.get( 0 );
final TemporalUnit unit = extractUnit.getTemporalUnit();
final String pattern;
switch (unit) {
case DAY_OF_WEEK: {
//TODO change from monday=0
pattern = "weekday(?2)";
break;
}
case DAY:
case DAY_OF_MONTH: {
pattern = "dayofmonth(?2)";
break;
}
case DAY_OF_YEAR: {
pattern = "dayofyear(?2)";
break;
}
default: {
//I think week() returns the ISO week number
pattern = unit.toString() + "(?2)";
break;
}
}
final SqmFunctionDescriptor sqmPattern = converter.getCreationContext().getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.patternDescriptorBuilder( pattern )
.setReturnTypeResolver( useArgType( 1 ) )
.build();
return sqmPattern.generateSqlExpression( functionName, arguments, inferableTypeAccess, converter, creationState );
}
}

View File

@ -1,88 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* Informix has no extract() function, but we can
* partially emulate it by using the appropriate
* named functions, and by using to_char() with
* a format string.
*
* The supported fields are
* {@link TemporalUnit#HOUR},
* {@link TemporalUnit#MINUTE},
* {@link TemporalUnit#SECOND},
* {@link TemporalUnit#DAY},
* {@link TemporalUnit#MONTH},
* {@link TemporalUnit#YEAR},
* {@link TemporalUnit#QUARTER},
* {@link TemporalUnit#DAY_OF_MONTH},
* {@link TemporalUnit#DAY_OF_WEEK}.
*
* @author Gavin King
*/
public class InformixExtractEmulation implements SqmFunctionDescriptor {
private static final ArgumentsValidator ARGS_VALIDATOR = StandardArgumentsValidators.exactly( 2 );
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> arguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
ARGS_VALIDATOR.validate( arguments );
final SqmExtractUnit<?> extractUnit = (SqmExtractUnit<?>) arguments.get( 0 );
final TemporalUnit unit = extractUnit.getTemporalUnit();
final String pattern;
switch (unit) {
case SECOND:
pattern = "to_number(to_char(?2,'%S'))";
break;
case MINUTE:
pattern = "to_number(to_char(?2,'%M'))";
break;
case HOUR:
pattern = "to_number(to_char(?2,'%H'))";
break;
case DAY_OF_WEEK:
pattern = "(weekday(?2)+1)";
break;
case DAY_OF_MONTH:
pattern = "day(?2)";
break;
default:
//I think week() returns the ISO week number
pattern = unit.toString() + "(?2)";
break;
}
final SqmFunctionDescriptor sqmPattern = converter.getCreationContext().getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.patternDescriptorBuilder( pattern )
.build();
return sqmPattern.generateSqlExpression( functionName, arguments, inferableTypeAccess, converter, creationState );
}
}

View File

@ -0,0 +1,113 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
import static java.util.Arrays.asList;
/**
* @author Gavin King
*/
public class InsertSubstringOverlayEmulation
extends AbstractSqmFunctionDescriptor {
public InsertSubstringOverlayEmulation() {
super(
"overlay",
StandardArgumentsValidators.between( 3, 4 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
);
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
BasicType<Integer> intType = typeConfiguration.getBasicTypeForJavaType(Integer.class);
SqmTypedNode<?> string = arguments.get(0);
SqmTypedNode<?> replacement = arguments.get(1);
SqmTypedNode<?> start = arguments.get(2);
SqmTypedNode<?> length = arguments.size() > 3
? arguments.get(3)
: queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("length")
.generateSqmExpression( replacement, intType, queryEngine, typeConfiguration );
SqmFunctionDescriptor insert = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("insert");
if ( insert != null ) {
return insert.generateSqmExpression(
asList( string, start, length, replacement ),
impliedResultType,
queryEngine,
typeConfiguration
);
}
else {
SqmFunctionDescriptor substring = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("substring");
SqmFunctionDescriptor concat = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("concat");
SqmLiteral<Integer> one = new SqmLiteral<>( 1, intType, queryEngine.getCriteriaBuilder() );
SqmExpression<Integer> startPlusLength = new SqmBinaryArithmetic<>(
BinaryArithmeticOperator.ADD,
(SqmExpression<?>) start,
(SqmExpression<?>) length,
intType,
queryEngine.getCriteriaBuilder()
);
SqmExpression<Integer> startMinusOne = new SqmBinaryArithmetic<>(
BinaryArithmeticOperator.SUBTRACT,
(SqmExpression<?>) start,
one,
intType,
queryEngine.getCriteriaBuilder()
);
return concat.generateSqmExpression(
asList(
substring.generateSqmExpression(
asList( string, one, startMinusOne ),
impliedResultType,
queryEngine,
typeConfiguration
),
replacement,
substring.generateSqmExpression(
asList( string, startPlusLength ),
impliedResultType,
queryEngine,
typeConfiguration
)
),
impliedResultType,
queryEngine,
typeConfiguration
);
}
}
@Override
public String getArgumentListSignature() {
return "(string placing replacement from start[ for length])";
}
}

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqlFunctionExpression;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
/**
* @author Gavin King
*/
public class LocatePositionEmulation
extends AbstractSqmFunctionDescriptor {
public LocatePositionEmulation() {
super(
"position",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.INTEGER )
);
}
@Override
protected <T> SelfRenderingSqlFunctionExpression<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine,
TypeConfiguration typeConfiguration) {
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( "locate" )
.generateSqmExpression( arguments, impliedResultType, queryEngine, typeConfiguration );
}
@Override
public String getArgumentListSignature() {
return "(pattern in string)";
}
}

Some files were not shown because too many files have changed in this diff Show More