Repository: phoenix Updated Branches: refs/heads/calcite 448920235 -> 3ad0e7700
PHOENIX-3690 Support declaring default values in Phoenix-Calcite(Rajeshbabu) Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/3ad0e770 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/3ad0e770 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/3ad0e770 Branch: refs/heads/calcite Commit: 3ad0e7700103d38b907934debd3be61b60dc498d Parents: 4489202 Author: Rajeshbabu Chintaguntla <[email protected]> Authored: Sat Feb 25 11:48:51 2017 +0530 Committer: Rajeshbabu Chintaguntla <[email protected]> Committed: Sat Feb 25 11:48:51 2017 +0530 ---------------------------------------------------------------------- .../src/main/codegen/includes/parserImpls.ftl | 7 ++- .../apache/calcite/sql/SqlColumnDefNode.java | 6 +- .../apache/phoenix/calcite/CalciteUtils.java | 47 ++++++++++++++++ .../phoenix/calcite/PhoenixPrepareImpl.java | 27 +++++---- .../apache/phoenix/calcite/PhoenixSchema.java | 22 ++++++-- .../apache/phoenix/calcite/PhoenixTable.java | 58 +++++++++++++++++++- .../jdbc/PhoenixCalciteEmbeddedDriver.java | 6 +- .../phoenix/calcite/ToExpressionTest.java | 2 +- 8 files changed, 151 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/codegen/includes/parserImpls.ftl ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/codegen/includes/parserImpls.ftl b/phoenix-core/src/main/codegen/includes/parserImpls.ftl index defed7d..0e04048 100644 --- a/phoenix-core/src/main/codegen/includes/parserImpls.ftl +++ b/phoenix-core/src/main/codegen/includes/parserImpls.ftl @@ -886,6 +886,7 @@ SqlColumnDefNode ColumnDef() : boolean isPk = false; SortOrder sortOrder = SortOrder.getDefault(); boolean isRowTimestamp = false; + SqlNode expression = null; SqlParserPos pos; } { @@ -899,6 +900,10 @@ SqlColumnDefNode ColumnDef() : {isNull = true;} ] [ + <DEFAULT_KW> + expression = Expression(ExprContext.ACCEPT_NONQUERY) + ] + [ <PRIMARY> <KEY> {isPk = true;} ] @@ -915,7 +920,7 @@ SqlColumnDefNode ColumnDef() : ] { pos = columnName.getParserPosition().plus(getPos()); - return new SqlColumnDefNode(pos, columnName, dataType, isNull, isPk, sortOrder, null, isRowTimestamp); + return new SqlColumnDefNode(pos, columnName, dataType, isNull, isPk, sortOrder, expression, isRowTimestamp); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/calcite/sql/SqlColumnDefNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/calcite/sql/SqlColumnDefNode.java b/phoenix-core/src/main/java/org/apache/calcite/sql/SqlColumnDefNode.java index c65c28b..af1f19f 100644 --- a/phoenix-core/src/main/java/org/apache/calcite/sql/SqlColumnDefNode.java +++ b/phoenix-core/src/main/java/org/apache/calcite/sql/SqlColumnDefNode.java @@ -30,6 +30,7 @@ import org.apache.phoenix.schema.SortOrder; public class SqlColumnDefNode extends SqlNode{ public final ColumnDef columnDef; + public final SqlNode defaultValueExp; public SqlColumnDefNode( SqlParserPos pos, @@ -38,7 +39,7 @@ public class SqlColumnDefNode extends SqlNode{ Boolean isNullable, boolean isPk, SortOrder sortOrder, - String expressionStr, + SqlNode defaultValueExp, boolean isRowTimestamp) { super(pos); final ColumnName name; @@ -50,7 +51,8 @@ public class SqlColumnDefNode extends SqlNode{ this.columnDef = new ColumnDef(name, dataType.typeName, dataType.isArray, dataType.arraySize, isNullable, dataType.maxLength, dataType.scale, isPk, - sortOrder, expressionStr, isRowTimestamp); + sortOrder, null, isRowTimestamp); + this.defaultValueExp = defaultValueExp; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java index d4092ec..1b6937b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java @@ -24,6 +24,7 @@ import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.core.Project; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; +import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexCorrelVariable; import org.apache.calcite.rex.RexDynamicParam; @@ -57,6 +58,7 @@ import org.apache.calcite.util.Util; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.calcite.rel.PhoenixRelImplementor; +import org.apache.phoenix.compile.ExpressionCompiler; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.expression.AndExpression; import org.apache.phoenix.expression.CoerceExpression; @@ -123,12 +125,17 @@ import org.apache.phoenix.expression.function.SumAggregateFunction; import org.apache.phoenix.expression.function.TrimFunction; import org.apache.phoenix.expression.function.UDFExpression; import org.apache.phoenix.expression.function.UpperFunction; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.expression.function.WeekFunction; import org.apache.phoenix.expression.function.YearFunction; import org.apache.phoenix.parse.FunctionParseNode; +import org.apache.phoenix.parse.ParseNode; +import org.apache.phoenix.parse.SQLParser; import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunctionInfo; import org.apache.phoenix.parse.JoinTableNode.JoinType; import org.apache.phoenix.parse.SequenceValueParseNode; +import org.apache.phoenix.schema.PColumn; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.SortOrder; import org.apache.phoenix.schema.TypeMismatchException; @@ -1277,4 +1284,44 @@ public class CalciteUtils { } return root; } + + public static Expression parseExpressionFromStr(String expressionStr, PhoenixConnection pc) { + StatementContext context = + new StatementContext(new PhoenixStatement(pc)); + ExpressionCompiler compiler = new ExpressionCompiler(context); + ParseNode defaultParseNode; + try { + defaultParseNode = new SQLParser(expressionStr).parseExpression(); + } catch (SQLException e) { + throw new RuntimeException("Parsing default value failed." + expressionStr); + } + Expression defaultExpression; + try { + defaultExpression = defaultParseNode.accept(compiler); + } catch (SQLException e) { + throw new RuntimeException("Parsing default value failed." + expressionStr); + } + return defaultExpression; + }; + + public static RexNode convertColumnExpressionToLiteral(PColumn column, + Expression defaultExpression, RelDataTypeFactory typeFactory, RexBuilder rexBuilder) { + ImmutableBytesWritable key = new ImmutableBytesWritable(); + defaultExpression.evaluate(null, key); + column.getDataType().coerceBytes(key, null, + defaultExpression.getDataType(), + defaultExpression.getMaxLength(), defaultExpression.getScale(), + defaultExpression.getSortOrder(), + column.getMaxLength(), column.getScale(), + column.getSortOrder()); + Object object = + defaultExpression.getDataType().toObject(key, + defaultExpression.getSortOrder(), defaultExpression.getMaxLength(), + defaultExpression.getScale()); + RelDataType pDataTypeToRelDataType = + CalciteUtils.pDataTypeToRelDataType(typeFactory, + defaultExpression.getDataType(), defaultExpression.getMaxLength(), + defaultExpression.getScale(), column.getArraySize()); + return rexBuilder.makeLiteral((Comparable)object, pDataTypeToRelDataType,true); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixPrepareImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixPrepareImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixPrepareImpl.java index 2daa44e..daa5ad8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixPrepareImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixPrepareImpl.java @@ -277,10 +277,7 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl { name = TableName.create(table.tableName.names.get(0), table.tableName.names.get(1)); } final ListMultimap<String, Pair<String, Object>> props = convertOptions(table.tableOptions); - final List<ColumnDef> columnDefs = Lists.newArrayList(); - for (SqlNode columnDef : table.columnDefs) { - columnDefs.add(((SqlColumnDefNode) columnDef).columnDef); - } + final List<ColumnDef> columnDefs = getColumnDefs(table.columnDefs); final PrimaryKeyConstraint pkConstraint; if (table.pkConstraint == null) { pkConstraint = null; @@ -440,12 +437,7 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl { } final NamedTableNode namedTable = NamedTableNode.create(name); if(alterTable.newColumnDefs != null || alterTable.tableOptions != null) { - final List<ColumnDef> columnDefs = Lists.newArrayList(); - if(alterTable.newColumnDefs != null) { - for (SqlNode columnDef : alterTable.newColumnDefs) { - columnDefs.add(((SqlColumnDefNode) columnDef).columnDef); - } - } + final List<ColumnDef> columnDefs = getColumnDefs(alterTable.newColumnDefs); boolean ifNotExists = false; if(alterTable.ifNotExists != null) { ifNotExists = alterTable.ifNotExists.booleanValue(); @@ -650,6 +642,21 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl { } } + public List<ColumnDef> getColumnDefs(SqlNodeList sqlColumnDefs) + throws SQLException { + List<ColumnDef> columnDefs = new ArrayList<ColumnDef>(sqlColumnDefs.size()); + for(SqlNode columnDef : sqlColumnDefs) { + SqlColumnDefNode columnDefNode = (SqlColumnDefNode) columnDef; + if(columnDefNode.defaultValueExp!=null) { + ParseNode defaultValueNode= convertSqlNodeToParseNode(columnDefNode.defaultValueExp); + columnDefs.add(new ColumnDef(columnDefNode.columnDef, defaultValueNode.toString())); + } else { + columnDefs.add(columnDefNode.columnDef); + } + } + return columnDefs; + } + private static ParseNode convertSqlNodeToParseNode(SqlNode sqlNode) throws SQLException { if (sqlNode == null) { return null; http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java index 73ad98a..d88f226 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java @@ -87,7 +87,6 @@ public class PhoenixSchema implements Schema { protected final SchemaPlus parentSchema; protected final MetaDataClient client; protected final SequenceManager sequenceManager; - protected final Map<String, Schema> subSchemas; protected final Map<String, Table> tables; protected final Map<String, Function> views; @@ -96,7 +95,7 @@ public class PhoenixSchema implements Schema { private final static Function listJarsFunction = TableFunctionImpl .create(ListJarsTable.LIST_JARS_TABLE_METHOD); private final Multimap<String, Function> builtinFunctions = ArrayListMultimap.create(); - + private RelDataTypeFactory typeFactory; protected PhoenixSchema(String name, String schemaName, SchemaPlus parentSchema, PhoenixConnection pc) { @@ -117,7 +116,12 @@ public class PhoenixSchema implements Schema { throw new RuntimeException(e); } registerBuiltinFunctions(); + } + protected PhoenixSchema(String name, String schemaName, + SchemaPlus parentSchema, PhoenixConnection pc, RelDataTypeFactory typeFactory) { + this(name, schemaName, parentSchema, pc); + this.setTypeFactory(typeFactory); } private static Schema create(SchemaPlus parentSchema, @@ -310,7 +314,7 @@ public class PhoenixSchema implements Schema { TableRef tableRef = tables.get(0); if (!isView(tableRef.getTable())) { tableRef = fixTableMultiTenancy(tableRef); - table = new PhoenixTable(pc, tableRef); + table = new PhoenixTable(pc, tableRef, getTypeFactory()); } } catch (TableNotFoundException e) { } catch (SQLException e) { @@ -410,7 +414,7 @@ public class PhoenixSchema implements Schema { if (getTable(name) != null || !getFunctions(name).isEmpty()) { return null; } - schema = new PhoenixSchema(name, name, parentSchema.getSubSchema(this.name), pc); + schema = new PhoenixSchema(name, name, parentSchema.getSubSchema(this.name), pc, typeFactory); subSchemas.put(name, schema); return schema; } @@ -483,7 +487,7 @@ public class PhoenixSchema implements Schema { private void addMaterialization(TableRef indexTableRef, List<String> path, CalciteSchema calciteSchema) throws SQLException { indexTableRef = fixTableMultiTenancy(indexTableRef); - final PhoenixTable table = new PhoenixTable(pc, indexTableRef); + final PhoenixTable table = new PhoenixTable(pc, indexTableRef, getTypeFactory()); final PTable index = indexTableRef.getTable(); tables.put(index.getTableName().getString(), table); StringBuffer sb = new StringBuffer(); @@ -536,6 +540,14 @@ public class PhoenixSchema implements Schema { return new PhoenixSequence(schemaName, name, pc); } + public RelDataTypeFactory getTypeFactory() { + return typeFactory; + } + + public void setTypeFactory(RelDataTypeFactory typeFactory) { + this.typeFactory = typeFactory; + } + /** Schema factory that creates a * {@link org.apache.phoenix.calcite.PhoenixSchema}. * This allows you to create a Phoenix schema inside a model.json file. http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java index f3d44eb..b29d860 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java @@ -16,24 +16,34 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeField; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexNode; import org.apache.calcite.schema.CustomColumnResolvingTable; import org.apache.calcite.schema.Statistic; import org.apache.calcite.schema.TranslatableTable; +import org.apache.calcite.schema.Wrapper; import org.apache.calcite.schema.impl.AbstractTable; +import org.apache.calcite.sql2rel.InitializerExpressionFactory; +import org.apache.calcite.sql2rel.NullInitializerExpressionFactory; import org.apache.calcite.util.ImmutableBitSet; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.calcite.rel.PhoenixTableScan; import org.apache.phoenix.compile.ColumnResolver; +import org.apache.phoenix.compile.ExpressionCompiler; import org.apache.phoenix.compile.FromCompiler; import org.apache.phoenix.compile.SequenceManager; import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.expression.Expression; import org.apache.phoenix.iterate.BaseResultIterators; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.parse.ColumnDef; import org.apache.phoenix.parse.NamedTableNode; +import org.apache.phoenix.parse.ParseNode; +import org.apache.phoenix.parse.SQLParser; import org.apache.phoenix.parse.TableName; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; @@ -45,6 +55,7 @@ import org.apache.phoenix.schema.PTable.IndexType; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.stats.StatisticsUtil; import org.apache.phoenix.util.SchemaUtil; + import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -54,15 +65,17 @@ import com.google.common.collect.Lists; * Phoenix. */ public class PhoenixTable extends AbstractTable - implements TranslatableTable, CustomColumnResolvingTable { + implements TranslatableTable, CustomColumnResolvingTable, Wrapper { public final TableMapping tableMapping; public final ImmutableBitSet pkBitSet; public final RelCollation collation; public final long byteCount; public final long rowCount; public final PhoenixConnection pc; + public final RelDataTypeFactory typeFactory; + public final InitializerExpressionFactory initializerExpressionFactory; - public PhoenixTable(PhoenixConnection pc, TableRef tableRef) throws SQLException { + public PhoenixTable(PhoenixConnection pc, TableRef tableRef, final RelDataTypeFactory typeFactory) throws SQLException { this.pc = Preconditions.checkNotNull(pc); PTable pTable = tableRef.getTable(); TableRef dataTable = null; @@ -127,8 +140,12 @@ public class PhoenixTable extends AbstractTable } catch (SQLException | IOException e) { throw new RuntimeException(e); } + this.typeFactory = typeFactory; + this.initializerExpressionFactory = + this.typeFactory == null ? null : new PhoenixTableInitializerExpressionFactory( + typeFactory, pc, tableMapping); } - + public List<PColumn> getColumns() { return tableMapping.getMappedColumns(); } @@ -183,4 +200,39 @@ public class PhoenixTable extends AbstractTable RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) { return tableMapping.resolveColumn(rowType, typeFactory, names); } + + @Override public <C> C unwrap(Class<C> aClass) { + if (aClass.isInstance(initializerExpressionFactory)) { + return aClass.cast(initializerExpressionFactory); + } + return null; + } + + public static class PhoenixTableInitializerExpressionFactory extends + NullInitializerExpressionFactory { + private final RelDataTypeFactory typeFactory; + private final RexBuilder rexBuilder; + private final PhoenixConnection pc; + private final TableMapping tableMapping; + + public PhoenixTableInitializerExpressionFactory(RelDataTypeFactory typeFactory, + PhoenixConnection pc, TableMapping tableMapping) { + super(typeFactory); + this.typeFactory = typeFactory; + this.rexBuilder = new RexBuilder(typeFactory); + this.pc = pc; + this.tableMapping = tableMapping; + } + + public RexNode newColumnDefaultValue(RelOptTable table, int iColumn) { + PColumn column = tableMapping.getMappedColumns().get(iColumn); + String expressionStr = column.getExpressionStr(); + if(expressionStr == null) { + return super.newColumnDefaultValue(table, iColumn); + } + Expression defaultExpression = CalciteUtils.parseExpressionFromStr(expressionStr, pc); + return CalciteUtils.convertColumnExpressionToLiteral(column, defaultExpression, + typeFactory, rexBuilder); + } + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixCalciteEmbeddedDriver.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixCalciteEmbeddedDriver.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixCalciteEmbeddedDriver.java index c20151d..025ab58 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixCalciteEmbeddedDriver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixCalciteEmbeddedDriver.java @@ -30,6 +30,7 @@ import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.jdbc.CalcitePrepare; import org.apache.calcite.jdbc.Driver; import org.apache.calcite.linq4j.function.Function0; +import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; import org.apache.phoenix.calcite.PhoenixPrepareImpl; import org.apache.phoenix.calcite.PhoenixSchema; @@ -114,8 +115,9 @@ public abstract class PhoenixCalciteEmbeddedDriver extends Driver implements SQL final String phoenixUrl = url.replaceFirst(PhoenixRuntime.JDBC_PROTOCOL_CALCITE, PhoenixRuntime.JDBC_PROTOCOL); operand.put("url", phoenixUrl); SchemaPlus rootSchema = connection.getRootSchema(); - rootSchema.add("phoenix", - PhoenixSchema.FACTORY.create(rootSchema, "phoenix", operand)); + Schema schema = PhoenixSchema.FACTORY.create(rootSchema, "phoenix", operand); + ((PhoenixSchema)schema).setTypeFactory(connection.getTypeFactory()); + rootSchema.add("phoenix",schema); connection.setSchema("phoenix"); return connection; http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ad0e770/phoenix-core/src/test/java/org/apache/phoenix/calcite/ToExpressionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/calcite/ToExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/calcite/ToExpressionTest.java index 7dbca10..e1afa84 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/calcite/ToExpressionTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/calcite/ToExpressionTest.java @@ -170,7 +170,7 @@ public class ToExpressionTest extends BaseConnectionlessQueryTest { PTable table = rootTables.get(name); try { - return new PhoenixTable(pc, new TableRef(table)); + return new PhoenixTable(pc, new TableRef(table), null); } catch (SQLException e) { throw new RuntimeException(e); }
