Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add method 'toChar[class java.lang.Object]' in class class org.apach… #3752

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3575,6 +3575,12 @@ public static char toChar(String s) {
return s.charAt(0);
}

public static char toChar(Object o){
return o instanceof Character ? (Character) o
: o instanceof CharSequence ? ((CharSequence) o).charAt(0)
: (Character) cannotConvert(o, char.class);
}

public static Character toCharBoxed(String s) {
return s.charAt(0);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.apache.calcite.runtime.inmemory;

import org.apache.calcite.adapter.enumerable.EnumerableConvention;
import org.apache.calcite.adapter.enumerable.EnumerableRel;
import org.apache.calcite.adapter.enumerable.EnumerableRelImplementor;
import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
import org.apache.calcite.adapter.enumerable.JavaRowFormat;
import org.apache.calcite.adapter.enumerable.PhysType;
import org.apache.calcite.adapter.enumerable.PhysTypeImpl;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.linq4j.tree.BlockBuilder;
import org.apache.calcite.linq4j.tree.ConstantExpression;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.MethodCallExpression;
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.linq4j.tree.Statement;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.prepare.Prepare;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.schema.ModifiableTable;
import org.apache.calcite.util.BuiltInMethod;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Type;

public class InMemoryEnumerableTableModify extends TableModify implements EnumerableRel {
private final int rowCount;

public InMemoryEnumerableTableModify(RelOptCluster cluster, RelTraitSet traits, RelOptTable table, Prepare.CatalogReader catalogReader, RelNode child, Operation operation, @Nullable List<String> updateColumnList, @Nullable List<RexNode> sourceExpressionList, boolean flattened) {
super(cluster, traits, table, catalogReader, child, operation, updateColumnList, sourceExpressionList, flattened);
assert child.getConvention() instanceof EnumerableConvention;
assert getConvention() instanceof EnumerableConvention;
final ModifiableTable modifiableTable = table.unwrap(ModifiableTable.class);
if (modifiableTable == null) {
throw new AssertionError();
}
// custom part
RelDataType rowType = table.getRowType();
rowCount = rowType.getFieldCount();
}

@Override
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
return new InMemoryEnumerableTableModify(getCluster(), traitSet, getTable(), getCatalogReader(), sole(inputs), getOperation(), getUpdateColumnList(), getSourceExpressionList(), isFlattened());
}

@Override
public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
final BlockBuilder builder = new BlockBuilder();
final Result result = implementor.visitChild(this, 0, (EnumerableRel)getInput(), pref);
// collection parameter
final ParameterExpression collectionParameter = Expressions.parameter(Collection.class, builder.newName("collection"));
final Expression expression = table.getExpression(ModifiableTable.class);
builder.add(Expressions.declare(Modifier.FINAL, collectionParameter, Expressions.call(expression, BuiltInMethod.MODIFIABLE_TABLE_GET_MODIFIABLE_COLLECTION.method)));
final JavaTypeFactory typeFactory = (JavaTypeFactory)getCluster().getTypeFactory();
final JavaRowFormat format = EnumerableTableScan.deduceFormat(table);
PhysType physType_ = PhysTypeImpl.of(typeFactory, table.getRowType(), format);
List<Expression> expressionList = new ArrayList<>();
final PhysType childPhysType = result.physType;
final ParameterExpression o_ = Expressions.parameter(childPhysType.getJavaRowType(), "o");
for (int i = 0; i < rowCount; i++) {
Type javaFieldType = physType_.getJavaFieldType(i);
Expression fieldRef = childPhysType.fieldReference(o_, i, javaFieldType);
expressionList.add(fieldRef);
}
// update column parameter
List<String> updateColumnList = getUpdateColumnList();
ConstantExpression updateColumnExpression = Expressions.constant(updateColumnList, List.class);
Expression updateColumnListParameter = builder.append("updateColumnList", updateColumnExpression);
// source expression parameter
List<RexNode> rawSourceExpressionList = getSourceExpressionList();
List<String> stringSourceExpressionList = rawSourceExpressionList.stream().map(element -> element.toString()).collect(Collectors.toList());
ConstantExpression sourceExpressionExpression = Expressions.constant(stringSourceExpressionList, List.class);
Expression sourceExpressionListParameter = builder.append("sourceExpressionList", sourceExpressionExpression);
// update method statement
try {
Method func = InMemoryOperationHandler.class.getMethod("update", Collection.class, List.class, List.class);
MethodCallExpression methodCallExpression = Expressions.call(func, collectionParameter, updateColumnListParameter, sourceExpressionListParameter);
Statement statement = Expressions.statement(methodCallExpression);
builder.add(statement);
} catch (Exception e) {
e.printStackTrace();
}
// return statement
builder.add(Expressions.return_(null, Expressions.call(BuiltInMethod.SINGLETON_ENUMERABLE.method, Expressions.constant(0, Integer.class))));
// compile
final PhysType physType = PhysTypeImpl.of(implementor.getTypeFactory(), getRowType(), JavaRowFormat.ARRAY);
return implementor.result(physType, builder.toBlock());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.apache.calcite.runtime.inmemory;

import org.apache.calcite.adapter.enumerable.EnumerableConvention;
import org.apache.calcite.plan.Convention;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.rel.logical.LogicalTableModify;
import org.apache.calcite.schema.ModifiableTable;
import org.checkerframework.checker.nullness.qual.Nullable;

public class InMemoryEnumerableTableModifyRule extends ConverterRule {
public static final Config DEFAULT_CONFIG = Config.INSTANCE
.withConversion(LogicalTableModify.class, Convention.NONE,
EnumerableConvention.INSTANCE, "InMemoryEnumerableTableModificationRule")
.withRuleFactory(InMemoryEnumerableTableModifyRule::new);

protected InMemoryEnumerableTableModifyRule(Config config) {
super(config);
}

@Override
public @Nullable RelNode convert(RelNode rel) {
final TableModify modify = (TableModify) rel;
final ModifiableTable modifiableTable =
modify.getTable().unwrap(ModifiableTable.class);
if (modifiableTable == null) {
return null;
}
final RelTraitSet traitSet =
modify.getTraitSet().replace(EnumerableConvention.INSTANCE);
return new InMemoryEnumerableTableModify(
modify.getCluster(), traitSet,
modify.getTable(),
modify.getCatalogReader(),
convert(modify.getInput(), traitSet),
modify.getOperation(),
modify.getUpdateColumnList(),
modify.getSourceExpressionList(),
modify.isFlattened());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.apache.calcite.runtime.inmemory;

import java.util.List;
import java.lang.reflect.Field;
import java.util.Collection;

public class InMemoryOperationHandler {
public static void update(Collection<?> collection, List<String> updateColumnList, List<String> sourceExpressionList) {
int size = collection.size();
List<?> list = (List<?>)collection;
for (int index = 0; index < size; index++) {
Object element = list.get(index);
Class<?> clazz = element.getClass();
String updateColumn = updateColumnList.get(index);
String sourceExpression = sourceExpressionList.get(index);
int targetExpression = Integer.valueOf(sourceExpression);
try {
Field field = clazz.getField(updateColumn);
field.set(element, targetExpression);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.apache.calcite.runtime.inmemory;

import org.apache.calcite.schema.Table;
import org.apache.calcite.schema.impl.AbstractSchema;
import java.util.Map;
import java.util.Map.Entry;
import java.util.HashMap;
import com.google.common.collect.ImmutableMap.Builder;

public final class InMemorySchema extends AbstractSchema {
private final Map<String, InMemoryTable<?>> inMemoryTableMap = new HashMap<>();

public final void addTable(final String tableName, final InMemoryTable<?> tableObject) {
inMemoryTableMap.put(tableName, tableObject);
}

@Override
protected final Map<String, Table> getTableMap() {
Builder tableMap = new Builder<String, Table>();
for (Entry<String, InMemoryTable<?>> tableEntry : inMemoryTableMap.entrySet()) {
String tableName = tableEntry.getKey();
InMemoryTable<?> inMemoryTable = tableEntry.getValue();
if (null != tableName && null != inMemoryTable) {
tableMap.put(tableName, inMemoryTable);
}
}
return tableMap.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.apache.calcite.runtime.inmemory;

import java.util.List;
import org.apache.calcite.adapter.enumerable.EnumerableTableModifyRule;
import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
import org.apache.calcite.adapter.java.AbstractQueryableTable;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.linq4j.Enumerator;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.Queryable;
import org.apache.calcite.plan.Convention;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.RelOptTable.ToRelContext;
import org.apache.calcite.prepare.Prepare.CatalogReader;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.rel.core.TableModify.Operation;
import org.apache.calcite.rel.logical.LogicalTableModify;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.schema.ModifiableTable;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.TranslatableTable;
import org.apache.calcite.schema.impl.AbstractTableQueryable;
import org.apache.calcite.rel.convert.ConverterRule.Config;

public final class InMemoryTable<T> extends AbstractQueryableTable implements ModifiableTable, TranslatableTable {
private final List<? extends T> data;

public InMemoryTable(final Class<T> clazz, final List<? extends T> data) {
super(clazz);
this.data = data;
}

@SuppressWarnings("unchecked")
@Override
public final Queryable<T> asQueryable(final QueryProvider queryProvider, final SchemaPlus schema, final String tableName) {
return new AbstractTableQueryable<T>(queryProvider, schema, this, tableName) {
@Override
public Enumerator<T> enumerator() {
return Linq4j.enumerator(data);
}
};
}

@Override
public final RelDataType getRowType(final RelDataTypeFactory typeFactory) {
return ((JavaTypeFactory)typeFactory).createType(elementType);
}

@Override
public final List<? extends T> getModifiableCollection() {
return data;
}

@Override
public final TableModify toModificationRel(final RelOptCluster cluster, final RelOptTable table, final CatalogReader catalogReader, final RelNode child, final Operation operation, final List<String> updateColumnList, final List<RexNode> sourceExpressionList, final boolean flattened) {
return new LogicalTableModify(cluster, cluster.traitSetOf(Convention.NONE), table, catalogReader, child, operation, updateColumnList, sourceExpressionList, flattened);
}

@Override
public RelNode toRel(ToRelContext context, RelOptTable relOptTable) {
// use custom table modify rule
RelOptCluster cluster = context.getCluster();
RelOptPlanner planner = cluster.getPlanner();
List<RelOptRule> rules = planner.getRules();
for (RelOptRule rule : rules) {
if(rule instanceof EnumerableTableModifyRule){
planner.removeRule(rule);
Config config= InMemoryEnumerableTableModifyRule.DEFAULT_CONFIG;
rule = new InMemoryEnumerableTableModifyRule(config);
planner.addRule(rule);
}
}
// default table scan
EnumerableTableScan relNode = EnumerableTableScan.create(cluster, relOptTable);
return relNode;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.apache.calcite.runtime.inmemory;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.calcite.schema.SchemaPlus;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static java.sql.DriverManager.getConnection;

final class PrimitiveTest {
@Test
void testUpdate() throws Exception {
// set up schema & table
InMemorySchema schema = new InMemorySchema();
PrimitiveType table = new PrimitiveType(0, '\u0000');
List<PrimitiveType> primitivetypesCollection = new ArrayList<>();
primitivetypesCollection.add(table);
InMemoryTable<PrimitiveType> primitivetypesTable = new InMemoryTable<>(PrimitiveType.class, primitivetypesCollection);
schema.addTable("PRIMITIVE", primitivetypesTable);
// connection
Connection connection = getConnection("jdbc:calcite:");
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
// add schema
SchemaPlus rootSchema = calciteConnection.getRootSchema();
rootSchema.add("DUMMY", schema);
// set-up statement
Statement statement = calciteConnection.createStatement();
try {
// update query
statement.executeUpdate("UPDATE DUMMY.PRIMITIVE SET INT_=1");
// toChar(Object) found
assertEquals(1,table.INT_);
} catch (Exception e) {
e.printStackTrace(); // stack trace in stdout
// toChar(Object) not found ?
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
assertTrue(sStackTrace.contains("NoSuchMethodException: org.apache.calcite.runtime.SqlFunctions.toChar(java.lang.Object)"));
} finally {
// close
statement.close();
calciteConnection.close();
}
}

private void assetEquals(int i, int iNT_) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'assetEquals'");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.apache.calcite.runtime.inmemory;

import java.util.ArrayList;
import java.util.List;

public final class PrimitiveType {
public int INT_;
public char CHAR_;

public PrimitiveType(final int int_, final char char_) {
INT_ = int_;
CHAR_ = char_;
}

@Override
public final String toString() {
return INT_+";"+CHAR_;
}

@Override
public final boolean equals(final Object other) {
return null != other && hashCode() == other.hashCode();
}

@Override
public final int hashCode() {
List<Object> set = new ArrayList<>();
set.add(INT_);
set.add(CHAR_);
return set.hashCode();
}
}
Loading