4029 Craig L Russell 2010-12-20
Add DynamicObject to clusterj
added:
storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ColumnMetadata.java
storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObject.java
storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObjectDelegate.java
storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/DynamicObjectTest.java
storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/DynamicObjectTest.java
modified:
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java
storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java
4028 Jonas Oreland 2010-12-20 [merge]
ndb - merge 70 to 71
modified:
mysql-test/suite/ndb/ndb_config_config.ini
storage/ndb/include/kernel/signaldata/AllocMem.hpp
storage/ndb/include/kernel/signaldata/NodeStateSignalData.hpp
storage/ndb/include/mgmapi/mgmapi_config_parameters.h
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp
storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.cpp
storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp
storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp
storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp
storage/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp
storage/ndb/src/kernel/blocks/record_types.hpp
storage/ndb/src/kernel/ndbd.cpp
storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp
storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp
storage/ndb/src/mgmsrv/ConfigInfo.cpp
=== added file 'storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ColumnMetadata.java'
--- a/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ColumnMetadata.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ColumnMetadata.java 2010-12-21 00:52:28 +0000
@@ -0,0 +1,114 @@
+/*
+ Copyright 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package com.mysql.clusterj;
+
+public interface ColumnMetadata {
+
+ /** Return the name of the column.
+ * @return the name of the column
+ */
+ String name();
+
+ /** Return the type of the column.
+ * @return the type of the column
+ */
+ Type type();
+
+ /** Return the java type of the column.
+ * @return the java type of the column
+ */
+ Class<?> javaType();
+
+ /** Return the maximum number of bytes that can be stored in the column
+ * after translating the characters using the character set.
+ * @return the maximum number of bytes that can be stored in the column
+ */
+ int maximumLength();
+
+ /** Return the column number. This number is used as the first parameter in
+ * the get and set methods of DynamicColumn.
+ * @return the column number.
+ */
+ int number();
+
+ /** Return whether this column is a primary key column.
+ * @return true if this column is a primary key column
+ */
+ boolean isPrimaryKey();
+
+ /** Return whether this column is a partition key column.
+ * @return true if this column is a partition key column
+ */
+ boolean isPartitionKey();
+
+ /** Return the precision of the column.
+ * @return the precision of the column
+ */
+ int precision();
+
+ /** Return the scale of the column.
+ * @return the scale of the column
+ */
+ int scale();
+
+ /** Return whether this column is nullable.
+ * @return whether this column is nullable
+ */
+ boolean nullable();
+
+ /** Return the charset name.
+ * @return the charset name
+ */
+ String charsetName();
+
+ public enum Type {
+
+ Bigint, ///< 64 bit. 8 byte signed integer, can be used in array
+ Bigunsigned, ///< 64 Bit. 8 byte signed integer, can be used in array
+ Binary, ///< Len
+ Bit, ///< Bit, length specifies no of bits
+ Blob, ///< Binary large object (see NdbBlob)
+ Char, ///< Len. A fixed array of 1-byte chars
+ Date, ///< Precision down to 1 day(sizeof(Date) == 4 bytes )
+ Datetime, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes )
+ Double, ///< 64-bit float. 8 byte float, can be used in array
+ Decimal, ///< MySQL >= 5.0 signed decimal, Precision, Scale
+ Decimalunsigned,
+ Float, ///< 32-bit float. 4 bytes float, can be used in array
+ Int, ///< 32 bit. 4 byte signed integer, can be used in array
+ Longvarchar, ///< Length bytes: 2, little-endian
+ Longvarbinary, ///< Length bytes: 2, little-endian
+ Mediumint, ///< 24 bit. 3 byte signed integer, can be used in array
+ Mediumunsigned, ///< 24 bit. 3 byte unsigned integer, can be used in array
+ Olddecimal,
+ Olddecimalunsigned,
+ Smallint, ///< 16 bit. 2 byte signed integer, can be used in array
+ Smallunsigned, ///< 16 bit. 2 byte unsigned integer, can be used in array
+ Text, ///< Text blob
+ Time, ///< Time without date
+ Timestamp, ///< Unix time
+ Tinyint, ///< 8 bit. 1 byte signed integer, can be used in array
+ Tinyunsigned, ///< 8 bit. 1 byte unsigned integer, can be used in array
+ Undefined,
+ Unsigned, ///< 32 bit. 4 byte unsigned integer, can be used in array
+ Varbinary, ///< Length bytes: 1, Max: 255
+ Varchar, ///< Length bytes: 1, Max: 255
+ Year ///< Year 1901-2155 (1 byte)
+ }
+
+}
=== added file 'storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObject.java'
--- a/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObject.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObject.java 2010-12-21 00:52:28 +0000
@@ -0,0 +1,45 @@
+/*
+ Copyright 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package com.mysql.clusterj;
+
+public abstract class DynamicObject {
+
+ private DynamicObjectDelegate delegate;
+
+ public abstract String tableName();
+
+ public final void delegate(DynamicObjectDelegate delegate) {
+ this.delegate = delegate;
+ }
+
+ public final DynamicObjectDelegate delegate() {
+ return delegate;
+ }
+
+ public final Object get(int columnNumber) {
+ return delegate.get(columnNumber);
+ }
+
+ public final void set(int columnNumber, Object value) {
+ delegate.set(columnNumber, value);
+ }
+
+ public final ColumnMetadata[] columnMetadata() {
+ return delegate.columnMetadata();
+ }
+}
=== added file 'storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObjectDelegate.java'
--- a/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObjectDelegate.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/DynamicObjectDelegate.java 2010-12-21 00:52:28 +0000
@@ -0,0 +1,29 @@
+/*
+ Copyright 2010, Oracle and/or its affiliates. All rights reserved.
+ All rights reserved. Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package com.mysql.clusterj;
+
+public interface DynamicObjectDelegate {
+
+ public Object get(int columnNumber);
+
+ public void set(int columnNumber, Object value);
+
+ public ColumnMetadata[] columnMetadata();
+
+}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java 2010-12-17 19:54:39 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java 2010-12-21 00:52:28 +0000
@@ -260,16 +260,34 @@ public class SessionImpl implements Sess
return instance;
}
- /** Make an instance persistent.
+ /** Make an instance persistent. Also recursively make an iterable collection or array persistent.
*
- * @param object the instance
+ * @param object the instance or array or iterable collection of instances
* @return the instance
*/
public <T> T makePersistent(T object) {
if (object == null) {
return null;
}
- DomainTypeHandler domainTypeHandler = getDomainTypeHandler(object);
+ if (Iterable.class.isAssignableFrom(object.getClass())) {
+ startAutoTransaction();
+ Iterable<?> instances = (Iterable<?>)object;
+ for (Object instance:instances) {
+ makePersistent(instance);
+ }
+ endAutoTransaction();
+ return object;
+ }
+ if (object.getClass().isArray()) {
+ startAutoTransaction();
+ Object[] instances = (Object[])object;
+ for (Object instance:instances) {
+ makePersistent(instance);
+ }
+ endAutoTransaction();
+ return object;
+ }
+ DomainTypeHandler<?> domainTypeHandler = getDomainTypeHandler(object);
ValueHandler valueHandler = domainTypeHandler.getValueHandler(object);
insert(domainTypeHandler, valueHandler);
return object;
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java 2010-09-13 10:48:19 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java 2010-12-21 00:52:28 +0000
@@ -18,11 +18,12 @@
package com.mysql.clusterj.core.metadata;
-import com.mysql.clusterj.core.spi.ValueHandler;
-import com.mysql.clusterj.core.spi.DomainTypeHandler;
import com.mysql.clusterj.ClusterJDatastoreException;
import com.mysql.clusterj.ClusterJFatalInternalException;
import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.spi.ValueHandler;
+import com.mysql.clusterj.core.spi.DomainTypeHandler;
import com.mysql.clusterj.core.query.CandidateIndexImpl;
import com.mysql.clusterj.core.query.PredicateImpl;
import com.mysql.clusterj.core.spi.DomainFieldHandler;
@@ -32,7 +33,6 @@ import com.mysql.clusterj.core.store.Ope
import com.mysql.clusterj.core.store.PartitionKey;
import com.mysql.clusterj.core.store.ResultData;
import com.mysql.clusterj.core.store.ScanFilter;
-import com.mysql.clusterj.core.store.Column.Type;
import com.mysql.clusterj.core.util.I18NHelper;
import com.mysql.clusterj.core.util.Logger;
import com.mysql.clusterj.core.util.LoggerFactoryService;
@@ -50,7 +50,7 @@ import java.util.Set;
/**
*
*/
-public abstract class AbstractDomainFieldHandlerImpl implements DomainFieldHandler {
+public abstract class AbstractDomainFieldHandlerImpl implements DomainFieldHandler, ColumnMetadata {
public AbstractDomainFieldHandlerImpl() {}
@@ -62,8 +62,8 @@ public abstract class AbstractDomainFiel
/** The domain type handler for this field */
protected DomainTypeHandler<?> domainTypeHandler;
- /** "true" if the mapped column allows null values */
- protected String columnAllowsNull;
+ /** true if the mapped column allows null values */
+ protected boolean nullable;
/** The default value for the column if the field is null */
protected String columnDefaultValue = null;
@@ -77,6 +77,18 @@ public abstract class AbstractDomainFiel
/** The Charset name for the column. */
protected String charsetName = null;
+ /** The precision of the column in the database */
+ protected int precision;
+
+ /** The scale of the column in the database */
+ protected int scale;
+
+ /** The length of the column in the database */
+ protected int maximumLength;
+
+ /** true if the column is part of the partition key */
+ protected boolean partitionKey;
+
/** The Store Type for the column. */
protected Type storeColumnType = null;
@@ -2613,4 +2625,59 @@ public abstract class AbstractDomainFiel
}
};
+ /* These methods implement ColumnMetadata
+ */
+
+ protected void initializeColumnMetadata(com.mysql.clusterj.core.store.Column storeColumn) {
+ this.columnName = storeColumn.getName();;
+ this.storeColumnType = storeColumn.getType();
+ this.charsetName = storeColumn.getCharsetName();
+ this.primaryKey = storeColumn.isPrimaryKey();
+ this.partitionKey = storeColumn.isPartitionKey();
+ this.precision = storeColumn.getPrecision();
+ this.scale = storeColumn.getScale();
+ this.maximumLength = storeColumn.getLength();
+ this.nullable = storeColumn.getNullable();
+ }
+
+ public boolean isPartitionKey() {
+ return partitionKey;
+ }
+
+ public int maximumLength() {
+ return maximumLength;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public int number() {
+ return fieldNumber;
+ }
+
+ public int precision() {
+ return precision;
+ }
+
+ public int scale() {
+ return scale;
+ }
+
+ public Type type() {
+ return this.storeColumnType;
+ }
+
+ public boolean nullable() {
+ return nullable;
+ }
+
+ public Class<?> javaType() {
+ return this.type;
+ }
+
+ public String charsetName() {
+ return this.charsetName;
+ }
+
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java 2010-09-22 18:34:38 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java 2010-12-21 00:52:28 +0000
@@ -130,12 +130,14 @@ public abstract class AbstractDomainType
if (primaryKeyColumnNames[i].equals(columnName)) {
idFieldHandlers[i] = fmd;
idFieldNumbers[i] = fmd.getFieldNumber();
+ if (logger.isDetailEnabled()) logger.detail("registerPrimaryKeyColumn found primary key " + columnName);
}
}
// find the partition key column that matches the primary key column
for (int j = 0; j < partitionKeyColumnNames.length; ++j) {
if (partitionKeyColumnNames[j].equals(columnName)) {
partitionKeyFieldHandlers[j] = fmd;
+ if (logger.isDetailEnabled()) logger.detail("registerPrimaryKeyColumn found partition key " + columnName);
}
}
return;
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java 2010-10-28 09:50:56 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java 2010-12-21 00:52:28 +0000
@@ -18,7 +18,6 @@
package com.mysql.clusterj.core.metadata;
-import com.mysql.clusterj.core.spi.DomainFieldHandler;
import com.mysql.clusterj.core.spi.ValueHandler;
import com.mysql.clusterj.ClusterJDatastoreException;
import com.mysql.clusterj.ClusterJUserException;
@@ -47,7 +46,7 @@ import java.math.BigInteger;
* type-specific handlers for Ndb operations.
*
*/
-public class DomainFieldHandlerImpl extends AbstractDomainFieldHandlerImpl implements DomainFieldHandler {
+public class DomainFieldHandlerImpl extends AbstractDomainFieldHandlerImpl {
/** The NullValue setting of the column from the Persistent annotation. */
NullValue nullValue = NullValue.NONE;
@@ -70,6 +69,9 @@ public class DomainFieldHandlerImpl exte
/** The Column annotation on the get method. */
protected Column columnAnnotation = null;
+ /** The AllowsNull annotation */
+ protected String columnAllowsNull;
+
/** Lob annotation is not null if annotated with @Lob. */
protected Lob lobAnnotation;
@@ -83,6 +85,16 @@ public class DomainFieldHandlerImpl exte
return compareTo((DomainFieldHandlerImpl)other);
}
+ /** Create a domain field handler for annotated interfaces.
+ *
+ * @param domainTypeHandler the domain type handler
+ * @param table the table
+ * @param fieldNumber the field number (in schema definition order)
+ * @param name the field name
+ * @param type the java type
+ * @param getMethod the get method for the field
+ * @param setMethod the set method for the field
+ */
public DomainFieldHandlerImpl(DomainTypeHandlerImpl<?> domainTypeHandler, Table table,
int fieldNumber, String name, Class<?> type,
Method getMethod, Method setMethod) {
@@ -136,13 +148,11 @@ public class DomainFieldHandlerImpl exte
throw new ClusterJUserException(local.message("ERR_No_Column",
name, table.getName(), columnName));
}
- storeColumnType = storeColumn.getType();
- charsetName = storeColumn.getCharsetName();
+ initializeColumnMetadata(storeColumn);
if (logger.isDebugEnabled())
logger.debug("Column type for " + name + " is "
+ storeColumnType.toString() + "; charset name is "
+ charsetName);
- primaryKey = storeColumn.isPrimaryKey();
domainTypeHandler.registerPrimaryKeyColumn(this, columnName);
lobAnnotation = getMethod.getAnnotation(Lob.class);
}
@@ -205,7 +215,7 @@ public class DomainFieldHandlerImpl exte
} else if (type.equals(Long.class)) {
objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
} else if (type.equals(Short.class)) {
- if (com.mysql.clusterj.core.store.Column.Type.Year.equals(storeColumnType)) {
+ if (Type.Year.equals(storeColumnType)) {
objectOperationHandlerDelegate = objectOperationHandlerObjectShortYear;
} else {
objectOperationHandlerDelegate = objectOperationHandlerObjectShort;
@@ -217,7 +227,7 @@ public class DomainFieldHandlerImpl exte
} else if (type.equals(long.class)) {
objectOperationHandlerDelegate = objectOperationHandlerLong;
} else if (type.equals(short.class)) {
- if (com.mysql.clusterj.core.store.Column.Type.Year.equals(storeColumnType)) {
+ if (Type.Year.equals(storeColumnType)) {
objectOperationHandlerDelegate = objectOperationHandlerShortYear;
} else {
objectOperationHandlerDelegate = objectOperationHandlerShort;
@@ -247,6 +257,7 @@ public class DomainFieldHandlerImpl exte
// Handle indexes. One index can be annotated on this field.
// Other indexes including the column mapped to this field
// are annotated on the class.
+ // TODO: indexes are ignored since they are handled by reading the column metadata
indexAnnotation = getMethod.getAnnotation(
com.mysql.clusterj.annotation.Index.class);
String indexName = null;
@@ -257,10 +268,7 @@ public class DomainFieldHandlerImpl exte
local.message("ERR_Index_Annotation_Columns", domainTypeHandler.getName(), name));
}
}
- indices = domainTypeHandler.registerIndices(this, columnName);
- indexNames = domainTypeHandler.getIndexNames(indices);
- logger.debug("Index names for " + name + " are " + indexNames);
- logger.debug("Indices for " + name + " are " + printIndices());
+ registerIndices(domainTypeHandler);
persistentAnnotation = getMethod.getAnnotation(Persistent.class);
if (persistentAnnotation != null) {
@@ -289,10 +297,174 @@ public class DomainFieldHandlerImpl exte
reportErrors();
}
+ /** Create a domain field handler for dynamic objects.
+ *
+ * @param domainTypeHandler the domain type handler
+ * @param table the table
+ * @param i the field number
+ * @param storeColumn the store column definition
+ */
+ public DomainFieldHandlerImpl(
+ DomainTypeHandlerImpl<?> domainTypeHandler, Table table, int i,
+ com.mysql.clusterj.core.store.Column storeColumn) {
+ if (logger.isDebugEnabled()) logger.debug("new dynamic DomainFieldHandlerImpl: " +
+ "fieldNumber: " + fieldNumber + "; name:" + name);
+ this.domainTypeHandler = domainTypeHandler;
+ this.fieldNumber = i;
+ this.storeColumn = storeColumn;
+ initializeColumnMetadata(storeColumn);
+ this.name = this.columnName;
+ this.columnNames = new String[]{columnName};
+ if (primaryKey) {
+ domainTypeHandler.registerPrimaryKeyColumn(this, columnName);
+ switch (this.storeColumnType) {
+ case Int:
+ case Unsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerKeyInt;
+ this.type = Integer.class;
+ break;
+ case Char:
+ case Varchar:
+ this.objectOperationHandlerDelegate = objectOperationHandlerKeyString;
+ this.type = String.class;
+ break;
+ case Bigint:
+ case Bigunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerKeyLong;
+ this.type = Long.class;
+ break;
+ default:
+ error(local.message("ERR_Primary_Field_Type", name));
+ }
+ } else {
+ switch (this.storeColumnType) {
+ case Bigint:
+ case Bigunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
+ this.type = Long.class;
+ break;
+ case Binary:
+ this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
+ this.type = byte[].class;
+ break;
+ case Bit:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
+ this.type = Long.class;
+ break;
+ case Blob:
+ this.objectOperationHandlerDelegate = objectOperationHandlerBytesLob;
+ this.type = byte[].class;
+ break;
+ case Char:
+ this.objectOperationHandlerDelegate = objectOperationHandlerString;
+ this.type = String.class;
+ break;
+ case Date:
+ this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlDate;
+ this.type = java.sql.Date.class;
+ break;
+ case Datetime:
+ this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTimestamp;
+ this.type = java.sql.Timestamp.class;
+ break;
+ case Decimal:
+ case Decimalunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerDecimal;
+ this.type = BigDecimal.class;
+ break;
+ case Double:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectDouble;
+ this.type = Double.class;
+ break;
+ case Float:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectFloat;
+ this.type = Float.class;
+ break;
+ case Int:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
+ this.type = Integer.class;
+ break;
+ case Longvarbinary:
+ this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
+ this.type = byte[].class;
+ break;
+ case Longvarchar:
+ this.objectOperationHandlerDelegate = objectOperationHandlerString;
+ this.type = String.class;
+ break;
+ case Mediumint:
+ case Mediumunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
+ this.type = Integer.class;
+ break;
+ case Olddecimal:
+ error(local.message("ERR_Unsupported_Field_Type", "Olddecimal", name));
+ objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
+ break;
+ case Olddecimalunsigned:
+ error(local.message("ERR_Unsupported_Field_Type", "Olddecimalunsigned", name));
+ objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
+ break;
+ case Smallint:
+ case Smallunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectShort;
+ this.type = Short.class;
+ break;
+ case Text:
+ this.objectOperationHandlerDelegate = objectOperationHandlerStringLob;
+ this.type = String.class;
+ break;
+ case Time:
+ this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTime;
+ this.type = java.sql.Time.class;
+ break;
+ case Timestamp:
+ this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTimestamp;
+ this.type = java.sql.Timestamp.class;
+ break;
+ case Tinyint:
+ case Tinyunsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectByte;
+ this.type = Byte.class;
+ break;
+ case Undefined:
+ error(local.message("ERR_Unsupported_Field_Type", "Undefined"));
+ objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
+ break;
+ case Unsigned:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
+ this.type = Integer.class;
+ break;
+ case Varbinary:
+ this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
+ this.type = byte[].class;
+ break;
+ case Varchar:
+ this.objectOperationHandlerDelegate = objectOperationHandlerString;
+ this.type = String.class;
+ break;
+ case Year:
+ this.objectOperationHandlerDelegate = objectOperationHandlerObjectShortYear;
+ this.type = Short.class;
+ break;
+ }
+ }
+ nullValueDelegate = nullValueNONE;
+ registerIndices(domainTypeHandler);
+ reportErrors();
+ }
+
public boolean isPersistent() {
return notPersistentAnnotation == null;
}
+ protected void registerIndices(DomainTypeHandlerImpl<?> domainTypeHandler) {
+ this.indices = domainTypeHandler.registerIndices(this, columnName);
+ this.indexNames = domainTypeHandler.getIndexNames(indices);
+ if (logger.isDebugEnabled()) logger.debug("Index names for " + name + " are " + indexNames);
+ if (logger.isDebugEnabled()) logger.debug("Indices for " + name + " are " + printIndices());
+ }
+
@Override
public void operationSetValue(ValueHandler handler, Operation op) {
// handle NullValue here
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java 2010-01-22 19:10:41 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java 2010-12-21 00:52:28 +0000
@@ -18,6 +18,7 @@
package com.mysql.clusterj.core.metadata;
+import com.mysql.clusterj.ClusterJException;
import com.mysql.clusterj.ClusterJHelper;
import com.mysql.clusterj.ClusterJUserException;
import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
@@ -76,6 +77,9 @@ public class DomainTypeHandlerFactoryImp
errorMessages.append("Trying standard factory com.mysql.clusterj.core.metadata.DomainTypeHandlerImpl.\n");
handler = new DomainTypeHandlerImpl<T>(domainClass, dictionary);
return handler;
+ } catch (ClusterJException e) {
+ errorMessages.append(e.toString());
+ throw e;
} catch (Exception e) {
errorMessages.append(e.toString());
throw new ClusterJUserException(errorMessages.toString(), e);
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java 2010-09-22 18:34:38 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java 2010-12-21 00:52:28 +0000
@@ -23,11 +23,15 @@ import com.mysql.clusterj.core.spi.Value
import com.mysql.clusterj.ClusterJException;
import com.mysql.clusterj.ClusterJFatalInternalException;
import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.DynamicObject;
+import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.DynamicObjectDelegate;
import com.mysql.clusterj.annotation.PersistenceCapable;
import com.mysql.clusterj.core.CacheManager;
+import com.mysql.clusterj.core.store.Column;
import com.mysql.clusterj.core.store.Index;
import com.mysql.clusterj.core.store.Dictionary;
import com.mysql.clusterj.core.store.Operation;
@@ -59,6 +63,9 @@ public class DomainTypeHandlerImpl<T> ex
/** The domain class. */
Class<T> cls;
+ /** Dynamic class indicator */
+ boolean dynamic = false;
+
/** The methods of the properties. */
private Map<String, Method> unmatchedGetMethods = new HashMap<String, Method>();
private Map<String, Method> unmatchedSetMethods = new HashMap<String, Method>();
@@ -84,19 +91,24 @@ public class DomainTypeHandlerImpl<T> ex
*/
@SuppressWarnings( "unchecked" )
public DomainTypeHandlerImpl(Class<T> cls, Dictionary dictionary) {
- if (logger.isDebugEnabled()) logger.debug("New DomainTypeHandlerImpl for class " + cls.getName());
this.cls = cls;
this.name = cls.getName();
- // Create a proxy class for the domain class
- proxyClass = (Class<T>)Proxy.getProxyClass(
- cls.getClassLoader(), new Class[]{cls});
- ctor = getConstructorForInvocationHandler (proxyClass);
- persistenceCapable = cls.getAnnotation(PersistenceCapable.class);
- if (persistenceCapable == null) {
- throw new ClusterJUserException(local.message(
- "ERR_No_Persistence_Capable_Annotation", name));
+ this.dynamic = DynamicObject.class.isAssignableFrom(cls);
+ if (dynamic) {
+ // Dynamic object has a handler but no proxy
+ this.tableName = getTableNameForDynamicObject((Class<DynamicObject>)cls);
+ } else {
+ // Create a proxy class for the domain class
+ proxyClass = (Class<T>)Proxy.getProxyClass(
+ cls.getClassLoader(), new Class[]{cls});
+ ctor = getConstructorForInvocationHandler (proxyClass);
+ persistenceCapable = cls.getAnnotation(PersistenceCapable.class);
+ if (persistenceCapable == null) {
+ throw new ClusterJUserException(local.message(
+ "ERR_No_Persistence_Capable_Annotation", name));
+ }
+ this.tableName = persistenceCapable.table();
}
- tableName = persistenceCapable.table();
this.table = getTable(dictionary);
if (table == null) {
throw new ClusterJUserException(local.message("ERR_Get_NdbTable", name, tableName));
@@ -132,76 +144,95 @@ public class DomainTypeHandlerImpl<T> ex
indexHandlerImpls.add(imd);
}
- // Now iterate the fields in the class
- List<String> fieldNameList = new ArrayList<String>();
- Method[] methods = cls.getMethods();
- for (Method method: methods) {
- // remember get methods
- String methodName = method.getName();
- String name = convertMethodName(methodName);
- Class type = getType(method);
- DomainFieldHandlerImpl domainFieldHandler = null;
- if (methodName.startsWith("get")) {
- Method unmatched = unmatchedSetMethods.get(name);
- if (unmatched == null) {
- // get is first of the pair; put it into the unmatched map
- unmatchedGetMethods.put(name, method);
- } else {
- // found the potential match
- if (getType(unmatched).equals(type)) {
- // method names and types match
- unmatchedSetMethods.remove(name);
- domainFieldHandler = new DomainFieldHandlerImpl(this, table,
- numberOfFields++, name, type, method, unmatched);
- } else {
- // both unmatched because of type mismatch
- unmatchedGetMethods.put(name, method);
- }
+ if (dynamic) {
+ // for each column in the database, create a field
+ List<String> fieldNameList = new ArrayList<String>();
+ for (String columnName: table.getColumnNames()) {
+ Column storeColumn = table.getColumn(columnName);
+ DomainFieldHandlerImpl domainFieldHandler = null;
+ domainFieldHandler =
+ new DomainFieldHandlerImpl(this, table, numberOfFields++, storeColumn);
+ String fieldName = domainFieldHandler.getName();
+ fieldNameList.add(fieldName);
+ fieldNameToNumber.put(domainFieldHandler.getName(), domainFieldHandler.getFieldNumber());
+ persistentFieldHandlers.add(domainFieldHandler);
+ if (!storeColumn.isPrimaryKey()) {
+ nonPKFieldHandlers.add(domainFieldHandler);
}
- } else if (methodName.startsWith("set")) {
- Method unmatched = unmatchedGetMethods.get(name);
- if (unmatched == null) {
- // set is first of the pair; put it into the unmatched map
- unmatchedSetMethods.put(name, method);
- } else {
- // found the potential match
- if (getType(unmatched).equals(type)) {
- // method names and types match
- unmatchedGetMethods.remove(name);
- domainFieldHandler = new DomainFieldHandlerImpl(this, table,
- numberOfFields++, name, type, unmatched, method);
+ }
+ fieldNames = fieldNameList.toArray(new String[fieldNameList.size()]);
+ } else {
+ // Iterate the fields (names and types based on get/set methods) in the class
+ List<String> fieldNameList = new ArrayList<String>();
+ Method[] methods = cls.getMethods();
+ for (Method method: methods) {
+ // remember get methods
+ String methodName = method.getName();
+ String name = convertMethodName(methodName);
+ Class type = getType(method);
+ DomainFieldHandlerImpl domainFieldHandler = null;
+ if (methodName.startsWith("get")) {
+ Method unmatched = unmatchedSetMethods.get(name);
+ if (unmatched == null) {
+ // get is first of the pair; put it into the unmatched map
+ unmatchedGetMethods.put(name, method);
} else {
- // both unmatched because of type mismatch
+ // found the potential match
+ if (getType(unmatched).equals(type)) {
+ // method names and types match
+ unmatchedSetMethods.remove(name);
+ domainFieldHandler = new DomainFieldHandlerImpl(this, table,
+ numberOfFields++, name, type, method, unmatched);
+ } else {
+ // both unmatched because of type mismatch
+ unmatchedGetMethods.put(name, method);
+ }
+ }
+ } else if (methodName.startsWith("set")) {
+ Method unmatched = unmatchedGetMethods.get(name);
+ if (unmatched == null) {
+ // set is first of the pair; put it into the unmatched map
unmatchedSetMethods.put(name, method);
+ } else {
+ // found the potential match
+ if (getType(unmatched).equals(type)) {
+ // method names and types match
+ unmatchedGetMethods.remove(name);
+ domainFieldHandler = new DomainFieldHandlerImpl(this, table,
+ numberOfFields++, name, type, unmatched, method);
+ } else {
+ // both unmatched because of type mismatch
+ unmatchedSetMethods.put(name, method);
+ }
}
}
- }
- if (domainFieldHandler != null) {
- // found matching methods
- // set up field name to number map
- String fieldName = domainFieldHandler.getName();
- fieldNameList.add(fieldName);
- fieldNameToNumber.put(domainFieldHandler.getName(), domainFieldHandler.getFieldNumber());
- // put field into either persistent or not persistent list
- if (domainFieldHandler.isPersistent()) {
- persistentFieldHandlers.add(domainFieldHandler);
- if (!domainFieldHandler.isPrimaryKey()) {
- nonPKFieldHandlers.add(domainFieldHandler);
+ if (domainFieldHandler != null) {
+ // found matching methods
+ // set up field name to number map
+ String fieldName = domainFieldHandler.getName();
+ fieldNameList.add(fieldName);
+ fieldNameToNumber.put(domainFieldHandler.getName(), domainFieldHandler.getFieldNumber());
+ // put field into either persistent or not persistent list
+ if (domainFieldHandler.isPersistent()) {
+ persistentFieldHandlers.add(domainFieldHandler);
+ if (!domainFieldHandler.isPrimaryKey()) {
+ nonPKFieldHandlers.add(domainFieldHandler);
+ }
+ }
+ if (domainFieldHandler.isPrimitive()) {
+ primitiveFieldHandlers.add(domainFieldHandler);
}
- }
- if (domainFieldHandler.isPrimitive()) {
- primitiveFieldHandlers.add(domainFieldHandler);
}
}
- }
- fieldNames = fieldNameList.toArray(new String[fieldNameList.size()]);
- // done with methods; if anything in unmatched we have a problem
- if ((!unmatchedGetMethods.isEmpty()) || (!unmatchedSetMethods.isEmpty())) {
- throw new ClusterJUserException(
- local.message("ERR_Unmatched_Methods",
- unmatchedGetMethods, unmatchedSetMethods));
- }
+ fieldNames = fieldNameList.toArray(new String[fieldNameList.size()]);
+ // done with methods; if anything in unmatched we have a problem
+ if ((!unmatchedGetMethods.isEmpty()) || (!unmatchedSetMethods.isEmpty())) {
+ throw new ClusterJUserException(
+ local.message("ERR_Unmatched_Methods",
+ unmatchedGetMethods, unmatchedSetMethods));
+ }
+ }
// Check that all index columnNames have corresponding fields
// indexes without fields will be unusable for query
for (IndexHandlerImpl indexHandler:indexHandlerImpls) {
@@ -214,6 +245,24 @@ public class DomainTypeHandlerImpl<T> ex
}
}
+ protected <O extends DynamicObject> String getTableNameForDynamicObject(Class<O> cls) {
+ DynamicObject dynamicObject;
+ String tableName;
+ try {
+ dynamicObject = cls.newInstance();
+ tableName = dynamicObject.tableName();
+ } catch (InstantiationException e) {
+ throw new ClusterJUserException(local.message("ERR_Dynamic_Object_Instantiation", cls.getName()), e);
+ } catch (IllegalAccessException e) {
+ throw new ClusterJUserException(local.message("ERR_Dynamic_Object_Illegal_Access", cls.getName()), e);
+ }
+ if (tableName == null) {
+ throw new ClusterJUserException(local.message("ERR_Dynamic_Object_Null_Table_Name",
+ cls.getName()));
+ }
+ return tableName;
+ }
+
/** Is this type supported? */
public boolean isSupportedType() {
// if unsupported, throw an exception
@@ -224,6 +273,8 @@ public class DomainTypeHandlerImpl<T> ex
throws IllegalArgumentException {
if (instance instanceof ValueHandler) {
return (ValueHandler)instance;
+ } else if (instance instanceof DynamicObject) {
+ return (ValueHandler)((DynamicObject)instance).delegate();
} else {
ValueHandler handler = (ValueHandler)
Proxy.getInvocationHandler(instance);
@@ -284,11 +335,17 @@ public class DomainTypeHandlerImpl<T> ex
}
public T newInstance() {
+ T instance;
try {
InvocationHandlerImpl<T> handler = new InvocationHandlerImpl<T>(this);
- T proxy = ctor.newInstance(new Object[] {handler});
- handler.setProxy(proxy);
- return proxy;
+ if (dynamic) {
+ instance = cls.newInstance();
+ ((DynamicObject)instance).delegate((DynamicObjectDelegate)handler);
+ } else {
+ instance = ctor.newInstance(new Object[] {handler});
+ handler.setProxy(instance);
+ }
+ return instance;
} catch (InstantiationException ex) {
throw new ClusterJException(
local.message("ERR_Create_Instance", cls.getName()), ex);
@@ -431,4 +488,9 @@ public class DomainTypeHandlerImpl<T> ex
throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
}
+ protected ColumnMetadata[] columnMetadata() {
+ ColumnMetadata[] result = new ColumnMetadata[numberOfFields];
+ return persistentFieldHandlers.toArray(result);
+ }
+
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java 2010-01-22 19:10:41 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java 2010-12-21 00:52:28 +0000
@@ -21,6 +21,8 @@ package com.mysql.clusterj.core.metadata
import com.mysql.clusterj.core.spi.ValueHandler;
import com.mysql.clusterj.core.spi.DomainTypeHandler;
import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.DynamicObjectDelegate;
import com.mysql.clusterj.core.CacheManager;
import com.mysql.clusterj.core.StateManager;
@@ -44,7 +46,7 @@ import java.util.HashMap;
import java.util.Map;
public class InvocationHandlerImpl<T> implements InvocationHandler,
- StateManager, ValueHandler {
+ StateManager, ValueHandler, DynamicObjectDelegate {
/** My message translator */
static final I18NHelper local = I18NHelper.getInstance(InvocationHandlerImpl.class);
@@ -441,4 +443,16 @@ public class InvocationHandlerImpl<T> im
properties[fieldNumber] = value;
}
+ public Object get(int columnNumber) {
+ return properties[columnNumber];
+ }
+
+ public void set(int columnNumber, Object value) {
+ properties[columnNumber] = value;
+ }
+
+ public ColumnMetadata[] columnMetadata() {
+ return domainTypeHandler.columnMetadata();
+ }
+
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java 2010-09-13 10:48:19 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java 2010-12-21 00:52:28 +0000
@@ -18,6 +18,8 @@
package com.mysql.clusterj.core.store;
+import com.mysql.clusterj.ColumnMetadata.Type;
+
/** Column metadata for ndb columns.
*
*/
@@ -39,6 +41,11 @@ public interface Column {
*/
public boolean isPrimaryKey();
+ /** Is this column a partition key column?
+ * @return true if this column is a partition key column
+ */
+ public boolean isPartitionKey();
+
/** Get the Charset name of the column. This is the value of the
* CHARACTER SET parameter in the column definition, or if not specified,
* the value of the DEFAULT CHARACTER SET parameter in the table definition.
@@ -53,42 +60,10 @@ public interface Column {
*/
public int getCharsetNumber();
- /** The store type of the column. This is mapped from the ndb column type
- * to the abstract type used in the store api.
+ /** For character columns, get the maximum length in bytes that can be stored
+ * in the column, excluding the prefix, after conversion via the charset.
*/
- public enum Type {
- Bigint,
- Bigunsigned,
- Binary,
- Bit,
- Blob,
- Char,
- Date,
- Datetime,
- Decimal,
- Decimalunsigned,
- Double,
- Float,
- Int,
- Longvarbinary,
- Longvarchar,
- Mediumint,
- Mediumunsigned,
- Olddecimal,
- Olddecimalunsigned,
- Smallint,
- Smallunsigned,
- Text,
- Time,
- Timestamp,
- Tinyint,
- Tinyunsigned,
- Undefined,
- Unsigned,
- Varbinary,
- Varchar,
- Year
- }
+ public int getLength();
/** For variable size columns, get the length of the prefix (one or two bytes)
* that specifies the length of the column data.
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties'
--- a/storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties 2010-09-22 18:34:38 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties 2010-12-21 00:52:28 +0000
@@ -109,3 +109,8 @@ cannot have a null parameter.
ERR_Query_Where_Must_Not_Be_Null:Query where must not be null.
ERR_Cannot_Set_Coordinated_Transaction_Id_After_Transaction_Begin:\
Cannot set coordinated transaction after transaction begin.
+ERR_Dynamic_Object_Instantiation:InstantiationException: \
+The dynamic class {0} must be static, public, and have a public constructor.
+ERR_Dynamic_Object_Illegal_Access:IllegalAccessException: \
+The dynamic class {0} must be static, public, and have a public constructor.
+ERR_Dynamic_Object_Null_Table_Name:The method {0}.tableName() must return a non-null table name.
=== added file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/DynamicObjectTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/DynamicObjectTest.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/DynamicObjectTest.java 2010-12-21 00:52:28 +0000
@@ -0,0 +1,232 @@
+/*
+ Copyright (C) 2009 Sun Microsystems Inc.
+ All rights reserved. Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package testsuite.clusterj;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.DynamicObject;
+import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.Query;
+import com.mysql.clusterj.ColumnMetadata.Type;
+import com.mysql.clusterj.query.QueryBuilder;
+import com.mysql.clusterj.query.QueryDomainType;
+
+public class DynamicObjectTest extends AbstractClusterJModelTest {
+
+ private static final String tablename = "t_basic";
+
+ private static final int NUMBER_TO_INSERT = 5;
+
+ private DynamicObject[] instances = new TBasic[NUMBER_TO_INSERT];
+
+ private DynamicObject tbasic;
+
+ private Object[] expectedTBasicNames = new Object[] {"id", "name", "age", "magic"};
+
+ private Object[] expectedTBasicTypes = new Object[] {Type.Int, Type.Varchar, Type.Int, Type.Int};
+
+ private Object[] expectedTBasicJavaTypes = new Object[] {Integer.class, String.class, Integer.class, Integer.class};
+
+ private Object[] expectedTBasicMaximumLengths = new Object[] {1, 32, 1, 1};
+
+ private Object[] expectedTBasicNumbers = new Object[] {0, 1, 2, 3};
+
+ private Object[] expectedTBasicIsPrimaryKeys = new Object[] {true, false, false, false};
+
+ private Object[] expectedTBasicIsPartitionKeys = new Object[] {true, false, false, false};
+
+ private Object[] expectedTBasicPrecisions = new Object[] {0, 0, 0, 0};
+
+ private Object[] expectedTBasicScales = new Object[] {0, 0, 0, 0};
+
+ private Object[] expectedTBasicNullables = new Object[] {false, true, true, false};
+
+ private Object[] expectedTBasicCharsetNames = new Object[] {null, "latin1", null, null};
+
+ @Override
+ public void localSetUp() {
+ createSessionFactory();
+ session = sessionFactory.getSession();
+ createDynamicInstances(TBasic.class, NUMBER_TO_INSERT);
+ tbasic = instances[0];
+ tx = session.currentTransaction();
+ int count = 0;
+ for (int i = 0; i < NUMBER_TO_INSERT; ++i) {
+ try {
+ session.deletePersistent(TBasic.class, i);
+ ++count;
+ } catch (Exception ex) {
+ // ignore exceptions -- might not be any instances to delete
+ }
+ }
+ addTearDownClasses(TBasic.class);
+ }
+
+ private <T extends DynamicObject> void createDynamicInstances(Class<T> dynamicClass, int numberToInsert) {
+ for (int i = 0; i < numberToInsert; ++i) {
+ DynamicObject instance = createInstance(dynamicClass, i);
+ instance.set(1, String.valueOf(i)); // name
+ instance.set(2, i); // age
+ instance.set(3, i); // magic
+ instances[i] = instance;
+ }
+ }
+
+ private <T> T createInstance(Class<T> cls, int i) {
+ T instance = session.newInstance(cls, i);
+ return instance;
+ }
+
+ public static class TBasic extends DynamicObject {
+ @Override
+ public String tableName() {
+ return tablename;
+ }
+ }
+
+ public void test() {
+ insert();
+ find();
+ lookup();
+ query();
+ badClass(DynamicObjectPrivate.class);
+ badClass(DynamicObjectProtectedConstructor.class);
+ badClass(DynamicObjectNonStatic.class);
+ badClass(DynamicObjectPrivateConstructor.class);
+ badClass(DynamicObjectNullTableName.class);
+ badClass(DynamicObjectTableDoesNotExist.class);
+ checkMetadata();
+ failOnError();
+ }
+ private void insert() {
+ session.makePersistent(instances);
+ }
+
+ private void find() {
+ TBasic instance = session.find(TBasic.class, 0);
+ validateInstance(instance);
+ }
+
+ private void lookup() {
+ QueryBuilder builder = session.getQueryBuilder();
+ QueryDomainType<TBasic> queryTBasic = builder.createQueryDefinition(TBasic.class);
+ queryTBasic.where(queryTBasic.get("magic").equal(queryTBasic.param("magic")));
+ Query<TBasic> query = session.createQuery(queryTBasic);
+ query.setParameter("magic", 1);
+ TBasic instance = query.getResultList().get(0);
+ validateInstance(instance);
+ }
+
+ private void query() {
+ QueryBuilder builder = session.getQueryBuilder();
+ QueryDomainType<TBasic> queryTBasic = builder.createQueryDefinition(TBasic.class);
+ queryTBasic.where(queryTBasic.get("name").equal(queryTBasic.param("name")));
+ Query<TBasic> query = session.createQuery(queryTBasic);
+ query.setParameter("name", "2");
+ TBasic instance = query.getResultList().get(0);
+ validateInstance(instance);
+ }
+
+ private void validateInstance(TBasic instance) {
+ int id = (Integer)instance.get(0);
+ errorIfNotEqual("validate name", String.valueOf(id), instance.get(1)); // name
+ errorIfNotEqual("validate age", id, instance.get(2)); // age
+ errorIfNotEqual("validate magic", id, instance.get(3)); // magic
+ }
+
+ private void badClass(Class<?> cls) {
+ try {
+ session.newInstance(cls);
+ } catch (ClusterJUserException e) {
+ // good catch
+ } catch (Throwable t) {
+ error(cls.getClass().getName() + " threw wrong exception: " + t.getMessage());
+ }
+ }
+
+ public static class DynamicObjectProtectedConstructor extends DynamicObject {
+ protected DynamicObjectProtectedConstructor() {}
+ @Override
+ public String tableName() {
+ return "DynamicObjectProtectedConstructor";
+ }
+ }
+
+ private static class DynamicObjectPrivate extends DynamicObject {
+ public DynamicObjectPrivate() {}
+ @Override
+ public String tableName() {
+ return "DynamicObjectProtectedConstructor";
+ }
+ }
+
+ public class DynamicObjectNonStatic extends DynamicObject {
+ public DynamicObjectNonStatic() {}
+ @Override
+ public String tableName() {
+ return "DynamicObjectProtectedConstructor";
+ }
+ }
+
+ public static class DynamicObjectPrivateConstructor extends DynamicObject {
+ private DynamicObjectPrivateConstructor() {}
+ @Override
+ public String tableName() {
+ return "DynamicObjectPrivateConstructor";
+ }
+ }
+
+ public static class DynamicObjectTableDoesNotExist extends DynamicObject {
+ private DynamicObjectTableDoesNotExist() {}
+ @Override
+ public String tableName() {
+ return "DynamicObjectTableDoesNotExist";
+ }
+ }
+
+ public static class DynamicObjectNullTableName extends DynamicObject {
+ public DynamicObjectNullTableName() {}
+ @Override
+ public String tableName() {
+ return null;
+ }
+ }
+
+ protected void checkMetadata() {
+ ColumnMetadata[] metadata = tbasic.columnMetadata();
+ for (int i = 0; i < metadata.length; ++i) {
+ errorIfNotEqual("t_basic column " + i + " name", expectedTBasicNames[i], metadata[i].name());
+ errorIfNotEqual("t_basic column " + i + " type", expectedTBasicTypes[i], metadata[i].type());
+ errorIfNotEqual("t_basic column " + i + " javaType", expectedTBasicJavaTypes[i], metadata[i].javaType());
+ errorIfNotEqual("t_basic column " + i + " maximumLength", expectedTBasicMaximumLengths[i], metadata[i].maximumLength());
+ errorIfNotEqual("t_basic column " + i + " charsetName", expectedTBasicCharsetNames [i], metadata[i].charsetName());
+ errorIfNotEqual("t_basic column " + i + " number", expectedTBasicNumbers[i], metadata[i].number());
+ errorIfNotEqual("t_basic column " + i + " isPrimaryKey", expectedTBasicIsPrimaryKeys[i], metadata[i].isPrimaryKey());
+ errorIfNotEqual("t_basic column " + i + " isPartitionKey", expectedTBasicIsPartitionKeys[i], metadata[i].isPartitionKey());
+ errorIfNotEqual("t_basic column " + i + " precision", expectedTBasicPrecisions[i], metadata[i].precision());
+ errorIfNotEqual("t_basic column " + i + " scale", expectedTBasicScales[i], metadata[i].scale());
+ errorIfNotEqual("t_basic column " + i + " nullable", expectedTBasicNullables[i], metadata[i].nullable());
+ }
+ }
+
+
+}
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java 2010-09-13 10:48:19 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java 2010-12-21 00:52:28 +0000
@@ -24,6 +24,8 @@ import com.mysql.ndbjtie.ndbapi.NdbDicti
import com.mysql.clusterj.ClusterJDatastoreException;
import com.mysql.clusterj.ClusterJFatalInternalException;
+import com.mysql.clusterj.ColumnMetadata.Type;
+
import com.mysql.clusterj.core.store.Column;
import com.mysql.clusterj.core.util.I18NHelper;
@@ -56,7 +58,7 @@ class ColumnImpl implements Column {
private int charsetNumber = 0;
/** The ndb column type for the column */
- private Column.Type columnType;
+ private Type columnType;
/** The prefix length for variable size columns */
private int prefixLength = -1;
@@ -76,6 +78,9 @@ class ColumnImpl implements Column {
/** Is this column a primary key column? */
private boolean primaryKey;
+ /** Is this column a partition key column? */
+ private boolean partitionKey;
+
private int length;
private int inlineSize;
@@ -95,6 +100,7 @@ class ColumnImpl implements Column {
int ndbType = ndbColumn.getType();
this.columnType = convertType(ndbType);
this.primaryKey = ndbColumn.getPrimaryKey();
+ this.partitionKey = ndbColumn.getPartitionKey();
this.nullable = ndbColumn.getNullable();
this.length = ndbColumn.getLength();
this.inlineSize = ndbColumn.getInlineSize();
@@ -235,43 +241,43 @@ class ColumnImpl implements Column {
}
}
- public Column.Type getType() {
+ public Type getType() {
return columnType;
}
private Type convertType(int type) {
switch (type) {
- case ColumnConst.Type.Bigint: return Column.Type.Bigint;
- case ColumnConst.Type.Bigunsigned: return Column.Type.Bigunsigned;
- case ColumnConst.Type.Binary: return Column.Type.Binary;
- case ColumnConst.Type.Bit: return Column.Type.Bit;
- case ColumnConst.Type.Blob: return Column.Type.Blob;
- case ColumnConst.Type.Char: return Column.Type.Char;
- case ColumnConst.Type.Date: return Column.Type.Date;
- case ColumnConst.Type.Datetime: return Column.Type.Datetime;
- case ColumnConst.Type.Decimal: return Column.Type.Decimal;
- case ColumnConst.Type.Decimalunsigned: return Column.Type.Decimalunsigned;
- case ColumnConst.Type.Double: return Column.Type.Double;
- case ColumnConst.Type.Float: return Column.Type.Float;
- case ColumnConst.Type.Int: return Column.Type.Int;
- case ColumnConst.Type.Longvarbinary: return Column.Type.Longvarbinary;
- case ColumnConst.Type.Longvarchar: return Column.Type.Longvarchar;
- case ColumnConst.Type.Mediumint: return Column.Type.Mediumint;
- case ColumnConst.Type.Mediumunsigned: return Column.Type.Mediumunsigned;
- case ColumnConst.Type.Olddecimal: return Column.Type.Olddecimal;
- case ColumnConst.Type.Olddecimalunsigned: return Column.Type.Olddecimalunsigned;
- case ColumnConst.Type.Smallint: return Column.Type.Smallint;
- case ColumnConst.Type.Smallunsigned: return Column.Type.Smallunsigned;
- case ColumnConst.Type.Text: return Column.Type.Text;
- case ColumnConst.Type.Time: return Column.Type.Time;
- case ColumnConst.Type.Timestamp: return Column.Type.Timestamp;
- case ColumnConst.Type.Tinyint: return Column.Type.Tinyint;
- case ColumnConst.Type.Tinyunsigned: return Column.Type.Tinyunsigned;
- case ColumnConst.Type.Undefined: return Column.Type.Undefined;
- case ColumnConst.Type.Unsigned: return Column.Type.Unsigned;
- case ColumnConst.Type.Varbinary: return Column.Type.Varbinary;
- case ColumnConst.Type.Varchar: return Column.Type.Varchar;
- case ColumnConst.Type.Year: return Column.Type.Year;
+ case ColumnConst.Type.Bigint: return Type.Bigint;
+ case ColumnConst.Type.Bigunsigned: return Type.Bigunsigned;
+ case ColumnConst.Type.Binary: return Type.Binary;
+ case ColumnConst.Type.Bit: return Type.Bit;
+ case ColumnConst.Type.Blob: return Type.Blob;
+ case ColumnConst.Type.Char: return Type.Char;
+ case ColumnConst.Type.Date: return Type.Date;
+ case ColumnConst.Type.Datetime: return Type.Datetime;
+ case ColumnConst.Type.Decimal: return Type.Decimal;
+ case ColumnConst.Type.Decimalunsigned: return Type.Decimalunsigned;
+ case ColumnConst.Type.Double: return Type.Double;
+ case ColumnConst.Type.Float: return Type.Float;
+ case ColumnConst.Type.Int: return Type.Int;
+ case ColumnConst.Type.Longvarbinary: return Type.Longvarbinary;
+ case ColumnConst.Type.Longvarchar: return Type.Longvarchar;
+ case ColumnConst.Type.Mediumint: return Type.Mediumint;
+ case ColumnConst.Type.Mediumunsigned: return Type.Mediumunsigned;
+ case ColumnConst.Type.Olddecimal: return Type.Olddecimal;
+ case ColumnConst.Type.Olddecimalunsigned: return Type.Olddecimalunsigned;
+ case ColumnConst.Type.Smallint: return Type.Smallint;
+ case ColumnConst.Type.Smallunsigned: return Type.Smallunsigned;
+ case ColumnConst.Type.Text: return Type.Text;
+ case ColumnConst.Type.Time: return Type.Time;
+ case ColumnConst.Type.Timestamp: return Type.Timestamp;
+ case ColumnConst.Type.Tinyint: return Type.Tinyint;
+ case ColumnConst.Type.Tinyunsigned: return Type.Tinyunsigned;
+ case ColumnConst.Type.Undefined: return Type.Undefined;
+ case ColumnConst.Type.Unsigned: return Type.Unsigned;
+ case ColumnConst.Type.Varbinary: return Type.Varbinary;
+ case ColumnConst.Type.Varchar: return Type.Varchar;
+ case ColumnConst.Type.Year: return Type.Year;
default: throw new ClusterJFatalInternalException(
local.message("ERR_Unknown_Column_Type",
tableName, columnName, type));
@@ -290,6 +296,14 @@ class ColumnImpl implements Column {
return primaryKey;
}
+ public boolean isPartitionKey() {
+ return partitionKey;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
public int getPrefixLength() {
if (prefixLength != -1) {
return prefixLength;
=== added file 'storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/DynamicObjectTest.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/DynamicObjectTest.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/DynamicObjectTest.java 2010-12-21 00:52:28 +0000
@@ -0,0 +1,23 @@
+/*
+ Copyright (C) 2009 Sun Microsystems Inc.
+ All rights reserved. Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package testsuite.clusterj.tie;
+
+public class DynamicObjectTest extends testsuite.clusterj.DynamicObjectTest {
+
+}
Attachment: [text/bzr-bundle] bzr/craig.russell@oracle.com-20101221005228-5zrdu3fqziu6w4sk.bundle
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.1 branch (Craig.Russell:4028 to 4029) | Craig L Russell | 21 Dec |