You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ma...@apache.org on 2016/08/04 19:59:05 UTC

phoenix git commit: PHOENIX-3147 Support UPDATE STATISTICS in Phoenix-Calcite Integration

Repository: phoenix
Updated Branches:
  refs/heads/calcite 9a79dc99a -> 9a08a9d99


PHOENIX-3147 Support UPDATE STATISTICS in Phoenix-Calcite Integration


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/9a08a9d9
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/9a08a9d9
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/9a08a9d9

Branch: refs/heads/calcite
Commit: 9a08a9d9902cd93b192d8a84941fce5e0864edb6
Parents: 9a79dc9
Author: maryannxue <ma...@gmail.com>
Authored: Thu Aug 4 15:58:58 2016 -0400
Committer: maryannxue <ma...@gmail.com>
Committed: Thu Aug 4 15:58:58 2016 -0400

----------------------------------------------------------------------
 .../apache/phoenix/calcite/CalciteDDLIT.java    |   7 +
 phoenix-core/src/main/codegen/data/Parser.tdd   |   6 +-
 .../src/main/codegen/includes/parserImpls.ftl   |  87 ++++++++++--
 .../org/apache/calcite/sql/SqlOptionNode.java   |  71 ++++++++++
 .../apache/calcite/sql/SqlTableOptionNode.java  |  71 ----------
 .../calcite/jdbc/PhoenixPrepareImpl.java        | 142 +++++++++++--------
 .../calcite/parse/SqlUpdateStatistics.java      |  73 ++++++++++
 7 files changed, 313 insertions(+), 144 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteDDLIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteDDLIT.java b/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteDDLIT.java
index 1814516..2a222cd 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteDDLIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteDDLIT.java
@@ -2,6 +2,7 @@ package org.apache.phoenix.calcite;
 
 import java.util.Properties;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class CalciteDDLIT extends BaseCalciteIT {
@@ -50,4 +51,10 @@ public class CalciteDDLIT extends BaseCalciteIT {
         start(PROPS).sql("drop table t5").execute().close();
         start(PROPS).sql("create table t5(a bigint not null primary key, b varchar)").execute().close();
     }
+    
+    @Ignore
+    @Test public void testUpdateStatistics() throws Exception {
+        start(PROPS).sql("create table stest(a varchar(20) not null primary key, b integer)").execute().close();
+        start(PROPS).sql("update statistics stest columns set dummy=2").execute().close();
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/main/codegen/data/Parser.tdd
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/codegen/data/Parser.tdd b/phoenix-core/src/main/codegen/data/Parser.tdd
index a3091fd..68a0f43 100644
--- a/phoenix-core/src/main/codegen/data/Parser.tdd
+++ b/phoenix-core/src/main/codegen/data/Parser.tdd
@@ -23,6 +23,7 @@
   imports: [
     "org.apache.phoenix.calcite.parse.*",
     "org.apache.phoenix.schema.SortOrder",
+    "org.apache.phoenix.schema.stats.StatisticsCollectionScope",
     "org.apache.phoenix.parse.ColumnName",
     "org.apache.phoenix.parse.ColumnDef",
     "org.apache.phoenix.parse.ColumnDefInPkConstraint",
@@ -30,7 +31,7 @@
     "org.apache.calcite.sql.SqlColumnDefInPkConstraintNode"
     "org.apache.calcite.sql.SqlIndexExpressionNode"
     "org.apache.calcite.sql.SqlDataTypeNode"
-    "org.apache.calcite.sql.SqlTableOptionNode"
+    "org.apache.calcite.sql.SqlOptionNode"
     "java.util.*"
   ]
 
@@ -38,11 +39,13 @@
   keywords: [
     "ASYNC"
     "CACHE"
+    "COLUMNS"
     "IF"
     "INCLUDE"
     "INDEX"
     "ROW_TIMESTAMP"
     "SPLIT"
+    "STATISTICS"
   ]
 
   # List of keywords from "keywords" section that are not reserved.
@@ -60,6 +63,7 @@
     "SqlDropTableOrDropView()",
     "SqlDropIndex()",
     "SqlDropSequence()",
+    "SqlUpdateStatistics()",
   ]
 
   # List of methods for parsing custom literals.

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/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 f501e33..1360b68 100644
--- a/phoenix-core/src/main/codegen/includes/parserImpls.ftl
+++ b/phoenix-core/src/main/codegen/includes/parserImpls.ftl
@@ -103,7 +103,7 @@ SqlNode SqlCreateView() :
         }
     )
     (
-        tableOptions = TableOptionList()
+        tableOptions = FamilyOptionList()
         |
         {
             tableOptions = SqlNodeList.EMPTY;
@@ -154,7 +154,7 @@ SqlNode SqlCreateTable() :
     )
     <RPAREN>
     (
-        tableOptions = TableOptionList()
+        tableOptions = FamilyOptionList()
         |
         {
             tableOptions = SqlNodeList.EMPTY;
@@ -216,7 +216,7 @@ SqlNode SqlCreateIndex() :
         <ASYNC> { async = true; }
     ]
     [
-        indexOptions = TableOptionList()
+        indexOptions = FamilyOptionList()
     ]
     [
         <SPLIT> <ON> <LPAREN>
@@ -383,6 +383,40 @@ SqlNode SqlDropSequence() :
     }
 }
 
+/**
+ * Parses statement
+ *   UPDATE STATISTICS
+ */
+SqlNode SqlUpdateStatistics() :
+{
+    SqlParserPos pos;
+    SqlIdentifier tableName;
+    StatisticsCollectionScope scope;
+    SqlNodeList statsOptions = SqlNodeList.EMPTY;
+}
+{
+    <UPDATE> { pos = getPos(); } <STATISTICS>
+    tableName = DualIdentifier()
+    (
+        <ALL> { scope = StatisticsCollectionScope.ALL; }
+        |
+        <INDEX> { scope = StatisticsCollectionScope.INDEX; }
+        |
+        <COLUMNS> { scope = StatisticsCollectionScope.COLUMNS; }
+        |
+        {
+            scope = StatisticsCollectionScope.getDefault();
+        }
+    )
+    [
+        <SET>
+        statsOptions = GeneralOptionList()
+    ]
+    {
+        return new SqlUpdateStatistics(pos.plus(getPos()), tableName, scope, statsOptions);
+    }
+}
+
 SqlNodeList ColumnDefList() :
 {
     SqlParserPos pos;
@@ -451,20 +485,37 @@ SqlNodeList IndexIncludeList() :
     }
 }
 
