Line 1... |
Line 1... |
1 |
/*
|
1 |
/*
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
3 |
*
|
3 |
*
|
4 |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
|
4 |
* Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
|
5 |
*
|
5 |
*
|
6 |
* The contents of this file are subject to the terms of the GNU General Public License Version 3
|
6 |
* The contents of this file are subject to the terms of the GNU General Public License Version 3
|
7 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
|
7 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
|
8 |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
|
8 |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
|
9 |
* language governing permissions and limitations under the License.
|
9 |
* language governing permissions and limitations under the License.
|
Line 15... |
Line 15... |
15 |
|
15 |
|
16 |
import org.openconcerto.sql.model.SQLField.Properties;
|
16 |
import org.openconcerto.sql.model.SQLField.Properties;
|
17 |
import org.openconcerto.sql.model.graph.TablesMap;
|
17 |
import org.openconcerto.sql.model.graph.TablesMap;
|
18 |
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
|
18 |
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
|
19 |
import org.openconcerto.sql.utils.SQLUtils;
|
19 |
import org.openconcerto.sql.utils.SQLUtils;
|
- |
|
20 |
import org.openconcerto.utils.CollectionUtils;
|
20 |
import org.openconcerto.utils.ListMap;
|
21 |
import org.openconcerto.utils.ListMap;
|
21 |
import org.openconcerto.utils.NetUtils;
|
- |
|
22 |
import org.openconcerto.utils.Tuple2;
|
22 |
import org.openconcerto.utils.Tuple2;
|
- |
|
23 |
import org.openconcerto.utils.cc.ITransformer;
|
- |
|
24 |
import org.openconcerto.utils.cc.Transformer;
|
- |
|
25 |
import org.openconcerto.xml.XMLCodecUtils;
|
23 |
|
26 |
|
- |
|
27 |
import java.beans.DefaultPersistenceDelegate;
|
24 |
import java.io.File;
|
28 |
import java.io.File;
|
25 |
import java.math.BigDecimal;
|
29 |
import java.math.BigDecimal;
|
26 |
import java.sql.Blob;
|
30 |
import java.sql.Blob;
|
27 |
import java.sql.Clob;
|
31 |
import java.sql.Clob;
|
28 |
import java.sql.SQLException;
|
32 |
import java.sql.SQLException;
|
29 |
import java.sql.Timestamp;
|
33 |
import java.sql.Timestamp;
|
30 |
import java.util.ArrayList;
|
34 |
import java.util.ArrayList;
|
- |
|
35 |
import java.util.Arrays;
|
31 |
import java.util.IdentityHashMap;
|
36 |
import java.util.IdentityHashMap;
|
32 |
import java.util.List;
|
37 |
import java.util.List;
|
33 |
import java.util.Map;
|
38 |
import java.util.Map;
|
34 |
import java.util.Set;
|
39 |
import java.util.Set;
|
35 |
|
40 |
|
36 |
import org.h2.constant.ErrorCode;
|
41 |
import org.h2.constant.ErrorCode;
|
37 |
|
42 |
|
38 |
class SQLSyntaxH2 extends SQLSyntax {
|
43 |
public class SQLSyntaxH2 extends SQLSyntax {
|
39 |
|
44 |
|
40 |
static protected final IdentityHashMap<String, String> DATE_SPECS;
|
45 |
static protected final IdentityHashMap<String, String> DATE_SPECS;
|
41 |
|
46 |
|
42 |
static {
|
47 |
static {
|
43 |
DATE_SPECS = new IdentityHashMap<String, String>(DateProp.JAVA_DATE_SPECS_PURE);
|
48 |
DATE_SPECS = new IdentityHashMap<String, String>(DateProp.JAVA_DATE_SPECS_PURE);
|
44 |
DATE_SPECS.put(DateProp.MICROSECOND, "SSS000");
|
49 |
DATE_SPECS.put(DateProp.MICROSECOND, "SSS000");
|
- |
|
50 |
|
- |
|
51 |
XMLCodecUtils.register(SQLSyntaxH2.class, new DefaultPersistenceDelegate(new String[] {}));
|
45 |
}
|
52 |
}
|
46 |
|
53 |
|
- |
|
54 |
final static SQLSyntax create(DBSystemRoot sysRoot) {
|
- |
|
55 |
boolean standardArray = true;
|
- |
|
56 |
if (sysRoot != null) {
|
47 |
SQLSyntaxH2() {
|
57 |
try {
|
- |
|
58 |
standardArray = Arrays.equals(new String[] { "foo" }, (Object[]) sysRoot.getDataSource().executeScalar("SELECT ARRAY['foo']"));
|
- |
|
59 |
} catch (RuntimeException e) {
|
- |
|
60 |
if (SQLUtils.findWithSQLState(e).getErrorCode() == ErrorCode.COLUMN_NOT_FOUND_1)
|
- |
|
61 |
standardArray = false;
|
- |
|
62 |
else
|
- |
|
63 |
throw e;
|
- |
|
64 |
}
|
- |
|
65 |
}
|
- |
|
66 |
return new SQLSyntaxH2(standardArray);
|
- |
|
67 |
}
|
- |
|
68 |
|
- |
|
69 |
private final boolean standardArray;
|
- |
|
70 |
|
- |
|
71 |
public SQLSyntaxH2(final boolean standardArray) {
|
48 |
super(SQLSystem.H2, DATE_SPECS);
|
72 |
super(SQLSystem.H2, DATE_SPECS);
|
- |
|
73 |
this.standardArray = standardArray;
|
49 |
this.typeNames.addAll(Boolean.class, "boolean", "bool", "bit");
|
74 |
this.typeNames.addAll(Boolean.class, "boolean", "bool", "bit");
|
50 |
this.typeNames.addAll(Integer.class, "integer", "int", "int4", "mediumint");
|
75 |
this.typeNames.addAll(Integer.class, "integer", "int", "int4", "mediumint");
|
51 |
this.typeNames.addAll(Byte.class, "tinyint");
|
76 |
this.typeNames.addAll(Byte.class, "tinyint");
|
52 |
this.typeNames.addAll(Short.class, "smallint", "int2");
|
77 |
this.typeNames.addAll(Short.class, "smallint", "int2");
|
53 |
this.typeNames.addAll(Long.class, "bigint", "int8");
|
78 |
this.typeNames.addAll(Long.class, "bigint", "int8");
|
Line 187... |
Line 212... |
187 |
final String quotedSel = quoteString(SQLSyntaxPG.selectAll(t).asString());
|
212 |
final String quotedSel = quoteString(SQLSyntaxPG.selectAll(t).asString());
|
188 |
t.getBase().getDataSource().execute("CALL CSVWRITE(" + quotedPath + ", " + quotedSel + ", 'UTF8', ',', '\"', '\\', '\\N', '\n');");
|
213 |
t.getBase().getDataSource().execute("CALL CSVWRITE(" + quotedPath + ", " + quotedSel + ", 'UTF8', ',', '\"', '\\', '\\N', '\n');");
|
189 |
}
|
214 |
}
|
190 |
|
215 |
|
191 |
@Override
|
216 |
@Override
|
192 |
protected boolean isServerLocalhost(SQLServer s) {
|
- |
|
193 |
return s.getName().startsWith("mem") || s.getName().startsWith("file") || NetUtils.isSelfAddr(getAddr(s));
|
- |
|
194 |
}
|
- |
|
195 |
|
- |
|
196 |
private String getAddr(SQLServer s) {
|
- |
|
197 |
if (s.getName().startsWith("tcp") || s.getName().startsWith("ssl")) {
|
- |
|
198 |
final int startIndex = "tcp://".length();
|
- |
|
199 |
final int endIndex = s.getName().indexOf('/', startIndex);
|
- |
|
200 |
return s.getName().substring(startIndex, endIndex < 0 ? s.getName().length() : endIndex);
|
- |
|
201 |
} else
|
- |
|
202 |
return null;
|
- |
|
203 |
}
|
- |
|
204 |
|
- |
|
205 |
@Override
|
- |
|
206 |
public String getCreateSynonym(SQLTable t, SQLName newName) {
|
217 |
public String getCreateSynonym(SQLTable t, SQLName newName) {
|
207 |
return null;
|
218 |
return null;
|
208 |
}
|
219 |
}
|
209 |
|
220 |
|
210 |
@Override
|
221 |
@Override
|
Line 322... |
Line 333... |
322 |
// in MVCC, if two transactions modify the same row the second one will repeatedly throw
|
333 |
// in MVCC, if two transactions modify the same row the second one will repeatedly throw
|
323 |
// CONCURRENT_UPDATE_1 until LockTimeout
|
334 |
// CONCURRENT_UPDATE_1 until LockTimeout
|
324 |
// otherwise, the second one will timeout while waiting for the table lock
|
335 |
// otherwise, the second one will timeout while waiting for the table lock
|
325 |
return stateExn.getErrorCode() == ErrorCode.DEADLOCK_1 || stateExn.getErrorCode() == ErrorCode.LOCK_TIMEOUT_1;
|
336 |
return stateExn.getErrorCode() == ErrorCode.DEADLOCK_1 || stateExn.getErrorCode() == ErrorCode.LOCK_TIMEOUT_1;
|
326 |
}
|
337 |
}
|
- |
|
338 |
|
- |
|
339 |
@Override
|
- |
|
340 |
public boolean isTableNotFoundException(Exception exn) {
|
- |
|
341 |
final SQLException stateExn = SQLUtils.findWithSQLState(exn);
|
- |
|
342 |
return stateExn.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || stateExn.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1;
|
- |
|
343 |
}
|
- |
|
344 |
|
- |
|
345 |
@Override
|
- |
|
346 |
public String getSessionIDExpression() {
|
- |
|
347 |
return "SESSION_ID()";
|
- |
|
348 |
}
|
- |
|
349 |
|
- |
|
350 |
@Override
|
- |
|
351 |
public String getSessionsQuery(final DBSystemRoot sysRoot, final boolean includeSelf) {
|
- |
|
352 |
final String allRows = "SELECT \"ID\", \"STATEMENT\" as \"QUERY\", \"USER_NAME\" FROM INFORMATION_SCHEMA.SESSIONS";
|
- |
|
353 |
if (includeSelf)
|
- |
|
354 |
return allRows;
|
- |
|
355 |
return allRows + " WHERE \"ID\" != " + this.getSessionIDExpression();
|
- |
|
356 |
}
|
- |
|
357 |
|
- |
|
358 |
@Override
|
- |
|
359 |
public String getVersionFunction() {
|
- |
|
360 |
return "H2VERSION()";
|
- |
|
361 |
}
|
- |
|
362 |
|
- |
|
363 |
@Override
|
- |
|
364 |
public String getAllowConnectionsQuery(String sysRootName, final boolean allow) {
|
- |
|
365 |
return "SET EXCLUSIVE " + (allow ? "0" : "1");
|
- |
|
366 |
}
|
- |
|
367 |
|
- |
|
368 |
@Override
|
- |
|
369 |
public boolean isConnectionDisallowedException(SQLException exn) {
|
- |
|
370 |
return exn.getErrorCode() == ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE;
|
- |
|
371 |
}
|
- |
|
372 |
|
- |
|
373 |
@Override
|
- |
|
374 |
public String getSQLArray(final List<String> sqlExpressions, final String type) {
|
- |
|
375 |
// H2 cannot specify type in SQL, so cast each item
|
- |
|
376 |
final ITransformer<? super String, ?> tf = type == null ? Transformer.nopTransformer() : (s) -> {
|
- |
|
377 |
return this.cast(s, type);
|
- |
|
378 |
};
|
- |
|
379 |
final String items = CollectionUtils.join(sqlExpressions, ", ", tf);
|
- |
|
380 |
if (this.standardArray) {
|
- |
|
381 |
return "ARRAY[" + items + ']';
|
- |
|
382 |
} else {
|
- |
|
383 |
// For the comma, see http://h2database.com/html/grammar.html#array
|
- |
|
384 |
return '(' + items + (sqlExpressions.size() == 1 ? ",)" : ")");
|
- |
|
385 |
}
|
- |
|
386 |
}
|
- |
|
387 |
|
- |
|
388 |
@Override
|
- |
|
389 |
public String getSQLArrayContains(String arrayExpression, String itemExpression) {
|
- |
|
390 |
return "ARRAY_CONTAINS(" + arrayExpression + ", " + itemExpression + ")";
|
- |
|
391 |
}
|
- |
|
392 |
|
- |
|
393 |
@Override
|
- |
|
394 |
public String getSQLArrayLength(final String arrayExpression) {
|
- |
|
395 |
return "ARRAY_LENGTH(" + arrayExpression + ")";
|
- |
|
396 |
}
|
- |
|
397 |
|
- |
|
398 |
@Override
|
- |
|
399 |
public String getSQLArrayConcat(final String arrayExpression, final String array2Expression) {
|
- |
|
400 |
return "array_cat(" + arrayExpression + ", " + array2Expression + ")";
|
- |
|
401 |
}
|
- |
|
402 |
|
- |
|
403 |
@Override
|
- |
|
404 |
public String getSQLArrayAppend(final String arrayExpression, final String itemExpression) {
|
- |
|
405 |
return "array_append(" + arrayExpression + ", " + itemExpression + ")";
|
- |
|
406 |
}
|
- |
|
407 |
|
- |
|
408 |
@Override
|
- |
|
409 |
public String getSQLArraySlice(final String arrayExpression, final String index1Expression, final String index2Expression) {
|
- |
|
410 |
return "ARRAY_SLICE(" + arrayExpression + ", " + index1Expression + ", " + index2Expression + ")";
|
- |
|
411 |
}
|
327 |
}
|
412 |
}
|