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:
parent
89ebcfbc32
commit
9565d499af
|
@ -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
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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é 2007.1 dialect.
|
||||
*
|
||||
* This class is required in order to use Hibernate with InterSystems Caché SQL. Compatible with
|
||||
* This class is required in order to use Hibernate with Intersystems Caché SQL. Compatible with
|
||||
* Caché 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é 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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é 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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'";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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] );
|
||||
}
|
||||
}
|
|
@ -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 ", ";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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)";
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 "";
|
||||
}
|
||||
|
||||
}
|
|
@ -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)";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[, ...]])";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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])";
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue