blob: e3fd7937a0155a187ab130efc67ba10bf03097f6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.jdbc.sql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Locale;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.Table;
/**
* Dictionary for Empress using ODBC server combined with their
* type 2 driver. This dictionary may issues with other
* driver/topology configurations.
* Empress does not allow multiple connections to read rows
* read in a transaction, effectively forcing pessimistic transactions
* regardless of the Optimistic setting. To allow users to use
* optimistic transactions in a multi-connection evironment, you
* must set the AllowConcurrentRead setting to true in addition
* to standard options.
* Empress has the following additional limitations:
* <ul>
* <li>Foreign keys are quite limited in Empress and it is recommended
* that these be created by hand.</li>
* <li>Batching can be unreliable. Using BatchLimit=0 is strongly
* recommended.</li>
* <li>Using AllowConcurrentRead should be accompanied by
* SimulateLocking=true</li>
* <li>Connections should be rolled back on return to ensure locks
* are released (see OpenJPA default DataSource documentation.</li>
* <li>Certain outer joins requiring parameters in a subselect is not
* supported by Empress and may under certain configurations cause
* size () calls on query results and LRS fields to throw an exception.</li>
* <li>Certain aggregate functions are not supported.</li>
* </ul>
*/
public class EmpressDictionary
extends DBDictionary {
/**
* This setting inserts "BYPASS" after every "SELECT". This
* allows for multiple transactional reads of the same row
* from different connections at the expense of loss of
* pessimistic locking. Defaults to false.
*/
public boolean allowConcurrentRead = false;
public EmpressDictionary() {
platform = "Empress";
validationSQL = "SELECT DISTINCT today FROM sys_tables";
joinSyntax = SYNTAX_TRADITIONAL;
toUpperCaseFunction = "TOUPPER({0})";
toLowerCaseFunction = "TOLOWER({0})";
supportsDeferredConstraints = false;
requiresAliasForSubselect = true;
maxTableNameLength = 28;
maxColumnNameLength = 28;
maxIndexNameLength = 28;
maxConstraintNameLength = 28;
schemaCase = SCHEMA_CASE_PRESERVE;
useGetBytesForBlobs = true;
useSetBytesForBlobs = true;
useGetStringForClobs = true;
useSetStringForClobs = true;
clobTypeName = "TEXT";
blobTypeName = "BULK";
realTypeName = "FLOAT(8)";
bigintTypeName = "DECIMAL(38)";
timestampTypeName = "DATE";
varcharTypeName = "CHARACTER";
tinyintTypeName = "DOUBLE PRECISION";
doubleTypeName = "SMALLINT";
bitTypeName = "SMALLINT";
fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
"TEXT", "BULK", "LONGFLOAT", "INTEGER64", "SHORTINTEGER",
"LONGINTEGER",
}));
}
@Override
public boolean isSystemIndex(String name, Table table) {
return name.toUpperCase(Locale.ENGLISH).startsWith("SYS_");
}
@Override
public SQLBuffer toSelect(SQLBuffer selects, JDBCFetchConfiguration fetch,
SQLBuffer from, SQLBuffer where, SQLBuffer group,
SQLBuffer having, SQLBuffer order,
boolean distinct, boolean forUpdate, long startIdx, long endIdx) {
if (!allowConcurrentRead)
return super.toSelect(selects, fetch, from, where, group,
having, order, distinct, forUpdate, startIdx, endIdx);
// override to allow a "BYPASS" to be inserted post-"select"
// depending on allowConcurrentRead setting
SQLBuffer buf = new SQLBuffer(this);
buf.append("SELECT BYPASS ");
if (distinct)
buf.append("DISTINCT ");
buf.append(selects).append(" FROM ").append(from);
if (where != null && !where.isEmpty())
buf.append(" WHERE ").append(where);
if (group != null && !group.isEmpty())
buf.append(" GROUP BY ").append(group);
if (having != null && !having.isEmpty())
buf.append(" HAVING ").append(having);
if (order != null && !order.isEmpty())
buf.append(" ORDER BY ").append(order);
return buf;
}
@Override
public String[] getDropColumnSQL(Column column) {
// empress wants dropped columns in the form: ALTER TABLE foo
// DELETE columnToDrop
return new String[]{ "ALTER TABLE "
+ getFullName(column.getTable(), false) + " DELETE " +
getColumnDBName(column) };
}
@Override
public void setFloat(PreparedStatement stmnt, int idx, float val,
Column col)
throws SQLException {
// empress seems to allow INFINITY to be stored, but not retrieved,
// which can prove to be difficult to handle
if (val == Float.POSITIVE_INFINITY) {
val = Float.MAX_VALUE;
storageWarning(Float.POSITIVE_INFINITY,
val);
} else if (val == Float.NEGATIVE_INFINITY) {
val = Float.MIN_VALUE + 1;
storageWarning(Float.NEGATIVE_INFINITY,
val);
}
super.setFloat(stmnt, idx, val, col);
}
@Override
public void setDouble(PreparedStatement stmnt, int idx, double val,
Column col)
throws SQLException {
// empress seems to allow INFINITY to be stored, but not retrieved,
// which can prove to be difficult to handle
if (val == Double.POSITIVE_INFINITY) {
val = Double.MAX_VALUE;
storageWarning(Double.POSITIVE_INFINITY,
val);
} else if (val == Double.NEGATIVE_INFINITY) {
val = Double.MIN_VALUE + 1;
storageWarning(Double.NEGATIVE_INFINITY,
val);
}
super.setDouble(stmnt, idx, val, col);
}
}