You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2015/05/11 06:42:38 UTC
[3/8] cayenne git commit: CAY-2007 Refactoring SelectTranslator for
better extensibility
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
index 1a37f36..57456f5 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
@@ -36,6 +36,7 @@ import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslatorFactory;
import org.apache.cayenne.access.translator.select.QualifierTranslator;
import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.access.types.ByteArrayType;
import org.apache.cayenne.access.types.CharType;
import org.apache.cayenne.access.types.ExtendedType;
@@ -52,9 +53,11 @@ import org.apache.cayenne.di.Inject;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.merge.MergerFactory;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.resource.ResourceLocator;
/**
@@ -64,9 +67,8 @@ import org.apache.cayenne.resource.ResourceLocator;
* <p>
* Foreign key constraints are supported by InnoDB engine and NOT supported by
* MyISAM engine. This adapter by default assumes MyISAM, so
- * <code>supportsFkConstraints</code> will
- * be false. Users can manually change this by calling
- * <em>setSupportsFkConstraints(true)</em> or better by using an
+ * <code>supportsFkConstraints</code> will be false. Users can manually change
+ * this by calling <em>setSupportsFkConstraints(true)</em> or better by using an
* {@link org.apache.cayenne.dba.AutoAdapter}, i.e. not entering the adapter
* name at all for the DataNode, letting Cayenne guess it in runtime. In the
* later case Cayenne will check the <em>table_type</em> MySQL variable to
@@ -80,330 +82,341 @@ import org.apache.cayenne.resource.ResourceLocator;
*/
public class MySQLAdapter extends JdbcAdapter {
- static final String DEFAULT_STORAGE_ENGINE = "InnoDB";
- static final String MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_START = "`";
- static final String MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_END = "`";
-
- protected String storageEngine;
- protected boolean supportsFkConstraints;
-
- public MySQLAdapter(@Inject RuntimeProperties runtimeProperties,
- @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
- @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
- @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
- @Inject ResourceLocator resourceLocator) {
- super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
-
- // init defaults
- this.storageEngine = DEFAULT_STORAGE_ENGINE;
-
- setSupportsBatchUpdates(true);
- setSupportsFkConstraints(true);
- setSupportsUniqueConstraints(true);
- setSupportsGeneratedKeys(true);
- }
-
- void setSupportsFkConstraints(boolean flag) {
- this.supportsFkConstraints = flag;
- }
-
- @Override
- protected QuotingStrategy createQuotingStrategy() {
- return new DefaultQuotingStrategy("`", "`");
- }
-
- @Override
- public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
- QualifierTranslator translator = new MySQLQualifierTranslator(queryAssembler);
- translator.setCaseInsensitive(caseInsensitiveCollations);
- return translator;
- }
-
- /**
- * Uses special action builder to create the right action.
- *
- * @since 1.2
- */
- @Override
- public SQLAction getAction(Query query, DataNode node) {
- return query.createSQLAction(new MySQLActionBuilder(node));
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Collection<String> dropTableStatements(DbEntity table) {
- // note that CASCADE is a noop as of MySQL 5.0, so we have to use FK
- // checks
- // statement
- StringBuilder buf = new StringBuilder();
- QuotingStrategy context = getQuotingStrategy();
- buf.append(context.quotedFullyQualifiedName(table));
-
- return Arrays.asList("SET FOREIGN_KEY_CHECKS=0", "DROP TABLE IF EXISTS " + buf.toString() + " CASCADE",
- "SET FOREIGN_KEY_CHECKS=1");
- }
-
- /**
- * Installs appropriate ExtendedTypes used as converters for passing values
- * between JDBC and Java layers.
- */
- @Override
- protected void configureExtendedTypes(ExtendedTypeMap map) {
- super.configureExtendedTypes(map);
-
- // must handle CLOBs as strings, otherwise there
- // are problems with NULL clobs that are treated
- // as empty strings... somehow this doesn't happen
- // for BLOBs (ConnectorJ v. 3.0.9)
- map.registerType(new CharType(false, false));
- map.registerType(new ByteArrayType(false, false));
- }
-
- @Override
- public DbAttribute buildAttribute(String name, String typeName, int type, int size, int precision,
- boolean allowNulls) {
-
- if (typeName != null) {
- typeName = typeName.toLowerCase();
- }
-
- // all LOB types are returned by the driver as OTHER... must remap them
- // manually
- // (at least on MySQL 3.23)
- if (type == Types.OTHER) {
- if ("longblob".equals(typeName)) {
- type = Types.BLOB;
- } else if ("mediumblob".equals(typeName)) {
- type = Types.BLOB;
- } else if ("blob".equals(typeName)) {
- type = Types.BLOB;
- } else if ("tinyblob".equals(typeName)) {
- type = Types.VARBINARY;
- } else if ("longtext".equals(typeName)) {
- type = Types.CLOB;
- } else if ("mediumtext".equals(typeName)) {
- type = Types.CLOB;
- } else if ("text".equals(typeName)) {
- type = Types.CLOB;
- } else if ("tinytext".equals(typeName)) {
- type = Types.VARCHAR;
- }
- }
- // types like "int unsigned" map to Long
- else if (typeName != null && typeName.endsWith(" unsigned")) {
- // per
- // http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-type-conversions.html
- if (typeName.equals("int unsigned") || typeName.equals("integer unsigned")
- || typeName.equals("mediumint unsigned")) {
- type = Types.BIGINT;
- }
- // BIGINT UNSIGNED maps to BigInteger according to MySQL docs, but
- // there is no
- // JDBC mapping for BigInteger
- }
-
- return super.buildAttribute(name, typeName, type, size, precision, allowNulls);
- }
-
- @Override
- public void bindParameter(PreparedStatement statement, Object object, int pos, int sqlType, int scale) throws SQLException, Exception {
- super.bindParameter(statement, object, pos, mapNTypes(sqlType), scale);
- }
-
- private int mapNTypes(int sqlType) {
- switch (sqlType) {
- case Types.NCHAR : return Types.CHAR;
- case Types.NCLOB : return Types.CLOB;
- case Types.NVARCHAR : return Types.VARCHAR;
- case Types.LONGNVARCHAR : return Types.LONGVARCHAR;
-
- default:
- return sqlType;
- }
- }
-
- /**
- * Creates and returns a primary key generator. Overrides superclass
- * implementation to return an instance of MySQLPkGenerator that does the
- * correct table locking.
- */
- @Override
- protected PkGenerator createPkGenerator() {
- return new MySQLPkGenerator(this);
- }
-
- /**
- * @since 3.0
- */
- @Override
- protected EJBQLTranslatorFactory createEJBQLTranslatorFactory() {
- JdbcEJBQLTranslatorFactory translatorFactory = new MySQLEJBQLTranslatorFactory();
- translatorFactory.setCaseInsensitive(caseInsensitiveCollations);
- return translatorFactory;
- }
-
- /**
- * Overrides super implementation to explicitly set table engine to InnoDB
- * if FK constraints are supported by this adapter.
- */
- @Override
- public String createTable(DbEntity entity) {
- String ddlSQL = super.createTable(entity);
-
- if (storageEngine != null) {
- ddlSQL += " ENGINE=" + storageEngine;
- }
-
- return ddlSQL;
- }
-
- /**
- * Customizes PK clause semantics to ensure that generated columns are in
- * the beginning of the PK definition, as this seems to be a requirement for
- * InnoDB tables.
- *
- * @since 1.2
- */
- // See CAY-358 for details of the InnoDB problem
- @Override
- protected void createTableAppendPKClause(StringBuffer sqlBuffer, DbEntity entity) {
-
- // must move generated to the front...
- List<DbAttribute> pkList = new ArrayList<DbAttribute>(entity.getPrimaryKeys());
- Collections.sort(pkList, new PKComparator());
-
- Iterator<DbAttribute> pkit = pkList.iterator();
- if (pkit.hasNext()) {
-
- sqlBuffer.append(", PRIMARY KEY (");
- boolean firstPk = true;
- while (pkit.hasNext()) {
- if (firstPk)
- firstPk = false;
- else
- sqlBuffer.append(", ");
-
- DbAttribute at = pkit.next();
- sqlBuffer.append(quotingStrategy.quotedName(at));
- }
- sqlBuffer.append(')');
- }
-
- // if FK constraints are supported, we must add indices to all FKs
- // Note that according to MySQL docs, FK indexes are created
- // automatically when
- // constraint is defined, starting at MySQL 4.1.2
- if (supportsFkConstraints) {
- for (DbRelationship r : entity.getRelationships()) {
- if (r.getJoins().size() > 0 && r.isToPK() && !r.isToDependentPK()) {
-
- sqlBuffer.append(", KEY (");
-
- Iterator<DbAttribute> columns = r.getSourceAttributes().iterator();
- DbAttribute column = columns.next();
- sqlBuffer.append(quotingStrategy.quotedName(column));
-
- while (columns.hasNext()) {
- column = columns.next();
- sqlBuffer.append(", ").append(quotingStrategy.quotedName(column));
- }
-
- sqlBuffer.append(")");
- }
- }
- }
- }
-
- /**
- * Appends AUTO_INCREMENT clause to the column definition for generated
- * columns.
- */
- @Override
- public void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column) {
-
- String[] types = externalTypesForJdbcType(column.getType());
- if (types == null || types.length == 0) {
- String entityName = column.getEntity() != null ? ((DbEntity) column.getEntity()).getFullyQualifiedName()
- : "<null>";
- throw new CayenneRuntimeException("Undefined type for attribute '" + entityName + "." + column.getName()
- + "': " + column.getType());
- }
-
- String type = types[0];
- sqlBuffer.append(quotingStrategy.quotedName(column));
- sqlBuffer.append(' ').append(type);
-
- // append size and precision (if applicable)s
- if (typeSupportsLength(column.getType())) {
- int len = column.getMaxLength();
-
- int scale = TypesMapping.isDecimal(column.getType()) ? column.getScale() : -1;
-
- // sanity check
- if (scale > len) {
- scale = -1;
- }
-
- if (len > 0) {
- sqlBuffer.append('(').append(len);
-
- if (scale >= 0) {
- sqlBuffer.append(", ").append(scale);
- }
-
- sqlBuffer.append(')');
- }
- }
-
- sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL");
-
- if (column.isGenerated()) {
- sqlBuffer.append(" AUTO_INCREMENT");
- }
- }
-
- @Override
- public boolean typeSupportsLength(int type) {
- // As of MySQL 5.6.4 the "TIMESTAMP" and "TIME" types support length, which is the number of decimal places for fractional seconds
- // http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
- switch (type) {
- case Types.TIMESTAMP:
- case Types.TIME:
- return true;
- default:
- return super.typeSupportsLength(type);
- }
- }
-
- @Override
- public MergerFactory mergerFactory() {
- return new MySQLMergerFactory();
- }
-
- final class PKComparator implements Comparator<DbAttribute> {
-
- public int compare(DbAttribute a1, DbAttribute a2) {
- if (a1.isGenerated() != a2.isGenerated()) {
- return a1.isGenerated() ? -1 : 1;
- } else {
- return a1.getName().compareTo(a2.getName());
- }
- }
- }
-
- /**
- * @since 3.0
- */
- public String getStorageEngine() {
- return storageEngine;
- }
-
- /**
- * @since 3.0
- */
- public void setStorageEngine(String engine) {
- this.storageEngine = engine;
- }
+ static final String DEFAULT_STORAGE_ENGINE = "InnoDB";
+ static final String MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_START = "`";
+ static final String MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_END = "`";
+
+ protected String storageEngine;
+ protected boolean supportsFkConstraints;
+
+ public MySQLAdapter(@Inject RuntimeProperties runtimeProperties,
+ @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
+ @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
+ @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
+ @Inject ResourceLocator resourceLocator) {
+ super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
+
+ // init defaults
+ this.storageEngine = DEFAULT_STORAGE_ENGINE;
+
+ setSupportsBatchUpdates(true);
+ setSupportsFkConstraints(true);
+ setSupportsUniqueConstraints(true);
+ setSupportsGeneratedKeys(true);
+ }
+
+ void setSupportsFkConstraints(boolean flag) {
+ this.supportsFkConstraints = flag;
+ }
+
+ @Override
+ protected QuotingStrategy createQuotingStrategy() {
+ return new DefaultQuotingStrategy("`", "`");
+ }
+
+ @Override
+ public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) {
+ return new MySQLSelectTranslator(query, this, entityResolver);
+ }
+
+ @Override
+ public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
+ QualifierTranslator translator = new MySQLQualifierTranslator(queryAssembler);
+ translator.setCaseInsensitive(caseInsensitiveCollations);
+ return translator;
+ }
+
+ /**
+ * Uses special action builder to create the right action.
+ *
+ * @since 1.2
+ */
+ @Override
+ public SQLAction getAction(Query query, DataNode node) {
+ return query.createSQLAction(new MySQLActionBuilder(node));
+ }
+
+ /**
+ * @since 3.0
+ */
+ @Override
+ public Collection<String> dropTableStatements(DbEntity table) {
+ // note that CASCADE is a noop as of MySQL 5.0, so we have to use FK
+ // checks
+ // statement
+ StringBuilder buf = new StringBuilder();
+ QuotingStrategy context = getQuotingStrategy();
+ buf.append(context.quotedFullyQualifiedName(table));
+
+ return Arrays.asList("SET FOREIGN_KEY_CHECKS=0", "DROP TABLE IF EXISTS " + buf.toString() + " CASCADE",
+ "SET FOREIGN_KEY_CHECKS=1");
+ }
+
+ /**
+ * Installs appropriate ExtendedTypes used as converters for passing values
+ * between JDBC and Java layers.
+ */
+ @Override
+ protected void configureExtendedTypes(ExtendedTypeMap map) {
+ super.configureExtendedTypes(map);
+
+ // must handle CLOBs as strings, otherwise there
+ // are problems with NULL clobs that are treated
+ // as empty strings... somehow this doesn't happen
+ // for BLOBs (ConnectorJ v. 3.0.9)
+ map.registerType(new CharType(false, false));
+ map.registerType(new ByteArrayType(false, false));
+ }
+
+ @Override
+ public DbAttribute buildAttribute(String name, String typeName, int type, int size, int precision,
+ boolean allowNulls) {
+
+ if (typeName != null) {
+ typeName = typeName.toLowerCase();
+ }
+
+ // all LOB types are returned by the driver as OTHER... must remap them
+ // manually
+ // (at least on MySQL 3.23)
+ if (type == Types.OTHER) {
+ if ("longblob".equals(typeName)) {
+ type = Types.BLOB;
+ } else if ("mediumblob".equals(typeName)) {
+ type = Types.BLOB;
+ } else if ("blob".equals(typeName)) {
+ type = Types.BLOB;
+ } else if ("tinyblob".equals(typeName)) {
+ type = Types.VARBINARY;
+ } else if ("longtext".equals(typeName)) {
+ type = Types.CLOB;
+ } else if ("mediumtext".equals(typeName)) {
+ type = Types.CLOB;
+ } else if ("text".equals(typeName)) {
+ type = Types.CLOB;
+ } else if ("tinytext".equals(typeName)) {
+ type = Types.VARCHAR;
+ }
+ }
+ // types like "int unsigned" map to Long
+ else if (typeName != null && typeName.endsWith(" unsigned")) {
+ // per
+ // http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-type-conversions.html
+ if (typeName.equals("int unsigned") || typeName.equals("integer unsigned")
+ || typeName.equals("mediumint unsigned")) {
+ type = Types.BIGINT;
+ }
+ // BIGINT UNSIGNED maps to BigInteger according to MySQL docs, but
+ // there is no
+ // JDBC mapping for BigInteger
+ }
+
+ return super.buildAttribute(name, typeName, type, size, precision, allowNulls);
+ }
+
+ @Override
+ public void bindParameter(PreparedStatement statement, Object object, int pos, int sqlType, int scale)
+ throws SQLException, Exception {
+ super.bindParameter(statement, object, pos, mapNTypes(sqlType), scale);
+ }
+
+ private int mapNTypes(int sqlType) {
+ switch (sqlType) {
+ case Types.NCHAR:
+ return Types.CHAR;
+ case Types.NCLOB:
+ return Types.CLOB;
+ case Types.NVARCHAR:
+ return Types.VARCHAR;
+ case Types.LONGNVARCHAR:
+ return Types.LONGVARCHAR;
+
+ default:
+ return sqlType;
+ }
+ }
+
+ /**
+ * Creates and returns a primary key generator. Overrides superclass
+ * implementation to return an instance of MySQLPkGenerator that does the
+ * correct table locking.
+ */
+ @Override
+ protected PkGenerator createPkGenerator() {
+ return new MySQLPkGenerator(this);
+ }
+
+ /**
+ * @since 3.0
+ */
+ @Override
+ protected EJBQLTranslatorFactory createEJBQLTranslatorFactory() {
+ JdbcEJBQLTranslatorFactory translatorFactory = new MySQLEJBQLTranslatorFactory();
+ translatorFactory.setCaseInsensitive(caseInsensitiveCollations);
+ return translatorFactory;
+ }
+
+ /**
+ * Overrides super implementation to explicitly set table engine to InnoDB
+ * if FK constraints are supported by this adapter.
+ */
+ @Override
+ public String createTable(DbEntity entity) {
+ String ddlSQL = super.createTable(entity);
+
+ if (storageEngine != null) {
+ ddlSQL += " ENGINE=" + storageEngine;
+ }
+
+ return ddlSQL;
+ }
+
+ /**
+ * Customizes PK clause semantics to ensure that generated columns are in
+ * the beginning of the PK definition, as this seems to be a requirement for
+ * InnoDB tables.
+ *
+ * @since 1.2
+ */
+ // See CAY-358 for details of the InnoDB problem
+ @Override
+ protected void createTableAppendPKClause(StringBuffer sqlBuffer, DbEntity entity) {
+
+ // must move generated to the front...
+ List<DbAttribute> pkList = new ArrayList<DbAttribute>(entity.getPrimaryKeys());
+ Collections.sort(pkList, new PKComparator());
+
+ Iterator<DbAttribute> pkit = pkList.iterator();
+ if (pkit.hasNext()) {
+
+ sqlBuffer.append(", PRIMARY KEY (");
+ boolean firstPk = true;
+ while (pkit.hasNext()) {
+ if (firstPk)
+ firstPk = false;
+ else
+ sqlBuffer.append(", ");
+
+ DbAttribute at = pkit.next();
+ sqlBuffer.append(quotingStrategy.quotedName(at));
+ }
+ sqlBuffer.append(')');
+ }
+
+ // if FK constraints are supported, we must add indices to all FKs
+ // Note that according to MySQL docs, FK indexes are created
+ // automatically when
+ // constraint is defined, starting at MySQL 4.1.2
+ if (supportsFkConstraints) {
+ for (DbRelationship r : entity.getRelationships()) {
+ if (r.getJoins().size() > 0 && r.isToPK() && !r.isToDependentPK()) {
+
+ sqlBuffer.append(", KEY (");
+
+ Iterator<DbAttribute> columns = r.getSourceAttributes().iterator();
+ DbAttribute column = columns.next();
+ sqlBuffer.append(quotingStrategy.quotedName(column));
+
+ while (columns.hasNext()) {
+ column = columns.next();
+ sqlBuffer.append(", ").append(quotingStrategy.quotedName(column));
+ }
+
+ sqlBuffer.append(")");
+ }
+ }
+ }
+ }
+
+ /**
+ * Appends AUTO_INCREMENT clause to the column definition for generated
+ * columns.
+ */
+ @Override
+ public void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column) {
+
+ String[] types = externalTypesForJdbcType(column.getType());
+ if (types == null || types.length == 0) {
+ String entityName = column.getEntity() != null ? ((DbEntity) column.getEntity()).getFullyQualifiedName()
+ : "<null>";
+ throw new CayenneRuntimeException("Undefined type for attribute '" + entityName + "." + column.getName()
+ + "': " + column.getType());
+ }
+
+ String type = types[0];
+ sqlBuffer.append(quotingStrategy.quotedName(column));
+ sqlBuffer.append(' ').append(type);
+
+ // append size and precision (if applicable)s
+ if (typeSupportsLength(column.getType())) {
+ int len = column.getMaxLength();
+
+ int scale = TypesMapping.isDecimal(column.getType()) ? column.getScale() : -1;
+
+ // sanity check
+ if (scale > len) {
+ scale = -1;
+ }
+
+ if (len > 0) {
+ sqlBuffer.append('(').append(len);
+
+ if (scale >= 0) {
+ sqlBuffer.append(", ").append(scale);
+ }
+
+ sqlBuffer.append(')');
+ }
+ }
+
+ sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL");
+
+ if (column.isGenerated()) {
+ sqlBuffer.append(" AUTO_INCREMENT");
+ }
+ }
+
+ @Override
+ public boolean typeSupportsLength(int type) {
+ // As of MySQL 5.6.4 the "TIMESTAMP" and "TIME" types support length,
+ // which is the number of decimal places for fractional seconds
+ // http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
+ switch (type) {
+ case Types.TIMESTAMP:
+ case Types.TIME:
+ return true;
+ default:
+ return super.typeSupportsLength(type);
+ }
+ }
+
+ @Override
+ public MergerFactory mergerFactory() {
+ return new MySQLMergerFactory();
+ }
+
+ final class PKComparator implements Comparator<DbAttribute> {
+
+ public int compare(DbAttribute a1, DbAttribute a2) {
+ if (a1.isGenerated() != a2.isGenerated()) {
+ return a1.isGenerated() ? -1 : 1;
+ } else {
+ return a1.getName().compareTo(a2.getName());
+ }
+ }
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String getStorageEngine() {
+ return storageEngine;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void setStorageEngine(String engine) {
+ this.storageEngine = engine;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectAction.java
index a39bd16..0b522d3 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectAction.java
@@ -20,7 +20,6 @@ package org.apache.cayenne.dba.mysql;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.jdbc.SelectAction;
-import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.query.SelectQuery;
/**
@@ -36,9 +35,4 @@ class MySQLSelectAction extends SelectAction {
protected int getInMemoryOffset(int queryOffset) {
return 0;
}
-
- @Override
- protected SelectTranslator createTranslator() {
- return new MySQLSelectTranslator(query, dataNode.getAdapter(), dataNode.getEntityResolver());
- }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseActionBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseActionBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseActionBuilder.java
deleted file mode 100644
index fb03bde..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseActionBuilder.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*****************************************************************
- * 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.cayenne.dba.openbase;
-
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.jdbc.SelectAction;
-import org.apache.cayenne.access.translator.select.SelectTranslator;
-import org.apache.cayenne.dba.JdbcActionBuilder;
-import org.apache.cayenne.query.SQLAction;
-import org.apache.cayenne.query.SelectQuery;
-
-/**
- * @since 1.2
- */
-class OpenBaseActionBuilder extends JdbcActionBuilder {
-
- OpenBaseActionBuilder(DataNode dataNode) {
- super(dataNode);
- }
-
- @Override
- public <T> SQLAction objectSelectAction(SelectQuery<T> query) {
- return new SelectAction(query, dataNode) {
-
- @Override
- protected SelectTranslator createTranslator() {
- return new OpenBaseSelectTranslator(query, dataNode.getAdapter(), dataNode.getEntityResolver());
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java
index f7aeb82..a018aa4 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java
@@ -27,9 +27,9 @@ import java.util.Iterator;
import java.util.List;
import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.translator.select.QualifierTranslator;
import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.access.types.ByteType;
import org.apache.cayenne.access.types.CharType;
import org.apache.cayenne.access.types.ExtendedType;
@@ -45,14 +45,14 @@ import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.merge.MergerFactory;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.resource.ResourceLocator;
/**
- * DbAdapter implementation for <a href="http://www.openbase.com">OpenBase</a>. Sample
- * connection settings to use with OpenBase are shown below:
+ * DbAdapter implementation for <a href="http://www.openbase.com">OpenBase</a>.
+ * Sample connection settings to use with OpenBase are shown below:
*
* <pre>
* openbase.jdbc.username = test
@@ -65,284 +65,239 @@ import org.apache.cayenne.resource.ResourceLocator;
*/
public class OpenBaseAdapter extends JdbcAdapter {
- public OpenBaseAdapter(
- @Inject RuntimeProperties runtimeProperties,
- @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
- @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
- @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
- @Inject ResourceLocator resourceLocator) {
- super(
- runtimeProperties,
- defaultExtendedTypes,
- userExtendedTypes,
- extendedTypeFactories,
- resourceLocator);
-
- // init defaults
- this.setSupportsUniqueConstraints(false);
- }
-
- /**
- * Uses special action builder to create the right action.
- *
- * @since 1.2
- */
- @Override
- public SQLAction getAction(Query query, DataNode node) {
- return query.createSQLAction(new OpenBaseActionBuilder(node));
- }
-
- @Override
- protected void configureExtendedTypes(ExtendedTypeMap map) {
- super.configureExtendedTypes(map);
-
- // Byte handling doesn't work on read...
- // need special converter
- map.registerType(new OpenBaseByteType());
-
- map.registerType(new OpenBaseCharType());
- }
-
- @Override
- public DbAttribute buildAttribute(
- String name,
- String typeName,
- int type,
- int size,
- int scale,
- boolean allowNulls) {
-
- // OpenBase makes no distinction between CHAR and VARCHAR
- // so lets use VARCHAR, since it seems more generic
- if (type == Types.CHAR) {
- type = Types.VARCHAR;
- }
-
- return super.buildAttribute(name, typeName, type, size, scale, allowNulls);
- }
-
- /**
- * Returns word "go".
- */
- @Override
- public String getBatchTerminator() {
- return "go";
- }
-
- /**
- * Returns null, since views are not yet supported in openbase.
- */
- @Override
- public String tableTypeForView() {
- // TODO: according to OpenBase docs views *ARE* supported.
- return null;
- }
-
- /**
- * Returns OpenBase-specific translator for queries.
- */
- @Override
- public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
- return new OpenBaseQualifierTranslator(queryAssembler);
- }
-
- /**
- * Creates and returns a primary key generator. Overrides superclass implementation to
- * return an instance of OpenBasePkGenerator that uses built-in multi-server primary
- * key generation.
- */
- @Override
- protected PkGenerator createPkGenerator() {
- return new OpenBasePkGenerator(this);
- }
-
- /**
- * Returns a SQL string that can be used to create database table corresponding to
- * <code>ent</code> parameter.
- */
- @Override
- public String createTable(DbEntity ent) {
-
- StringBuilder buf = new StringBuilder();
-
- buf.append("CREATE TABLE ");
- buf.append(quotingStrategy.quotedFullyQualifiedName(ent));
- buf.append(" (");
-
- // columns
- Iterator<DbAttribute> it = ent.getAttributes().iterator();
- boolean first = true;
- while (it.hasNext()) {
- if (first) {
- first = false;
- }
- else {
- buf.append(", ");
- }
-
- DbAttribute at = it.next();
-
- // attribute may not be fully valid, do a simple check
- if (at.getType() == TypesMapping.NOT_DEFINED) {
- throw new CayenneRuntimeException("Undefined type for attribute '"
- + ent.getFullyQualifiedName()
- + "."
- + at.getName()
- + "'.");
- }
-
- String[] types = externalTypesForJdbcType(at.getType());
- if (types == null || types.length == 0) {
- throw new CayenneRuntimeException("Undefined type for attribute '"
- + ent.getFullyQualifiedName()
- + "."
- + at.getName()
- + "': "
- + at.getType());
- }
-
- String type = types[0];
- buf.append(quotingStrategy.quotedName(at)).append(' ').append(type);
-
- // append size and precision (if applicable)
- if (typeSupportsLength(at.getType())) {
- int len = at.getMaxLength();
- int scale = TypesMapping.isDecimal(at.getType()) ? at.getScale() : -1;
-
- // sanity check
- if (scale > len) {
- scale = -1;
- }
-
- if (len > 0) {
- buf.append('(').append(len);
-
- if (scale >= 0) {
- buf.append(", ").append(scale);
- }
-
- buf.append(')');
- }
- }
-
- if (at.isMandatory()) {
- buf.append(" NOT NULL");
- }
- else {
- buf.append(" NULL");
- }
- }
-
- buf.append(')');
- return buf.toString();
- }
-
- /**
- * Returns a SQL string that can be used to create a foreign key constraint for the
- * relationship.
- */
- @Override
- public String createFkConstraint(DbRelationship rel) {
- StringBuilder buf = new StringBuilder();
-
- // OpendBase Specifics is that we need to create a constraint going
- // from destination to source for this to work...
-
- DbEntity sourceEntity = (DbEntity) rel.getSourceEntity();
- DbEntity targetEntity = (DbEntity) rel.getTargetEntity();
- String toMany = (!rel.isToMany()) ? "'1'" : "'0'";
-
- // TODO: doesn't seem like OpenBase supports compound joins...
- // need to doublecheck that
-
- int joinsLen = rel.getJoins().size();
- if (joinsLen == 0) {
- throw new CayenneRuntimeException("Relationship has no joins: "
- + rel.getName());
- }
- else if (joinsLen > 1) {
- // ignore extra joins
- }
-
- DbJoin join = rel.getJoins().get(0);
-
- buf
- .append("INSERT INTO _SYS_RELATIONSHIP (")
- .append("dest_table, dest_column, source_table, source_column, ")
- .append(
- "block_delete, cascade_delete, one_to_many, operator, relationshipName")
- .append(") VALUES ('")
- .append(sourceEntity.getFullyQualifiedName())
- .append("', '")
- .append(join.getSourceName())
- .append("', '")
- .append(targetEntity.getFullyQualifiedName())
- .append("', '")
- .append(join.getTargetName())
- .append("', 0, 0, ")
- .append(toMany)
- .append(", '=', '")
- .append(rel.getName())
- .append("')");
-
- return buf.toString();
- }
-
- // OpenBase JDBC driver has trouble reading "integer" as byte
- // this converter addresses such problem
- static class OpenBaseByteType extends ByteType {
-
- OpenBaseByteType() {
- super(true);
- }
-
- @Override
- public Object materializeObject(ResultSet rs, int index, int type)
- throws Exception {
-
- // read value as int, and then narrow it down
- int val = rs.getInt(index);
- return (rs.wasNull()) ? null : Byte.valueOf((byte) val);
- }
-
- @Override
- public Object materializeObject(CallableStatement rs, int index, int type)
- throws Exception {
-
- // read value as int, and then narrow it down
- int val = rs.getInt(index);
- return (rs.wasNull()) ? null : Byte.valueOf((byte) val);
- }
- }
-
- static class OpenBaseCharType extends CharType {
-
- OpenBaseCharType() {
- super(false, true);
- }
-
- @Override
- public void setJdbcObject(
- PreparedStatement st,
- Object val,
- int pos,
- int type,
- int precision) throws Exception {
-
- // These to types map to "text"; and when setting "text" as object
- // OB assumes that the object is the actual CLOB... weird
- if (type == Types.CLOB || type == Types.LONGVARCHAR) {
- st.setString(pos, (String) val);
- }
- else {
- super.setJdbcObject(st, val, pos, type, precision);
- }
- }
- }
-
- @Override
- public MergerFactory mergerFactory() {
- return new OpenBaseMergerFactory();
- }
+ public OpenBaseAdapter(@Inject RuntimeProperties runtimeProperties,
+ @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
+ @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
+ @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
+ @Inject ResourceLocator resourceLocator) {
+ super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
+
+ // init defaults
+ this.setSupportsUniqueConstraints(false);
+ }
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) {
+ return new OpenBaseSelectTranslator(query, this, entityResolver);
+ }
+
+ @Override
+ protected void configureExtendedTypes(ExtendedTypeMap map) {
+ super.configureExtendedTypes(map);
+
+ // Byte handling doesn't work on read...
+ // need special converter
+ map.registerType(new OpenBaseByteType());
+
+ map.registerType(new OpenBaseCharType());
+ }
+
+ @Override
+ public DbAttribute buildAttribute(String name, String typeName, int type, int size, int scale, boolean allowNulls) {
+
+ // OpenBase makes no distinction between CHAR and VARCHAR
+ // so lets use VARCHAR, since it seems more generic
+ if (type == Types.CHAR) {
+ type = Types.VARCHAR;
+ }
+
+ return super.buildAttribute(name, typeName, type, size, scale, allowNulls);
+ }
+
+ /**
+ * Returns word "go".
+ */
+ @Override
+ public String getBatchTerminator() {
+ return "go";
+ }
+
+ /**
+ * Returns null, since views are not yet supported in openbase.
+ */
+ @Override
+ public String tableTypeForView() {
+ // TODO: according to OpenBase docs views *ARE* supported.
+ return null;
+ }
+
+ /**
+ * Returns OpenBase-specific translator for queries.
+ */
+ @Override
+ public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
+ return new OpenBaseQualifierTranslator(queryAssembler);
+ }
+
+ /**
+ * Creates and returns a primary key generator. Overrides superclass
+ * implementation to return an instance of OpenBasePkGenerator that uses
+ * built-in multi-server primary key generation.
+ */
+ @Override
+ protected PkGenerator createPkGenerator() {
+ return new OpenBasePkGenerator(this);
+ }
+
+ /**
+ * Returns a SQL string that can be used to create database table
+ * corresponding to <code>ent</code> parameter.
+ */
+ @Override
+ public String createTable(DbEntity ent) {
+
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("CREATE TABLE ");
+ buf.append(quotingStrategy.quotedFullyQualifiedName(ent));
+ buf.append(" (");
+
+ // columns
+ Iterator<DbAttribute> it = ent.getAttributes().iterator();
+ boolean first = true;
+ while (it.hasNext()) {
+ if (first) {
+ first = false;
+ } else {
+ buf.append(", ");
+ }
+
+ DbAttribute at = it.next();
+
+ // attribute may not be fully valid, do a simple check
+ if (at.getType() == TypesMapping.NOT_DEFINED) {
+ throw new CayenneRuntimeException("Undefined type for attribute '" + ent.getFullyQualifiedName() + "."
+ + at.getName() + "'.");
+ }
+
+ String[] types = externalTypesForJdbcType(at.getType());
+ if (types == null || types.length == 0) {
+ throw new CayenneRuntimeException("Undefined type for attribute '" + ent.getFullyQualifiedName() + "."
+ + at.getName() + "': " + at.getType());
+ }
+
+ String type = types[0];
+ buf.append(quotingStrategy.quotedName(at)).append(' ').append(type);
+
+ // append size and precision (if applicable)
+ if (typeSupportsLength(at.getType())) {
+ int len = at.getMaxLength();
+ int scale = TypesMapping.isDecimal(at.getType()) ? at.getScale() : -1;
+
+ // sanity check
+ if (scale > len) {
+ scale = -1;
+ }
+
+ if (len > 0) {
+ buf.append('(').append(len);
+
+ if (scale >= 0) {
+ buf.append(", ").append(scale);
+ }
+
+ buf.append(')');
+ }
+ }
+
+ if (at.isMandatory()) {
+ buf.append(" NOT NULL");
+ } else {
+ buf.append(" NULL");
+ }
+ }
+
+ buf.append(')');
+ return buf.toString();
+ }
+
+ /**
+ * Returns a SQL string that can be used to create a foreign key constraint
+ * for the relationship.
+ */
+ @Override
+ public String createFkConstraint(DbRelationship rel) {
+ StringBuilder buf = new StringBuilder();
+
+ // OpendBase Specifics is that we need to create a constraint going
+ // from destination to source for this to work...
+
+ DbEntity sourceEntity = (DbEntity) rel.getSourceEntity();
+ DbEntity targetEntity = (DbEntity) rel.getTargetEntity();
+ String toMany = (!rel.isToMany()) ? "'1'" : "'0'";
+
+ // TODO: doesn't seem like OpenBase supports compound joins...
+ // need to doublecheck that
+
+ int joinsLen = rel.getJoins().size();
+ if (joinsLen == 0) {
+ throw new CayenneRuntimeException("Relationship has no joins: " + rel.getName());
+ } else if (joinsLen > 1) {
+ // ignore extra joins
+ }
+
+ DbJoin join = rel.getJoins().get(0);
+
+ buf.append("INSERT INTO _SYS_RELATIONSHIP (").append("dest_table, dest_column, source_table, source_column, ")
+ .append("block_delete, cascade_delete, one_to_many, operator, relationshipName").append(") VALUES ('")
+ .append(sourceEntity.getFullyQualifiedName()).append("', '").append(join.getSourceName())
+ .append("', '").append(targetEntity.getFullyQualifiedName()).append("', '")
+ .append(join.getTargetName()).append("', 0, 0, ").append(toMany).append(", '=', '")
+ .append(rel.getName()).append("')");
+
+ return buf.toString();
+ }
+
+ // OpenBase JDBC driver has trouble reading "integer" as byte
+ // this converter addresses such problem
+ static class OpenBaseByteType extends ByteType {
+
+ OpenBaseByteType() {
+ super(true);
+ }
+
+ @Override
+ public Object materializeObject(ResultSet rs, int index, int type) throws Exception {
+
+ // read value as int, and then narrow it down
+ int val = rs.getInt(index);
+ return (rs.wasNull()) ? null : Byte.valueOf((byte) val);
+ }
+
+ @Override
+ public Object materializeObject(CallableStatement rs, int index, int type) throws Exception {
+
+ // read value as int, and then narrow it down
+ int val = rs.getInt(index);
+ return (rs.wasNull()) ? null : Byte.valueOf((byte) val);
+ }
+ }
+
+ static class OpenBaseCharType extends CharType {
+
+ OpenBaseCharType() {
+ super(false, true);
+ }
+
+ @Override
+ public void setJdbcObject(PreparedStatement st, Object val, int pos, int type, int precision) throws Exception {
+
+ // These to types map to "text"; and when setting "text" as object
+ // OB assumes that the object is the actual CLOB... weird
+ if (type == Types.CLOB || type == Types.LONGVARCHAR) {
+ st.setString(pos, (String) val);
+ } else {
+ super.setJdbcObject(st, val, pos, type, precision);
+ }
+ }
+ }
+
+ @Override
+ public MergerFactory mergerFactory() {
+ return new OpenBaseMergerFactory();
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8ActionBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8ActionBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8ActionBuilder.java
index 3cd8f31..4dec81c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8ActionBuilder.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8ActionBuilder.java
@@ -23,7 +23,6 @@ import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.query.BatchQuery;
import org.apache.cayenne.query.SQLAction;
import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SelectQuery;
/**
* An action builder for Oracle8Adapter.
@@ -32,33 +31,28 @@ import org.apache.cayenne.query.SelectQuery;
*/
class Oracle8ActionBuilder extends OracleActionBuilder {
- Oracle8ActionBuilder(DataNode dataNode) {
- super(dataNode);
- }
-
- @Override
- public SQLAction sqlAction(SQLTemplate query) {
- return new Oracle8SQLTemplateAction(query, dataNode);
- }
-
- @Override
- public <T> SQLAction objectSelectAction(SelectQuery<T> query) {
- return new Oracle8SelectAction(query, dataNode);
- }
-
- @Override
- public SQLAction batchAction(BatchQuery query) {
- // special handling for LOB updates
- if (OracleAdapter.isSupportsOracleLOB() && OracleAdapter.updatesLOBColumns(query)) {
- // Special action for Oracle8. See CAY-1307.
- return new Oracle8LOBBatchAction(query, dataNode.getAdapter(), dataNode.getJdbcEventLogger());
- } else {
- // optimistic locking is not supported in batches due to JDBC driver
- // limitations
- boolean useOptimisticLock = query.isUsingOptimisticLocking();
- boolean runningAsBatch = !useOptimisticLock && dataNode.getAdapter().supportsBatchUpdates();
-
- return new OracleBatchAction(query, dataNode, runningAsBatch);
- }
- }
+ Oracle8ActionBuilder(DataNode dataNode) {
+ super(dataNode);
+ }
+
+ @Override
+ public SQLAction sqlAction(SQLTemplate query) {
+ return new Oracle8SQLTemplateAction(query, dataNode);
+ }
+
+ @Override
+ public SQLAction batchAction(BatchQuery query) {
+ // special handling for LOB updates
+ if (OracleAdapter.isSupportsOracleLOB() && OracleAdapter.updatesLOBColumns(query)) {
+ // Special action for Oracle8. See CAY-1307.
+ return new Oracle8LOBBatchAction(query, dataNode.getAdapter(), dataNode.getJdbcEventLogger());
+ } else {
+ // optimistic locking is not supported in batches due to JDBC driver
+ // limitations
+ boolean useOptimisticLock = query.isUsingOptimisticLocking();
+ boolean runningAsBatch = !useOptimisticLock && dataNode.getAdapter().supportsBatchUpdates();
+
+ return new OracleBatchAction(query, dataNode, runningAsBatch);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8Adapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8Adapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8Adapter.java
index 2a85312..c0acdb9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8Adapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8Adapter.java
@@ -26,82 +26,91 @@ import java.util.List;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.translator.select.QualifierTranslator;
import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.access.types.ExtendedType;
import org.apache.cayenne.access.types.ExtendedTypeFactory;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.RuntimeProperties;
import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.resource.ResourceLocator;
/**
- * A flavor of OracleAdapter that implements workarounds for some old driver limitations.
+ * A flavor of OracleAdapter that implements workarounds for some old driver
+ * limitations.
*
* @since 1.2
*/
public class Oracle8Adapter extends OracleAdapter {
- private static Method outputStreamFromBlobMethod;
- private static Method writerFromClobMethod;
-
- static {
- initOracle8DriverInformation();
- }
-
- public Oracle8Adapter(@Inject RuntimeProperties runtimeProperties,
- @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
- @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
- @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
- @Inject ResourceLocator resourceLocator) {
- super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
- }
-
- private static void initOracle8DriverInformation() {
- initDone = true;
-
- // configure static information
- try {
- outputStreamFromBlobMethod = Class.forName("oracle.sql.BLOB").getMethod(
- "getBinaryOutputStream");
- writerFromClobMethod = Class.forName("oracle.sql.CLOB").getMethod(
- "getCharacterOutputStream");
- }
- catch (Throwable th) {
- // ignoring...
- }
- }
-
- static Method getWriterFromClobMethod() {
- return writerFromClobMethod;
- }
-
- static Method getOutputStreamFromBlobMethod() {
- return outputStreamFromBlobMethod;
- }
-
- /**
- * Uses OracleActionBuilder to create the right action.
- */
- @Override
- public SQLAction getAction(Query query, DataNode node) {
- return query.createSQLAction(new Oracle8ActionBuilder(node));
- }
-
- @Override
- protected URL findResource(String name) {
-
- if ("/types.xml".equals(name)) {
- name = "/types-oracle8.xml";
- }
-
- return super.findResource(name);
- }
-
- @Override
- public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
- QualifierTranslator translator = new Oracle8QualifierTranslator(queryAssembler);
- translator.setCaseInsensitive(caseInsensitiveCollations);
- return translator;
- }
+ private static Method outputStreamFromBlobMethod;
+ private static Method writerFromClobMethod;
+
+ static {
+ initOracle8DriverInformation();
+ }
+
+ public Oracle8Adapter(@Inject RuntimeProperties runtimeProperties,
+ @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
+ @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
+ @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
+ @Inject ResourceLocator resourceLocator) {
+ super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
+ }
+
+ private static void initOracle8DriverInformation() {
+ initDone = true;
+
+ // configure static information
+ try {
+ outputStreamFromBlobMethod = Class.forName("oracle.sql.BLOB").getMethod("getBinaryOutputStream");
+ writerFromClobMethod = Class.forName("oracle.sql.CLOB").getMethod("getCharacterOutputStream");
+ } catch (Throwable th) {
+ // ignoring...
+ }
+ }
+
+ static Method getWriterFromClobMethod() {
+ return writerFromClobMethod;
+ }
+
+ static Method getOutputStreamFromBlobMethod() {
+ return outputStreamFromBlobMethod;
+ }
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) {
+ return new Oracle8SelectTranslator(query, this, entityResolver);
+ }
+
+ /**
+ * Uses OracleActionBuilder to create the right action.
+ */
+ @Override
+ public SQLAction getAction(Query query, DataNode node) {
+ return query.createSQLAction(new Oracle8ActionBuilder(node));
+ }
+
+ @Override
+ protected URL findResource(String name) {
+
+ if ("/types.xml".equals(name)) {
+ name = "/types-oracle8.xml";
+ }
+
+ return super.findResource(name);
+ }
+
+ @Override
+ public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
+ QualifierTranslator translator = new Oracle8QualifierTranslator(queryAssembler);
+ translator.setCaseInsensitive(caseInsensitiveCollations);
+ return translator;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8SelectAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8SelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8SelectAction.java
deleted file mode 100644
index abef7a7..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8SelectAction.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*****************************************************************
- * 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.cayenne.dba.oracle;
-
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.translator.select.SelectTranslator;
-import org.apache.cayenne.query.SelectQuery;
-
-/**
- * @since 3.0
- */
-class Oracle8SelectAction extends OracleSelectAction {
-
- <T> Oracle8SelectAction(SelectQuery<T> query, DataNode dataNode) {
- super(query, dataNode);
- }
-
- @Override
- protected SelectTranslator createTranslator() {
- return new Oracle8SelectTranslator(query, dataNode.getAdapter(), dataNode.getEntityResolver());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
index 50d621c..f16b69d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
@@ -34,6 +34,7 @@ import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
import org.apache.cayenne.access.translator.select.QualifierTranslator;
import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.access.types.ByteType;
import org.apache.cayenne.access.types.ExtendedType;
import org.apache.cayenne.access.types.ExtendedTypeFactory;
@@ -43,21 +44,22 @@ import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.RuntimeProperties;
import org.apache.cayenne.dba.JdbcAdapter;
import org.apache.cayenne.dba.PkGenerator;
-import org.apache.cayenne.dba.QuotingStrategy;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.merge.MergerFactory;
import org.apache.cayenne.query.BatchQuery;
import org.apache.cayenne.query.InsertBatchQuery;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.query.UpdateBatchQuery;
import org.apache.cayenne.resource.ResourceLocator;
/**
- * DbAdapter implementation for <a href="http://www.oracle.com">Oracle RDBMS </a>. Sample
- * connection settings to use with Oracle are shown below:
+ * DbAdapter implementation for <a href="http://www.oracle.com">Oracle RDBMS
+ * </a>. Sample connection settings to use with Oracle are shown below:
*
* <pre>
* test-oracle.jdbc.username = test
@@ -68,288 +70,280 @@ import org.apache.cayenne.resource.ResourceLocator;
*/
public class OracleAdapter extends JdbcAdapter {
- public static final String ORACLE_FLOAT = "FLOAT";
- public static final String ORACLE_BLOB = "BLOB";
- public static final String ORACLE_CLOB = "CLOB";
- public static final String ORACLE_NCLOB = "NCLOB";
-
- public static final String TRIM_FUNCTION = "RTRIM";
- public static final String NEW_CLOB_FUNCTION = "EMPTY_CLOB()";
- public static final String NEW_BLOB_FUNCTION = "EMPTY_BLOB()";
-
- protected static boolean initDone;
- protected static int oracleCursorType = Integer.MAX_VALUE;
-
- protected static boolean supportsOracleLOB;
-
- static {
- // TODO: as CAY-234 shows, having such initialization done in a static fashion
- // makes it untestable and any potential problems hard to reproduce. Make this
- // an instance method (with all the affected vars) and write unit tests.
- initDriverInformation();
- }
-
- protected static void initDriverInformation() {
- initDone = true;
-
- // configure static information
- try {
- Class<?> oraTypes = Class.forName("oracle.jdbc.driver.OracleTypes");
- Field cursorField = oraTypes.getField("CURSOR");
- oracleCursorType = cursorField.getInt(null);
-
- supportsOracleLOB = true;
- }
- catch (Throwable th) {
- // ignoring...
- }
- }
-
- // TODO: rename to something that looks like English ...
- public static boolean isSupportsOracleLOB() {
- return supportsOracleLOB;
- }
-
- /**
- * Utility method that returns <code>true</code> if the query will update at least one
- * BLOB or CLOB DbAttribute.
- *
- * @since 1.2
- */
- static boolean updatesLOBColumns(BatchQuery query) {
- boolean isInsert = query instanceof InsertBatchQuery;
- boolean isUpdate = query instanceof UpdateBatchQuery;
-
- if (!isInsert && !isUpdate) {
- return false;
- }
-
- List<DbAttribute> updatedAttributes = (isInsert)
- ? query.getDbAttributes()
- : ((UpdateBatchQuery) query).getUpdatedAttributes();
-
- for (DbAttribute attr : updatedAttributes) {
- int type = attr.getType();
- if (type == Types.CLOB || type == Types.BLOB) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns an Oracle JDBC extension type defined in
- * oracle.jdbc.driver.OracleTypes.CURSOR. This value is determined from Oracle driver
- * classes via reflection in runtime, so that Cayenne code has no compile dependency
- * on the driver. This means that calling this method when the driver is not available
- * will result in an exception.
- */
- public static int getOracleCursorType() {
-
- if (oracleCursorType == Integer.MAX_VALUE) {
- throw new CayenneRuntimeException(
- "No information exists about oracle types. "
- + "Check that Oracle JDBC driver is available to the application.");
- }
-
- return oracleCursorType;
- }
-
- public OracleAdapter(
- @Inject RuntimeProperties runtimeProperties,
- @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
- @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
- @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
- @Inject ResourceLocator resourceLocator) {
- super(
- runtimeProperties,
- defaultExtendedTypes,
- userExtendedTypes,
- extendedTypeFactories,
- resourceLocator);
-
- // enable batch updates by default
- setSupportsBatchUpdates(true);
- }
-
- /**
- * @since 3.0
- */
- @Override
- protected EJBQLTranslatorFactory createEJBQLTranslatorFactory() {
- return new OracleEJBQLTranslatorFactory();
- }
-
- /**
- * Installs appropriate ExtendedTypes as converters for passing values between JDBC
- * and Java layers.
- */
- @Override
- protected void configureExtendedTypes(ExtendedTypeMap map) {
- super.configureExtendedTypes(map);
-
- // create specially configured CharType handler
- map.registerType(new OracleCharType());
-
- // create specially configured ByteArrayType handler
- map.registerType(new OracleByteArrayType());
-
- // override date handler with Oracle handler
- map.registerType(new OracleUtilDateType());
-
- // At least on MacOS X, driver does not handle Short and Byte properly
- map.registerType(new ShortType(true));
- map.registerType(new ByteType(true));
- map.registerType(new OracleBooleanType());
- }
-
- /**
- * Creates and returns a primary key generator. Overrides superclass implementation to
- * return an instance of OraclePkGenerator.
- */
- @Override
- protected PkGenerator createPkGenerator() {
- return new OraclePkGenerator(this);
- }
-
- /**
- * Returns a query string to drop a table corresponding to <code>ent</code> DbEntity.
- * Changes superclass behavior to drop all related foreign key constraints.
- *
- * @since 3.0
- */
- @Override
- public Collection<String> dropTableStatements(DbEntity table) {
- return Collections.singleton("DROP TABLE " + getQuotingStrategy().quotedFullyQualifiedName(table)
- + " CASCADE CONSTRAINTS");
- }
-
- @Override
- public void bindParameter(
- PreparedStatement statement,
- Object object,
- int pos,
- int sqlType,
- int scale) throws SQLException, Exception {
-
- // Oracle doesn't support BOOLEAN even when binding NULL, so have to intercept
- // NULL Boolean here, as super doesn't pass it through ExtendedType...
- if (object == null && sqlType == Types.BOOLEAN) {
- ExtendedType typeProcessor = getExtendedTypes().getRegisteredType(
- Boolean.class);
- typeProcessor.setJdbcObject(statement, object, pos, sqlType, scale);
- }
- else {
- super.bindParameter(statement, object, pos, sqlType, scale);
- }
- }
-
- /**
- * Fixes some reverse engineering problems. Namely if a columns is created as DECIMAL
- * and has non-positive precision it is converted to INTEGER.
- */
- @Override
- public DbAttribute buildAttribute(String name, String typeName, int type, int size, int scale, boolean allowNulls) {
- DbAttribute attr = super.buildAttribute(name, typeName, type, size, scale, allowNulls);
-
- if (type == Types.DECIMAL && scale <= 0) {
- attr.setType(Types.INTEGER);
- attr.setScale(-1);
- } else if (type == Types.OTHER) {
- // in this case we need to guess the attribute type
- // based on its string value
- if (ORACLE_FLOAT.equals(typeName)) {
- attr.setType(Types.FLOAT);
- } else if (ORACLE_BLOB.equals(typeName)) {
- attr.setType(Types.BLOB);
- } else if (ORACLE_CLOB.equals(typeName)) {
- attr.setType(Types.CLOB);
- } else if (ORACLE_NCLOB.equals(typeName)) {
- attr.setType(Types.NCLOB);
- }
- } else if (type == Types.DATE) {
- // Oracle DATE can store JDBC TIMESTAMP
- if ("DATE".equals(typeName)) {
- attr.setType(Types.TIMESTAMP);
- }
- }
-
- return attr;
- }
-
- /**
- * Returns a trimming translator.
- */
- @Override
- public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
- QualifierTranslator translator = new Oracle8QualifierTranslator(queryAssembler);
- translator.setCaseInsensitive(caseInsensitiveCollations);
- return translator;
- }
-
- /**
- * Uses OracleActionBuilder to create the right action.
- *
- * @since 1.2
- */
- @Override
- public SQLAction getAction(Query query, DataNode node) {
- return query.createSQLAction(new OracleActionBuilder(node));
- }
-
- /**
- * @since 3.0
- */
- final class OracleBooleanType implements ExtendedType {
-
- @Override
- public String getClassName() {
- return Boolean.class.getName();
- }
-
- @Override
- public void setJdbcObject(
- PreparedStatement st,
- Object val,
- int pos,
- int type,
- int precision) throws Exception {
-
- // Oracle does not support Types.BOOLEAN, so we have to override user mapping
- // unconditionally
- if (val == null) {
- st.setNull(pos, Types.INTEGER);
- }
- else {
- boolean flag = Boolean.TRUE.equals(val);
- st.setInt(pos, flag ? 1 : 0);
- }
- }
-
- @Override
- public Object materializeObject(ResultSet rs, int index, int type)
- throws Exception {
-
- // Oracle does not support Types.BOOLEAN, so we have to override user mapping
- // unconditionally
- int i = rs.getInt(index);
- return rs.wasNull() ? null : i == 0 ? Boolean.FALSE : Boolean.TRUE;
- }
-
- @Override
- public Object materializeObject(CallableStatement st, int index, int type)
- throws Exception {
-
- // Oracle does not support Types.BOOLEAN, so we have to override user mapping
- // unconditionally
- int i = st.getInt(index);
- return st.wasNull() ? null : i == 0 ? Boolean.FALSE : Boolean.TRUE;
- }
- }
-
- @Override
- public MergerFactory mergerFactory() {
- return new OracleMergerFactory();
- }
+ public static final String ORACLE_FLOAT = "FLOAT";
+ public static final String ORACLE_BLOB = "BLOB";
+ public static final String ORACLE_CLOB = "CLOB";
+ public static final String ORACLE_NCLOB = "NCLOB";
+
+ public static final String TRIM_FUNCTION = "RTRIM";
+ public static final String NEW_CLOB_FUNCTION = "EMPTY_CLOB()";
+ public static final String NEW_BLOB_FUNCTION = "EMPTY_BLOB()";
+
+ protected static boolean initDone;
+ protected static int oracleCursorType = Integer.MAX_VALUE;
+
+ protected static boolean supportsOracleLOB;
+
+ static {
+ // TODO: as CAY-234 shows, having such initialization done in a static
+ // fashion
+ // makes it untestable and any potential problems hard to reproduce.
+ // Make this
+ // an instance method (with all the affected vars) and write unit tests.
+ initDriverInformation();
+ }
+
+ protected static void initDriverInformation() {
+ initDone = true;
+
+ // configure static information
+ try {
+ Class<?> oraTypes = Class.forName("oracle.jdbc.driver.OracleTypes");
+ Field cursorField = oraTypes.getField("CURSOR");
+ oracleCursorType = cursorField.getInt(null);
+
+ supportsOracleLOB = true;
+ } catch (Throwable th) {
+ // ignoring...
+ }
+ }
+
+ // TODO: rename to something that looks like English ...
+ public static boolean isSupportsOracleLOB() {
+ return supportsOracleLOB;
+ }
+
+ /**
+ * Utility method that returns <code>true</code> if the query will update at
+ * least one BLOB or CLOB DbAttribute.
+ *
+ * @since 1.2
+ */
+ static boolean updatesLOBColumns(BatchQuery query) {
+ boolean isInsert = query instanceof InsertBatchQuery;
+ boolean isUpdate = query instanceof UpdateBatchQuery;
+
+ if (!isInsert && !isUpdate) {
+ return false;
+ }
+
+ List<DbAttribute> updatedAttributes = (isInsert) ? query.getDbAttributes() : ((UpdateBatchQuery) query)
+ .getUpdatedAttributes();
+
+ for (DbAttribute attr : updatedAttributes) {
+ int type = attr.getType();
+ if (type == Types.CLOB || type == Types.BLOB) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an Oracle JDBC extension type defined in
+ * oracle.jdbc.driver.OracleTypes.CURSOR. This value is determined from
+ * Oracle driver classes via reflection in runtime, so that Cayenne code has
+ * no compile dependency on the driver. This means that calling this method
+ * when the driver is not available will result in an exception.
+ */
+ public static int getOracleCursorType() {
+
+ if (oracleCursorType == Integer.MAX_VALUE) {
+ throw new CayenneRuntimeException("No information exists about oracle types. "
+ + "Check that Oracle JDBC driver is available to the application.");
+ }
+
+ return oracleCursorType;
+ }
+
+ public OracleAdapter(@Inject RuntimeProperties runtimeProperties,
+ @Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
+ @Inject(Constants.SERVER_USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
+ @Inject(Constants.SERVER_TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
+ @Inject ResourceLocator resourceLocator) {
+ super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator);
+
+ // enable batch updates by default
+ setSupportsBatchUpdates(true);
+ }
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) {
+ return new OracleSelectTranslator(query, this, entityResolver);
+ }
+
+ /**
+ * @since 3.0
+ */
+ @Override
+ protected EJBQLTranslatorFactory createEJBQLTranslatorFactory() {
+ return new OracleEJBQLTranslatorFactory();
+ }
+
+ /**
+ * Installs appropriate ExtendedTypes as converters for passing values
+ * between JDBC and Java layers.
+ */
+ @Override
+ protected void configureExtendedTypes(ExtendedTypeMap map) {
+ super.configureExtendedTypes(map);
+
+ // create specially configured CharType handler
+ map.registerType(new OracleCharType());
+
+ // create specially configured ByteArrayType handler
+ map.registerType(new OracleByteArrayType());
+
+ // override date handler with Oracle handler
+ map.registerType(new OracleUtilDateType());
+
+ // At least on MacOS X, driver does not handle Short and Byte properly
+ map.registerType(new ShortType(true));
+ map.registerType(new ByteType(true));
+ map.registerType(new OracleBooleanType());
+ }
+
+ /**
+ * Creates and returns a primary key generator. Overrides superclass
+ * implementation to return an instance of OraclePkGenerator.
+ */
+ @Override
+ protected PkGenerator createPkGenerator() {
+ return new OraclePkGenerator(this);
+ }
+
+ /**
+ * Returns a query string to drop a table corresponding to <code>ent</code>
+ * DbEntity. Changes superclass behavior to drop all related foreign key
+ * constraints.
+ *
+ * @since 3.0
+ */
+ @Override
+ public Collection<String> dropTableStatements(DbEntity table) {
+ return Collections.singleton("DROP TABLE " + getQuotingStrategy().quotedFullyQualifiedName(table)
+ + " CASCADE CONSTRAINTS");
+ }
+
+ @Override
+ public void bindParameter(PreparedStatement statement, Object object, int pos, int sqlType, int scale)
+ throws SQLException, Exception {
+
+ // Oracle doesn't support BOOLEAN even when binding NULL, so have to
+ // intercept
+ // NULL Boolean here, as super doesn't pass it through ExtendedType...
+ if (object == null && sqlType == Types.BOOLEAN) {
+ ExtendedType typeProcessor = getExtendedTypes().getRegisteredType(Boolean.class);
+ typeProcessor.setJdbcObject(statement, object, pos, sqlType, scale);
+ } else {
+ super.bindParameter(statement, object, pos, sqlType, scale);
+ }
+ }
+
+ /**
+ * Fixes some reverse engineering problems. Namely if a columns is created
+ * as DECIMAL and has non-positive precision it is converted to INTEGER.
+ */
+ @Override
+ public DbAttribute buildAttribute(String name, String typeName, int type, int size, int scale, boolean allowNulls) {
+ DbAttribute attr = super.buildAttribute(name, typeName, type, size, scale, allowNulls);
+
+ if (type == Types.DECIMAL && scale <= 0) {
+ attr.setType(Types.INTEGER);
+ attr.setScale(-1);
+ } else if (type == Types.OTHER) {
+ // in this case we need to guess the attribute type
+ // based on its string value
+ if (ORACLE_FLOAT.equals(typeName)) {
+ attr.setType(Types.FLOAT);
+ } else if (ORACLE_BLOB.equals(typeName)) {
+ attr.setType(Types.BLOB);
+ } else if (ORACLE_CLOB.equals(typeName)) {
+ attr.setType(Types.CLOB);
+ } else if (ORACLE_NCLOB.equals(typeName)) {
+ attr.setType(Types.NCLOB);
+ }
+ } else if (type == Types.DATE) {
+ // Oracle DATE can store JDBC TIMESTAMP
+ if ("DATE".equals(typeName)) {
+ attr.setType(Types.TIMESTAMP);
+ }
+ }
+
+ return attr;
+ }
+
+ /**
+ * Returns a trimming translator.
+ */
+ @Override
+ public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
+ QualifierTranslator translator = new Oracle8QualifierTranslator(queryAssembler);
+ translator.setCaseInsensitive(caseInsensitiveCollations);
+ return translator;
+ }
+
+ /**
+ * Uses OracleActionBuilder to create the right action.
+ *
+ * @since 1.2
+ */
+ @Override
+ public SQLAction getAction(Query query, DataNode node) {
+ return query.createSQLAction(new OracleActionBuilder(node));
+ }
+
+ /**
+ * @since 3.0
+ */
+ final class OracleBooleanType implements ExtendedType {
+
+ @Override
+ public String getClassName() {
+ return Boolean.class.getName();
+ }
+
+ @Override
+ public void setJdbcObject(PreparedStatement st, Object val, int pos, int type, int precision) throws Exception {
+
+ // Oracle does not support Types.BOOLEAN, so we have to override
+ // user mapping
+ // unconditionally
+ if (val == null) {
+ st.setNull(pos, Types.INTEGER);
+ } else {
+ boolean flag = Boolean.TRUE.equals(val);
+ st.setInt(pos, flag ? 1 : 0);
+ }
+ }
+
+ @Override
+ public Object materializeObject(ResultSet rs, int index, int type) throws Exception {
+
+ // Oracle does not support Types.BOOLEAN, so we have to override
+ // user mapping
+ // unconditionally
+ int i = rs.getInt(index);
+ return rs.wasNull() ? null : i == 0 ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ @Override
+ public Object materializeObject(CallableStatement st, int index, int type) throws Exception {
+
+ // Oracle does not support Types.BOOLEAN, so we have to override
+ // user mapping
+ // unconditionally
+ int i = st.getInt(index);
+ return st.wasNull() ? null : i == 0 ? Boolean.FALSE : Boolean.TRUE;
+ }
+ }
+
+ @Override
+ public MergerFactory mergerFactory() {
+ return new OracleMergerFactory();
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSelectAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSelectAction.java
index f361aa4..60e8e5a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSelectAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSelectAction.java
@@ -21,7 +21,6 @@ package org.apache.cayenne.dba.oracle;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.jdbc.SelectAction;
-import org.apache.cayenne.access.translator.select.SelectTranslator;
import org.apache.cayenne.query.SelectQuery;
/**
@@ -34,11 +33,6 @@ class OracleSelectAction extends SelectAction {
}
@Override
- protected SelectTranslator createTranslator() {
- return new OracleSelectTranslator(query, dataNode.getAdapter(), dataNode.getEntityResolver());
- }
-
- @Override
protected int getInMemoryOffset(int queryOffset) {
return 0;
}