-SqlNodeList TableOptionList() :
+SqlNodeList FamilyOptionList() :
 {
     SqlParserPos pos;
     SqlNode e;
-    List<SqlNode> tableOptionList;
+    List<SqlNode> familyOptionList;
 }
 {
     { pos = getPos(); }
-    e = TableOption() { tableOptionList = startList(e); }
+    e = FamilyOption() { familyOptionList = startList(e); }
     (
-        <COMMA> e = TableOption() { tableOptionList.add(e); }
+        <COMMA> e = FamilyOption() { familyOptionList.add(e); }
     ) *
     {
-        return new SqlNodeList(tableOptionList, pos.plus(getPos()));
+        return new SqlNodeList(familyOptionList, pos.plus(getPos()));
+    }
+}
+
+SqlNodeList GeneralOptionList() :
+{
+    SqlParserPos pos;
+    SqlNode e;
+    List<SqlNode> generalOptionList;
+}
+{
+    { pos = getPos(); }
+    e = GeneralOption() { generalOptionList = startList(e); }
+    (
+        <COMMA> e = GeneralOption() { generalOptionList.add(e); }
+    ) *
+    {
+        return new SqlNodeList(generalOptionList, pos.plus(getPos()));
     }
 }
 
@@ -609,7 +660,7 @@ SqlIndexExpressionNode IndexExpression() :
     }
 }
 
