/
ModeFunction.java
184 lines (168 loc) · 5.28 KB
/
ModeFunction.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* Copyright 2004-2022 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.mode;
import org.h2.api.ErrorCode;
import org.h2.engine.Database;
import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.SessionLocal;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.expression.function.FunctionN;
import org.h2.message.DbException;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Base class for mode-specific functions.
*/
public abstract class ModeFunction extends FunctionN {
/**
* Constant for variable number of arguments.
*/
protected static final int VAR_ARGS = -1;
/**
* The information about this function.
*/
protected final FunctionInfo info;
/**
* Get an instance of the given function for this database.
* If no function with this name is found, null is returned.
*
* @param database the database
* @param name the upper case function name
* @return the function object or null
*/
public static ModeFunction getFunction(Database database, String name) {
ModeEnum modeEnum = database.getMode().getEnum();
if (modeEnum != ModeEnum.REGULAR) {
return getCompatibilityModeFunction(name, modeEnum);
}
return null;
}
private static ModeFunction getCompatibilityModeFunction(String name, ModeEnum modeEnum) {
switch (modeEnum) {
case LEGACY:
return FunctionsLegacy.getFunction(name);
case DB2:
case Derby:
return FunctionsDB2Derby.getFunction(name);
case MSSQLServer:
return FunctionsMSSQLServer.getFunction(name);
case MySQL:
return FunctionsMySQL.getFunction(name);
case Oracle:
return FunctionsOracle.getFunction(name);
case PostgreSQL:
return FunctionsPostgreSQL.getFunction(name);
default:
return null;
}
}
/**
* Creates a new instance of function.
*
* @param info function information
*/
ModeFunction(FunctionInfo info) {
super(new Expression[info.parameterCount != VAR_ARGS ? info.parameterCount : 4]);
this.info = info;
}
/**
* Get value transformed by expression, or null if i is out of range or
* the input value is null.
*
* @param session database session
* @param args expressions
* @param values array of input values
* @param i index of value of transform
* @return value or null
*/
static Value getNullOrValue(SessionLocal session, Expression[] args,
Value[] values, int i) {
if (i >= args.length) {
return null;
}
Value v = values[i];
if (v == null) {
Expression e = args[i];
if (e == null) {
return null;
}
v = values[i] = e.getValue(session);
}
return v;
}
/**
* Gets values of arguments and checks them for NULL values if function
* returns NULL on NULL argument.
*
* @param session
* the session
* @param args
* the arguments
* @return the values, or {@code null} if function should return NULL due to
* NULL argument
*/
final Value[] getArgumentsValues(SessionLocal session, Expression[] args) {
Value[] values = new Value[args.length];
if (info.nullIfParameterIsNull) {
for (int i = 0, l = args.length; i < l; i++) {
Value v = args[i].getValue(session);
if (v == ValueNull.INSTANCE) {
return null;
}
values[i] = v;
}
}
return values;
}
/**
* Check if the parameter count is correct.
*
* @param len the number of parameters set
* @throws DbException if the parameter count is incorrect
*/
void checkParameterCount(int len) {
throw DbException.getInternalError("type=" + info.type);
}
@Override
public void doneWithParameters() {
int count = info.parameterCount;
if (count == VAR_ARGS) {
checkParameterCount(argsCount);
super.doneWithParameters();
} else if (count != argsCount) {
throw DbException.get(ErrorCode.INVALID_PARAMETER_COUNT_2, info.name, Integer.toString(argsCount));
}
}
/**
* Optimizes arguments.
*
* @param session
* the session
* @return whether all arguments are constants and function is deterministic
*/
final boolean optimizeArguments(SessionLocal session) {
return optimizeArguments(session, info.deterministic);
}
@Override
public String getName() {
return info.name;
}
@Override
public boolean isEverything(ExpressionVisitor visitor) {
if (!super.isEverything(visitor)) {
return false;
}
switch (visitor.getType()) {
case ExpressionVisitor.DETERMINISTIC:
case ExpressionVisitor.QUERY_COMPARABLE:
case ExpressionVisitor.READONLY:
return info.deterministic;
default:
return true;
}
}
}