-SqlTableOptionNode TableOption() :
+SqlOptionNode FamilyOption() :
 {
     SqlIdentifier key;
     SqlNode value;
@@ -621,7 +672,23 @@ SqlTableOptionNode TableOption() :
     value = Literal()
     {
         pos = key.getParserPosition().plus(getPos());
-        return new SqlTableOptionNode(pos, key, (SqlLiteral) value);
+        return new SqlOptionNode(pos, key, (SqlLiteral) value);
+    }
+}
+
+SqlOptionNode GeneralOption() :
+{
+    SqlIdentifier key;
+    SqlNode value;
+    SqlParserPos pos;
+}
+{
+    key = SimpleIdentifier()
+    <EQ>
+    value = Literal()
+    {
+        pos = key.getParserPosition().plus(getPos());
+        return new SqlOptionNode(pos, key, (SqlLiteral) value);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/main/java/org/apache/calcite/sql/SqlOptionNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/calcite/sql/SqlOptionNode.java b/phoenix-core/src/main/java/org/apache/calcite/sql/SqlOptionNode.java
new file mode 100644
index 0000000..dc2274e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/calcite/sql/SqlOptionNode.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.util.SqlVisitor;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
+import org.apache.calcite.util.Litmus;
+import org.apache.calcite.util.NlsString;
+
+public class SqlOptionNode extends SqlNode {
+    public final String familyName;
+    public final String propertyName;
+    public final Object value;
+
+    public SqlOptionNode(SqlParserPos pos, SqlIdentifier key, SqlLiteral literal) {
+        super(pos);
+        if (key.isSimple()) {
+            familyName = "";
+            propertyName = key.getSimple();
+        } else {
+            familyName = key.names.get(0);
+            propertyName = key.names.get(1);
+        }
+        final Object v = SqlLiteral.value(literal);
+        if (v instanceof NlsString) {
+            value = ((NlsString) v).toString();
+        } else {
+            value = v;
+        }
+    }
+
+    @Override
+    public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void validate(SqlValidator validator, SqlValidatorScope scope) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public <R> R accept(SqlVisitor<R> visitor) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean equalsDeep(SqlNode node, Litmus litmus) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/main/java/org/apache/calcite/sql/SqlTableOptionNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/calcite/sql/SqlTableOptionNode.java b/phoenix-core/src/main/java/org/apache/calcite/sql/SqlTableOptionNode.java
deleted file mode 100644
index 5119565..0000000
--- a/phoenix-core/src/main/java/org/apache/calcite/sql/SqlTableOptionNode.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.sql;
-
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.util.SqlVisitor;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
-import org.apache.calcite.util.Litmus;
-import org.apache.calcite.util.NlsString;
-
-public class SqlTableOptionNode extends SqlNode {
-    public final String familyName;
-    public final String propertyName;
-    public final Object value;
-
-    public SqlTableOptionNode(SqlParserPos pos, SqlIdentifier key, SqlLiteral literal) {
-        super(pos);
-        if (key.isSimple()) {
-            familyName = "";
-            propertyName = key.getSimple();
-        } else {
-            familyName = key.names.get(0);
-            propertyName = key.names.get(1);
-        }
-        final Object v = SqlLiteral.value(literal);
-        if (v instanceof NlsString) {
-            value = ((NlsString) v).toString();
-        } else {
-            value = v;
-        }
-    }
-
-    @Override
-    public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void validate(SqlValidator validator, SqlValidatorScope scope) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public <R> R accept(SqlVisitor<R> visitor) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean equalsDeep(SqlNode node, Litmus litmus) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
index 0a3baa9..f7e4a45 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
@@ -30,7 +30,7 @@ import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
-import org.apache.calcite.sql.SqlTableOptionNode;
+import org.apache.calcite.sql.SqlOptionNode;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.parser.SqlParserUtil;
@@ -38,7 +38,7 @@ import org.apache.calcite.tools.Program;
 import org.apache.calcite.tools.Programs;
 import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.NlsString;
-import org.apache.calcite.util.Pair;
+import org.apache.hadoop.hbase.util.Pair;
 import org.apache.phoenix.calcite.PhoenixSchema;
 import org.apache.phoenix.calcite.parse.SqlCreateIndex;
 import org.apache.phoenix.calcite.parse.SqlCreateSequence;
@@ -46,6 +46,7 @@ import org.apache.phoenix.calcite.parse.SqlCreateTable;
 import org.apache.phoenix.calcite.parse.SqlDropIndex;
 import org.apache.phoenix.calcite.parse.SqlDropSequence;
 import org.apache.phoenix.calcite.parse.SqlDropTable;
+import org.apache.phoenix.calcite.parse.SqlUpdateStatistics;
 import org.apache.phoenix.calcite.parser.PhoenixParserImpl;
 import org.apache.phoenix.calcite.rel.PhoenixRel;
 import org.apache.phoenix.calcite.rel.PhoenixServerProject;
@@ -83,6 +84,7 @@ import org.apache.phoenix.parse.PrimaryKeyConstraint;
 import org.apache.phoenix.parse.SQLParser;
 import org.apache.phoenix.parse.TableName;
 import org.apache.phoenix.parse.UDFParseNode;
+import org.apache.phoenix.parse.UpdateStatisticsStatement;
 import org.apache.phoenix.schema.MetaDataClient;
 import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.schema.PTableType;
@@ -177,10 +179,10 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
             });
         }
         
-        Hook.PROGRAM.add(new Function<Pair<List<Materialization>, Holder<Program>>, Object>() {
+        Hook.PROGRAM.add(new Function<org.apache.calcite.util.Pair<List<Materialization>, Holder<Program>>, Object>() {
 			@Override
 			public Object apply(
-					Pair<List<Materialization>, Holder<Program>> input) {
+			        org.apache.calcite.util.Pair<List<Materialization>, Holder<Program>> input) {
 				input.getValue().set(Programs.standard(PhoenixRel.METADATA_PROVIDER));
 				return null;
 			}
@@ -205,16 +207,7 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
                 } else {
                     name = TableName.create(table.tableName.names.get(0), table.tableName.names.get(1));
                 }
-                final ListMultimap<String, org.apache.hadoop.hbase.util.Pair<String, Object>> props;
-                if (SqlNodeList.isEmptyList(table.tableOptions)) {
-                    props = null;
-                } else {
-                    props = ArrayListMultimap.<String, org.apache.hadoop.hbase.util.Pair<String, Object>>create();
-                    for (SqlNode tableOption : table.tableOptions) {
-                        SqlTableOptionNode option = (SqlTableOptionNode) tableOption;
-                        props.put(option.familyName, new org.apache.hadoop.hbase.util.Pair<String, Object>(option.propertyName, option.value));
-                    }
-                }
+                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);
@@ -240,27 +233,9 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
                     } else {
                         baseTableName = TableName.create(table.baseTableName.names.get(0), table.baseTableName.names.get(1));
                     }
-                    if (table.whereNode == null) {
-                        where = null;
-                    } else {
-                        String sql = THREAD_SQL_STRING.get();
-                        SqlParserPos wherePos = table.whereNode.getParserPosition();
-                        int start = SqlParserUtil.lineColToIndex(sql, wherePos.getLineNum(), wherePos.getColumnNum());
-                        int end = SqlParserUtil.lineColToIndex(sql, wherePos.getEndLineNum(), wherePos.getEndColumnNum());
-                        String whereString = sql.substring(start, end + 1);
-                        where = new SQLParser(whereString).parseExpression();
-                    }
-                }
-                final List<ParseNode> splitNodes;
-                if (SqlNodeList.isEmptyList(table.splitKeyList)) {
-                    splitNodes = null;
-                } else {
-                    splitNodes = Lists.newArrayList();
-                    for (SqlNode splitKey : table.splitKeyList) {
-                        final SqlLiteral key = (SqlLiteral) splitKey;
-                        splitNodes.add(nodeFactory.literal(((NlsString) key.getValue()).toString()));
-                    }
+                    where = convertSqlNodeToParseNode(table.whereNode);
                 }
+                final List<ParseNode> splitNodes = convertSplits(table.splitKeyList, nodeFactory);
                 final CreateTableStatement create = nodeFactory.createTable(
                         name, props, columnDefs, pkConstraint,
                         splitNodes, tableType, table.ifNotExists.booleanValue(),
@@ -283,16 +258,11 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
                     dataTableName = TableName.create(index.dataTableName.names.get(0), index.dataTableName.names.get(1));
                 }
                 final NamedTableNode dataTable = NamedTableNode.create(dataTableName);
-                final List<org.apache.hadoop.hbase.util.Pair<ParseNode, SortOrder>> indexKeys = Lists.newArrayList();
+                final List<Pair<ParseNode, SortOrder>> indexKeys = Lists.newArrayList();
                 for (SqlNode e : index.expressions) {
                     SqlIndexExpressionNode indexExpression = (SqlIndexExpressionNode) e;
-                    String sql = THREAD_SQL_STRING.get();
-                    SqlParserPos exprPos = indexExpression.expression.getParserPosition();
-                    int start = SqlParserUtil.lineColToIndex(sql, exprPos.getLineNum(), exprPos.getColumnNum());
-                    int end = SqlParserUtil.lineColToIndex(sql, exprPos.getEndLineNum(), exprPos.getEndColumnNum());
-                    String exprString = sql.substring(start, end + 1);
-                    ParseNode exprNode = new SQLParser(exprString).parseExpression();
-                    indexKeys.add(new org.apache.hadoop.hbase.util.Pair<ParseNode, SortOrder>(exprNode, indexExpression.sortOrder));
+                    ParseNode exprNode = convertSqlNodeToParseNode(indexExpression.expression);
+                    indexKeys.add(new Pair<ParseNode, SortOrder>(exprNode, indexExpression.sortOrder));
                 }
                 final IndexKeyConstraint indexKeyConstraint = nodeFactory.indexKey(indexKeys);
                 final List<ColumnName> includeColumns;
@@ -311,26 +281,8 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
                         includeColumns.add(columnName);
                     }
                 }
-                final ListMultimap<String, org.apache.hadoop.hbase.util.Pair<String, Object>> props;
-                if (SqlNodeList.isEmptyList(index.indexOptions)) {
-                    props = null;
-                } else {
-                    props = ArrayListMultimap.<String, org.apache.hadoop.hbase.util.Pair<String, Object>>create();
-                    for (SqlNode tableOption : index.indexOptions) {
-                        SqlTableOptionNode option = (SqlTableOptionNode) tableOption;
-                        props.put(option.familyName, new org.apache.hadoop.hbase.util.Pair<String, Object>(option.propertyName, option.value));
-                    }
-                }
-                final List<ParseNode> splitNodes;
-                if (SqlNodeList.isEmptyList(index.splitKeyList)) {
-                    splitNodes = null;
-                } else {
-                    splitNodes = Lists.newArrayList();
-                    for (SqlNode splitKey : index.splitKeyList) {
-                        final SqlLiteral key = (SqlLiteral) splitKey;
-                        splitNodes.add(nodeFactory.literal(((NlsString) key.getValue()).toString()));
-                    }
-                }
+                final ListMultimap<String, Pair<String, Object>> props = convertOptions(index.indexOptions);
+                final List<ParseNode> splitNodes = convertSplits(index.splitKeyList, nodeFactory);
                 // TODO
                 final Map<String, UDFParseNode> udfParseNodes = new HashMap<String, UDFParseNode>();
                 final CreateIndexStatement create = nodeFactory.createIndex(
@@ -408,6 +360,29 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
                 client.dropSequence(drop);
                 break;                
             }
+            case OTHER_DDL: {
+                if (node instanceof SqlUpdateStatistics) {
+                    SqlUpdateStatistics updateStatsNode = (SqlUpdateStatistics) node;
+                    final TableName name;
+                    if (updateStatsNode.tableName.isSimple()) {
+                        name = TableName.create(null, updateStatsNode.tableName.getSimple());
+                    } else {
+                        name = TableName.create(updateStatsNode.tableName.names.get(0), updateStatsNode.tableName.names.get(1));
+                    }
+                    final NamedTableNode table = NamedTableNode.create(name);
+                    final Map<String, Object> props = new HashMap<String, Object>();
+                    for (SqlNode optionNode : updateStatsNode.options) {
+                        SqlOptionNode option = (SqlOptionNode) optionNode;
+                        props.put(option.propertyName, option.value);
+                    }
+                    final UpdateStatisticsStatement updateStatsStmt = nodeFactory.updateStatistics(table, updateStatsNode.scope, props);
+                    MetaDataClient client = new MetaDataClient(connection);
+                    client.updateStatistics(updateStatsStmt);                    
+                } else {
+                    throw new AssertionError("unknown DDL node " + node.getClass());                    
+                }
+                break;
+            }
             default:
                 throw new AssertionError("unknown DDL type " + node.getKind() + " " + node.getClass());
             }
@@ -415,6 +390,49 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
             throw new RuntimeException(ex);
         }
     }
+
+    private static ParseNode convertSqlNodeToParseNode(SqlNode sqlNode) throws SQLException {
+        if (sqlNode == null) {
+            return null;
+        }
+
+        String sql = THREAD_SQL_STRING.get();
+        SqlParserPos pos = sqlNode.getParserPosition();
+        int start = SqlParserUtil.lineColToIndex(sql, pos.getLineNum(), pos.getColumnNum());
+        int end = SqlParserUtil.lineColToIndex(sql, pos.getEndLineNum(), pos.getEndColumnNum());
+        String sqlString = sql.substring(start, end + 1);
+        return new SQLParser(sqlString).parseExpression();
+    }
+
+    private static ListMultimap<String, Pair<String, Object>> convertOptions(SqlNodeList options) {
+        final ListMultimap<String, Pair<String, Object>> props;
+        if (SqlNodeList.isEmptyList(options)) {
+            props = null;
+        } else {
+            props = ArrayListMultimap.<String, Pair<String, Object>>create();
+            for (SqlNode optionNode : options) {
+                SqlOptionNode option = (SqlOptionNode) optionNode;
+                props.put(option.familyName, new Pair<String, Object>(option.propertyName, option.value));
+            }
+        }
+
+        return props;
+    }
+
+    private static List<ParseNode> convertSplits(SqlNodeList splitKeyList, ParseNodeFactory nodeFactory) {
+        final List<ParseNode> splits;
+        if (SqlNodeList.isEmptyList(splitKeyList)) {
+            splits = null;
+        } else {
+            splits = Lists.newArrayList();
+            for (SqlNode splitKey : splitKeyList) {
+                final SqlLiteral key = (SqlLiteral) splitKey;
+                splits.add(nodeFactory.literal(((NlsString) key.getValue()).toString()));
+            }
+        }
+
+        return splits;
+    }
     
     private static PhoenixConnection getPhoenixConnection(SchemaPlus rootSchema) {
         for (String subSchemaName : rootSchema.getSubSchemaNames()) {               

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9a08a9d9/phoenix-core/src/main/java/org/apache/phoenix/calcite/parse/SqlUpdateStatistics.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/parse/SqlUpdateStatistics.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/parse/SqlUpdateStatistics.java
new file mode 100644
index 0000000..7f91ca7
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/parse/SqlUpdateStatistics.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.calcite.parse;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.phoenix.schema.stats.StatisticsCollectionScope;
+
+import java.util.List;
+
+/**
+ * Parse tree node for SQL {@code UPDATE STATISTICS} command.
+ */
+public class SqlUpdateStatistics extends SqlCall {
+    public static final SqlOperator OPERATOR = new SqlDdlOperator("UPDATE STATISTICS", SqlKind.OTHER_DDL);
+
+    public final SqlIdentifier tableName;
+    public final StatisticsCollectionScope scope;
+    public final SqlNodeList options;
+    
+    private final SqlLiteral scopeLiteral;
+    
+
+    /** Creates a UPDATE STATISTICS. */
+    public SqlUpdateStatistics(
+            SqlParserPos pos,
+            SqlIdentifier tableName,
+            StatisticsCollectionScope scope,
+            SqlNodeList options) {
+        super(pos);
+        this.tableName = tableName;
+        this.scope = scope;
+        this.options = options;
+        this.scopeLiteral = SqlLiteral.createCharString(scope.name(), SqlParserPos.ZERO);
+    }
+
+    public SqlOperator getOperator() {
+        return OPERATOR;
+    }
+
+    public List<SqlNode> getOperandList() {
+        return ImmutableList.of(tableName, scopeLiteral, options);
+    }
+
+    @Override
+    public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
+        // TODO Auto-generated method stub
+    }
+}