You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2013/07/02 16:16:26 UTC
[32/51] [partial] TAJO-22: The package prefix should be
org.apache.tajo. (DaeMyung Kang via hyunsik)
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/SumLong.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/SumLong.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/SumLong.java
new file mode 100644
index 0000000..3e800a5
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/SumLong.java
@@ -0,0 +1,68 @@
+/**
+ * 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.tajo.engine.function.builtin;
+
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.function.AggFunction;
+import org.apache.tajo.catalog.function.FunctionContext;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.common.TajoDataTypes.Type;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.Int8Datum;
+import org.apache.tajo.storage.Tuple;
+
+public class SumLong extends AggFunction<Datum> {
+
+ public SumLong() {
+ super(new Column[] {
+ new Column("val", Type.INT8)
+ });
+ }
+
+ @Override
+ public FunctionContext newContext() {
+ return new SumContext();
+ }
+
+ @Override
+ public void eval(FunctionContext ctx, Tuple params) {
+ ((SumContext)ctx).sum += params.get(0).asInt8();
+ }
+
+ @Override
+ public Datum getPartialResult(FunctionContext ctx) {
+ return DatumFactory.createInt8(((SumContext) ctx).sum);
+ }
+
+ @Override
+ public DataType [] getPartialResultType() {
+ return CatalogUtil.newDataTypesWithoutLen(Type.INT8);
+ }
+
+ @Override
+ public Int8Datum terminate(FunctionContext ctx) {
+ return DatumFactory.createInt8(((SumContext) ctx).sum);
+ }
+
+ private class SumContext implements FunctionContext {
+ long sum;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/Today.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/Today.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/Today.java
new file mode 100644
index 0000000..c6a8518
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/builtin/Today.java
@@ -0,0 +1,38 @@
+/**
+ * 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.tajo.engine.function.builtin;
+
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.function.GeneralFunction;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.Int8Datum;
+import org.apache.tajo.storage.Tuple;
+
+public class Today extends GeneralFunction<Int8Datum> {
+
+ public Today() {
+ super(new Column[] {});
+ }
+
+ @Override
+ public Datum eval(Tuple params) {
+ return DatumFactory.createInt8(System.currentTimeMillis());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/EvalNodeAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/EvalNodeAdapter.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/EvalNodeAdapter.java
new file mode 100644
index 0000000..49ea542
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/EvalNodeAdapter.java
@@ -0,0 +1,55 @@
+/**
+ * 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.tajo.engine.json;
+
+import com.google.gson.*;
+import org.apache.tajo.engine.eval.EvalNode;
+
+import java.lang.reflect.Type;
+
+public class EvalNodeAdapter implements JsonSerializer<EvalNode>, JsonDeserializer<EvalNode> {
+
+ @Override
+ public EvalNode deserialize(JsonElement json, Type type,
+ JsonDeserializationContext ctx) throws JsonParseException {
+ JsonObject jsonObj = json.getAsJsonObject();
+ String className = jsonObj.get("type").getAsString();
+ JsonElement elem = jsonObj.get("properties");
+
+ try {
+ return ctx.deserialize(elem, Class.forName(className));
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public JsonElement serialize(EvalNode evalNode, Type type,
+ JsonSerializationContext ctx) {
+ JsonObject json = new JsonObject();
+ json.add("type", new JsonPrimitive(evalNode.getClass().getName()));
+ json.add("properties", ctx.serialize(evalNode, evalNode.getClass()));
+ return json;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FragmentDeserializer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FragmentDeserializer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FragmentDeserializer.java
new file mode 100644
index 0000000..41b2ef6
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FragmentDeserializer.java
@@ -0,0 +1,54 @@
+/**
+ * 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.tajo.engine.json;
+
+import com.google.gson.*;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.catalog.Options;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.TableMetaImpl;
+import org.apache.tajo.catalog.proto.CatalogProtos.StoreType;
+import org.apache.tajo.storage.Fragment;
+
+import java.lang.reflect.Type;
+
+public class FragmentDeserializer implements JsonDeserializer<Fragment> {
+
+ @Override
+ public Fragment deserialize(JsonElement json, Type type,
+ JsonDeserializationContext ctx) throws JsonParseException {
+ Gson gson = GsonCreator.getInstance();
+ JsonObject fragObj = json.getAsJsonObject();
+ JsonObject metaObj = fragObj.get("meta").getAsJsonObject();
+ TableMetaImpl meta = new TableMetaImpl(
+ gson.fromJson(metaObj.get("schema"), Schema.class),
+ gson.fromJson(metaObj.get("storeType"), StoreType.class),
+ gson.fromJson(metaObj.get("options"), Options.class));
+ Fragment fragment = new Fragment(fragObj.get("tabletId").getAsString(),
+ gson.fromJson(fragObj.get("path"), Path.class),
+ meta,
+ fragObj.get("startOffset").getAsLong(),
+ fragObj.get("length").getAsLong(), null);
+ return fragment;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FromTableDeserializer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FromTableDeserializer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FromTableDeserializer.java
new file mode 100644
index 0000000..aa4bbbf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/FromTableDeserializer.java
@@ -0,0 +1,50 @@
+/**
+ * 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.tajo.engine.json;
+
+import com.google.gson.*;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.TableDescImpl;
+import org.apache.tajo.engine.parser.QueryBlock.FromTable;
+import org.apache.tajo.storage.Fragment;
+
+import java.lang.reflect.Type;
+
+public class FromTableDeserializer implements JsonDeserializer<FromTable> {
+
+ @Override
+ public FromTable deserialize(JsonElement json, Type type,
+ JsonDeserializationContext ctx) throws JsonParseException {
+ Gson gson = GsonCreator.getInstance();
+ JsonObject fromTableObj = json.getAsJsonObject();
+ boolean isFragment = fromTableObj.get("isFragment").getAsBoolean();
+ TableDesc desc;
+ if (isFragment) {
+ desc = gson.fromJson(fromTableObj.get("desc"), Fragment.class);
+ } else {
+ desc = gson.fromJson(fromTableObj.get("desc"), TableDescImpl.class);
+ }
+
+ return new FromTable(desc, fromTableObj.get("alias").getAsString());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/GsonCreator.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/GsonCreator.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/GsonCreator.java
new file mode 100644
index 0000000..98e7f1f
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/GsonCreator.java
@@ -0,0 +1,81 @@
+/**
+ * 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.tajo.engine.json;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.TableMeta;
+import org.apache.tajo.catalog.function.AggFunction;
+import org.apache.tajo.catalog.function.Function;
+import org.apache.tajo.catalog.function.GeneralFunction;
+import org.apache.tajo.catalog.json.FunctionAdapter;
+import org.apache.tajo.catalog.json.TableDescAdapter;
+import org.apache.tajo.catalog.json.TableMetaAdapter;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.json.DatumAdapter;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.planner.logical.LogicalNode;
+import org.apache.tajo.gson.*;
+
+public class GsonCreator {
+ private static GsonBuilder builder;
+ private static Gson gson;
+
+ private static void init() {
+ if (builder == null) {
+ builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation();
+ builder.registerTypeAdapter(Path.class, new PathSerializer());
+ builder.registerTypeAdapter(Path.class, new PathDeserializer());
+ builder.registerTypeAdapter(TableDesc.class, new TableDescAdapter());
+ builder.registerTypeAdapter(Class.class, new ClassNameSerializer());
+ builder.registerTypeAdapter(Class.class, new ClassNameDeserializer());
+ builder.registerTypeAdapter(LogicalNode.class, new LogicalNodeAdapter());
+ builder.registerTypeAdapter(EvalNode.class, new EvalNodeAdapter());
+ builder.registerTypeAdapter(TableMeta.class, new TableMetaAdapter());
+ builder.registerTypeAdapter(Datum.class, new DatumTypeAdapter());
+ builder.registerTypeAdapter(Function.class, new FunctionAdapter());
+ builder.registerTypeAdapter(GeneralFunction.class, new FunctionAdapter());
+ builder.registerTypeAdapter(AggFunction.class, new FunctionAdapter());
+ builder.registerTypeAdapter(Datum.class, new DatumAdapter());
+ builder.registerTypeAdapter(DataType.class, new DataTypeAdapter());
+ }
+ }
+
+ public static Gson getInstance() {
+ init();
+ if (gson == null ) {
+ gson = builder.create();
+ }
+ return gson;
+ }
+
+ public static Gson getPrettyInstance() {
+ init();
+ if (gson == null ) {
+ gson = builder.setPrettyPrinting().create();
+ }
+ return gson;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/LogicalNodeAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/LogicalNodeAdapter.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/LogicalNodeAdapter.java
new file mode 100644
index 0000000..1716916
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/json/LogicalNodeAdapter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.tajo.engine.json;
+
+import com.google.gson.*;
+import org.apache.tajo.engine.planner.logical.LogicalNode;
+
+import java.lang.reflect.Type;
+
+public class LogicalNodeAdapter implements JsonSerializer<LogicalNode>, JsonDeserializer<LogicalNode> {
+
+ @Override
+ public LogicalNode deserialize(JsonElement json, Type type,
+ JsonDeserializationContext ctx) throws JsonParseException {
+ JsonObject jsonObject = json.getAsJsonObject();
+ String className = jsonObject.get("classname").getAsJsonPrimitive().getAsString();
+
+ Class clazz;
+ try {
+ clazz = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ throw new JsonParseException(e);
+ }
+ return ctx.deserialize(jsonObject.get("property"), clazz);
+ }
+
+ @Override
+ public JsonElement serialize(LogicalNode src, Type typeOfSrc,
+ JsonSerializationContext context) {
+ JsonObject jsonObj = new JsonObject();
+ String className = src.getClass().getCanonicalName();
+ jsonObj.addProperty("classname", className);
+ JsonElement jsonElem = context.serialize(src);
+ jsonObj.add("property", jsonElem);
+ return jsonObj;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CommandType.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CommandType.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CommandType.java
new file mode 100644
index 0000000..911da97
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CommandType.java
@@ -0,0 +1,41 @@
+/**
+ * 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.tajo.engine.parser;
+
+public enum CommandType {
+ // Select
+ SELECT,
+
+ // Update
+ INSERT,
+ UPDATE,
+ DELETE,
+
+ // Schema
+ CREATE_TABLE,
+ DROP_TABLE,
+
+ // Control
+ SHOW_TABLES,
+ DESC_TABLE,
+ SHOW_FUNCTION;
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CopyStmt.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CopyStmt.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CopyStmt.java
new file mode 100644
index 0000000..cef63cf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CopyStmt.java
@@ -0,0 +1,72 @@
+/**
+ * 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.tajo.engine.parser;
+
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.catalog.Options;
+import org.apache.tajo.engine.planner.PlanningContext;
+
+import static org.apache.tajo.catalog.proto.CatalogProtos.StoreType;
+
+public class CopyStmt extends ParseTree {
+ private String tableName;
+ private Path path;
+ private StoreType storeType;
+ private Options params = null;
+
+ public CopyStmt(PlanningContext context) {
+ super(context, StatementType.COPY);
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ }
+
+ public String getTableName() {
+ return this.tableName;
+ }
+
+ public void setPath(Path path) {
+ this.path = path;
+ }
+
+ public Path getPath() {
+ return this.path;
+ }
+
+ public void setStoreType(StoreType storeType) {
+ this.storeType = storeType;
+ }
+
+ public StoreType getStoreType() {
+ return this.storeType;
+ }
+
+ public boolean hasParams() {
+ return this.params != null;
+ }
+
+ public void setParams(Options params) {
+ this.params = params;
+ }
+
+ public Options getParams() {
+ return this.params;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateIndexStmt.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateIndexStmt.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateIndexStmt.java
new file mode 100644
index 0000000..447aeb0
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateIndexStmt.java
@@ -0,0 +1,107 @@
+/**
+ * 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.tajo.engine.parser;
+
+import com.google.common.base.Preconditions;
+import org.apache.tajo.catalog.Options;
+import org.apache.tajo.catalog.SortSpec;
+import org.apache.tajo.catalog.proto.CatalogProtos.IndexMethod;
+import org.apache.tajo.engine.planner.PlanningContext;
+
+public class CreateIndexStmt extends ParseTree {
+ private String idxName;
+ private boolean unique = false;
+ private String tableName;
+ private IndexMethod method = IndexMethod.TWO_LEVEL_BIN_TREE;
+ private SortSpec[] sortSpecs;
+ private Options params = null;
+
+ public CreateIndexStmt(final PlanningContext context) {
+ super(context, StatementType.CREATE_INDEX);
+ }
+
+ public CreateIndexStmt(final PlanningContext context, String idxName,
+ boolean unique, String tableName,
+ SortSpec [] sortSpecs) {
+ this(context);
+ this.idxName = idxName;
+ this.unique = unique;
+ this.tableName = tableName;
+ this.sortSpecs = sortSpecs;
+ }
+
+ public void setIndexName(String name) {
+ this.idxName = name;
+ }
+
+ public String getIndexName() {
+ return this.idxName;
+ }
+
+ public boolean isUnique() {
+ return this.unique;
+ }
+
+ public void setUnique() {
+ this.unique = true;
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ addTableRef(tableName, tableName);
+ }
+
+ public String getTableName() {
+ return this.tableName;
+ }
+
+ public void setMethod(IndexMethod method) {
+ this.method = method;
+ }
+
+ public IndexMethod getMethod() {
+ return this.method;
+ }
+
+ public void setSortSpecs(SortSpec[] sortSpecs) {
+ Preconditions.checkNotNull(sortSpecs);
+ Preconditions.checkArgument(sortSpecs.length > 0,
+ "Sort specifiers must be at least one");
+ this.sortSpecs = sortSpecs;
+ }
+
+ public SortSpec[] getSortSpecs() {
+ return this.sortSpecs;
+ }
+
+ public boolean hasParams() {
+ return this.params != null;
+ }
+
+ public void setParams(Options params) {
+ this.params = params;
+ }
+
+ public Options getParams() {
+ return this.params;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateTableStmt.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateTableStmt.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateTableStmt.java
new file mode 100644
index 0000000..90b4a69
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/CreateTableStmt.java
@@ -0,0 +1,128 @@
+/**
+ * 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.tajo.engine.parser;
+
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.catalog.Options;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.proto.CatalogProtos.StoreType;
+import org.apache.tajo.engine.planner.PlanningContext;
+import org.apache.tajo.engine.planner.PlanningContextImpl;
+
+public class CreateTableStmt extends ParseTree {
+ private final String tableName;
+ private Schema schema;
+ private StoreType storeType;
+ private Path path;
+ private QueryBlock selectStmt;
+ private Options options;
+
+ public CreateTableStmt(final PlanningContext context,
+ final String tableName) {
+ super(context, StatementType.CREATE_TABLE);
+ this.tableName = tableName;
+ }
+
+ public CreateTableStmt(final PlanningContext context,
+ final String tableName, final Schema schema,
+ StoreType storeType) {
+ super(context, StatementType.CREATE_TABLE);
+ addTableRef(tableName, tableName);
+ this.tableName = tableName;
+ this.schema = schema;
+ this.storeType = storeType;
+ }
+
+ public CreateTableStmt(final PlanningContextImpl context,
+ final String tableName, final QueryBlock selectStmt) {
+ super(context, StatementType.CREATE_TABLE_AS);
+ context.setOutputTableName(tableName);
+ addTableRef(tableName, tableName);
+ this.tableName = tableName;
+ this.selectStmt = selectStmt;
+ }
+
+ public final String getTableName() {
+ return this.tableName;
+ }
+
+ public final boolean hasQueryBlock() {
+ return this.selectStmt != null;
+ }
+
+ public final QueryBlock getSelectStmt() {
+ return this.selectStmt;
+ }
+
+ public final boolean hasDefinition() {
+ return this.schema != null;
+ }
+
+ public boolean hasTableDef() {
+ return this.schema != null;
+ }
+
+ public void setTableDef(Schema schema) {
+ this.schema = schema;
+ }
+
+ public final Schema getTableDef() {
+ return this.schema;
+ }
+
+ public boolean hasStoreType() {
+ return this.storeType != null;
+ }
+
+ public void setStoreType(StoreType type) {
+ this.storeType = type;
+ }
+
+ public final StoreType getStoreType() {
+ return this.storeType;
+ }
+
+ public boolean hasOptions() {
+ return this.options != null;
+ }
+
+ public void setOptions(Options opt) {
+ this.options = opt;
+ }
+
+ public Options getOptions() {
+ return this.options;
+ }
+
+
+ public boolean hasPath() {
+ return this.path != null;
+ }
+
+ public void setPath(Path path) {
+ this.path = path;
+ }
+
+ public final Path getPath() {
+ return this.path;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseTree.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseTree.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseTree.java
new file mode 100644
index 0000000..76f4c3a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseTree.java
@@ -0,0 +1,63 @@
+/**
+ * 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.tajo.engine.parser;
+
+import org.apache.tajo.engine.parser.QueryBlock.FromTable;
+import org.apache.tajo.engine.planner.PlanningContext;
+
+import java.util.Map.Entry;
+
+public abstract class ParseTree {
+ protected final PlanningContext context;
+ protected final StatementType type;
+ private final TableMap tableMap = new TableMap();
+
+ public ParseTree(final PlanningContext context, final StatementType type) {
+ this.context = context;
+ this.type = type;
+ }
+
+ public StatementType getStatementType() {
+ return this.type;
+ }
+
+ protected void addTableRef(FromTable table) {
+ tableMap.addFromTable(table);
+ }
+
+ protected void addTableRef(String tableName, String alias) {
+ tableMap.addFromTable(tableName, alias);
+ }
+
+ public StatementType getType() {
+ return this.type;
+ }
+
+ public String getTableNameByAlias(String alias) {
+ return tableMap.getTableNameByAlias(alias);
+ }
+
+ public Iterable<String> getAllTableNames() {
+ return tableMap.getAllTableNames();
+ }
+
+ public Iterable<Entry<String, String>> getAliasToNames() {
+ return tableMap.getAliasToNames();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseUtil.java
new file mode 100644
index 0000000..5786b15
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParseUtil.java
@@ -0,0 +1,76 @@
+/**
+ * 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.tajo.engine.parser;
+
+import org.antlr.runtime.tree.Tree;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.eval.InvalidEvalException;
+
+public class ParseUtil {
+ private static final Log LOG = LogFactory.getLog(ParseUtil.class);
+
+ public static boolean isConstant(final Tree tree) {
+ switch (tree.getType()) {
+ case SQLParser.NUMBER:
+ case SQLParser.REAL:
+ case SQLParser.Character_String_Literal:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static EvalNode.Type getTypeByParseCode(int parseCode) {
+ switch(parseCode) {
+ case SQLParser.AND:
+ return EvalNode.Type.AND;
+ case SQLParser.OR:
+ return EvalNode.Type.OR;
+ case SQLParser.LIKE:
+ return EvalNode.Type.LIKE;
+ case SQLParser.EQUAL:
+ return EvalNode.Type.EQUAL;
+ case SQLParser.NOT_EQUAL:
+ return EvalNode.Type.NOT_EQUAL;
+ case SQLParser.LTH:
+ return EvalNode.Type.LTH;
+ case SQLParser.LEQ:
+ return EvalNode.Type.LEQ;
+ case SQLParser.GTH:
+ return EvalNode.Type.GTH;
+ case SQLParser.GEQ:
+ return EvalNode.Type.GEQ;
+ case SQLParser.NOT:
+ return EvalNode.Type.NOT;
+ case SQLParser.PLUS:
+ return EvalNode.Type.PLUS;
+ case SQLParser.MINUS:
+ return EvalNode.Type.MINUS;
+ case SQLParser.MULTIPLY:
+ return EvalNode.Type.MULTIPLY;
+ case SQLParser.DIVIDE:
+ return EvalNode.Type.DIVIDE;
+ case SQLParser.MODULAR:
+ return EvalNode.Type.MODULAR;
+ default: throw new InvalidEvalException("We does not support " + parseCode + " type AST yet");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParserException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParserException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParserException.java
new file mode 100644
index 0000000..b6890f9
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/ParserException.java
@@ -0,0 +1,54 @@
+/**
+ * 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.tajo.engine.parser;
+
+public class ParserException extends RuntimeException {
+ private static final long serialVersionUID = -4392842405539056555L;
+
+ /**
+ *
+ */
+ public ParserException() {
+ }
+
+ /**
+ * @param message
+ */
+ public ParserException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public ParserException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public ParserException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/QueryAnalyzer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/QueryAnalyzer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/QueryAnalyzer.java
new file mode 100644
index 0000000..fa5475a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/QueryAnalyzer.java
@@ -0,0 +1,1336 @@
+/**
+ * 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.tajo.engine.parser;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.Tree;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.catalog.*;
+import org.apache.tajo.catalog.exception.NoSuchTableException;
+import org.apache.tajo.catalog.function.AggFunction;
+import org.apache.tajo.catalog.function.GeneralFunction;
+import org.apache.tajo.catalog.proto.CatalogProtos.FunctionType;
+import org.apache.tajo.catalog.proto.CatalogProtos.IndexMethod;
+import org.apache.tajo.catalog.proto.CatalogProtos.StoreType;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.common.TajoDataTypes.Type;
+import org.apache.tajo.common.exception.NotImplementedException;
+import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.parser.QueryBlock.*;
+import org.apache.tajo.engine.planner.JoinType;
+import org.apache.tajo.engine.planner.PlanningContext;
+import org.apache.tajo.engine.planner.PlanningContextImpl;
+import org.apache.tajo.engine.query.exception.*;
+import org.apache.tajo.exception.InternalException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class transforms a query statement into a QueryBlock.
+ *
+ * @see org.apache.tajo.engine.parser.QueryBlock
+ */
+public final class QueryAnalyzer {
+ private static final Log LOG = LogFactory.getLog(QueryAnalyzer.class);
+ private final CatalogService catalog;
+
+ public QueryAnalyzer(CatalogService catalog) {
+ this.catalog = catalog;
+ }
+
+ public PlanningContext parse(final String query) {
+
+ CommonTree ast;
+ PlanningContextImpl context;
+ try {
+ ast = parseTree(query);
+ context = new PlanningContextImpl(query);
+ ParseTree parseTree = parseQueryTree(context,ast);
+ context.setParseTree(parseTree);
+ } catch (TQLParseError e) {
+ throw new TQLSyntaxError(query, e.getMessage());
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Analyzer: " + ast.toStringTree());
+ }
+
+ return context;
+ }
+
+ private ParseTree parseQueryTree(PlanningContextImpl context,
+ final CommonTree ast) {
+ ParseTree parseTree = null;
+
+ switch (getCmdType(ast)) {
+ case SELECT:
+ parseTree = parseSelectStatement(context, ast);
+ break;
+
+ case UNION:
+ case EXCEPT:
+ case INTERSECT:
+ parseTree = parseSetStatement(context, ast);
+ break;
+
+ case CREATE_INDEX:
+ parseTree = parseIndexStatement(context, ast);
+ break;
+
+ case CREATE_TABLE:
+ parseTree = parseCreateStatement(context, ast);
+ break;
+
+ case COPY:
+ parseTree = parseCopyStatement(context, ast);
+ break;
+
+ default:
+ break;
+ }
+
+ return parseTree;
+ }
+
+ private CopyStmt parseCopyStatement(final PlanningContextImpl context,
+ final CommonTree ast) {
+ CopyStmt stmt = new CopyStmt(context);
+ int idx = 0;
+ stmt.setTableName(ast.getChild(idx++).getText());
+ Path path = new Path(ast.getChild(idx++).getText());
+ stmt.setPath(path);
+ StoreType storeType = CatalogUtil.getStoreType(ast.getChild(idx).getText());
+ stmt.setStoreType(storeType);
+
+ if ((ast.getChildCount() - idx) > 1) {
+ idx++;
+ if (ast.getChild(idx).getType() == SQLParser.PARAMS) {
+ Options options = parseParams((CommonTree) ast.getChild(idx));
+ stmt.setParams(options);
+ }
+ }
+
+ return stmt;
+ }
+
+ /**
+ * t=table ASSIGN select_stmt -> ^(CREATE_TABLE $t select_stmt)
+ * | CREATE TABLE t=table AS select_stmt -> ^(CREATE_TABLE $t select_stmt)
+ *
+ * @param ast
+ * @return
+ */
+ private CreateTableStmt parseCreateStatement(final PlanningContextImpl context,
+ final CommonTree ast) {
+ CreateTableStmt stmt;
+
+ int idx = 0;
+ CommonTree node;
+ String tableName = ast.getChild(idx).getText();
+ idx++;
+
+ boolean external = false;
+ Schema tableDef = null;
+ StoreType storeType = null;
+ Options options = null;
+ QueryBlock selectStmt = null;
+ Path location = null;
+ while(idx < ast.getChildCount()) {
+ node = (CommonTree) ast.getChild(idx);
+ switch (node.getType()) {
+ case SQLParser.EXTERNAL:
+ external = true;
+ break;
+
+ case SQLParser.TABLE_DEF:
+ tableDef = parseCreateTableDef(node);
+ break;
+
+ case SQLParser.FORMAT:
+ case SQLParser.USING:
+ storeType = CatalogUtil.getStoreType(node.getChild(0).getText());
+ break;
+
+ case SQLParser.PARAMS:
+ options = parseParams(node);
+ break;
+
+ case SQLParser.AS:
+ selectStmt = parseSelectStatement(context, (CommonTree) node.getChild(0));
+ break;
+
+ case SQLParser.LOCATION:
+ location = new Path(node.getChild(0).getText());
+ break;
+
+ default:
+ throw new NotSupportQueryException("ERROR: not yet supported query");
+ }
+ idx++;
+ }
+
+ if (selectStmt != null) {
+ stmt = new CreateTableStmt(context, tableName, selectStmt);
+ } else {
+ stmt = new CreateTableStmt(context, tableName);
+ if (external) {
+ if (location != null) {
+ stmt.setPath(location);
+ }
+ }
+ }
+
+ if (tableDef != null) {
+ stmt.setTableDef(tableDef);
+ }
+
+ if (storeType != null) {
+ stmt.setStoreType(storeType);
+ if (options != null) {
+ stmt.setOptions(options);
+ }
+ }
+
+ // constraints
+ if (external && location == null) {
+ throw new TQLSyntaxError(context.getRawQuery(), "CREATE EXTERNAL TABLE statement requires LOCATION clause.");
+ }
+ if (!external && location != null) {
+ throw new TQLSyntaxError(context.getRawQuery(), "LOCATION clause can be only used in CREATE EXTERNAL TABLE statement.");
+ }
+ if (tableDef == null && location != null) {
+ throw new TQLSyntaxError(context.getRawQuery(), "LOCATION clause requires a schema definition.");
+ }
+
+ return stmt;
+ }
+
+ private Schema parseCreateTableDef(final CommonTree ast) {
+ Schema tableDef = new Schema();
+ Type type;
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ Tree child = ast.getChild(i).getChild(1);
+ switch(child.getType()) {
+ case SQLParser.BOOLEAN: type = Type.BOOLEAN; break;
+ case SQLParser.BIT: type = Type.BIT; break;
+
+ case SQLParser.INT1:
+ case SQLParser.INT2:
+ type = Type.INT2;
+ break;
+
+ case SQLParser.INT4: type = Type.INT4; break;
+ case SQLParser.INT8: type = Type.INT8; break;
+ case SQLParser.FLOAT4: type = Type.FLOAT4; break;
+ case SQLParser.FLOAT:
+ if (child.getChildCount() > 0) {
+ int length = Integer.valueOf(child.getChild(0).getText());
+ if (length < 1 || length > 53) {
+ throw new InvalidQueryException("ERROR: floating point precision " + length + " is out of range");
+ }
+ if (length > 25) {
+ type = Type.FLOAT8;
+ } else {
+ type = Type.FLOAT4;
+ }
+ } else { // no given length
+ type = Type.FLOAT8;
+ }
+ break;
+ case SQLParser.FLOAT8:
+ type = Type.FLOAT8; break;
+ case SQLParser.TEXT: type = Type.TEXT; break;
+ case SQLParser.BLOB: type = Type.BLOB; break;
+ case SQLParser.INET4: type = Type.INET4;
+ break;
+
+ case SQLParser.CHAR:
+ case SQLParser.NCHAR:
+ case SQLParser.NUMERIC:
+ case SQLParser.VARCHAR:
+ case SQLParser.NVARCHAR:
+ case SQLParser.BINARY:
+ case SQLParser.VARBINARY:
+ throw new NotImplementedException("ERROR: " + child.toString() +
+ " type is not supported yet");
+
+ default: throw new InvalidQueryException(ast.toStringTree());
+ }
+
+ tableDef.addColumn(ast.getChild(i).getChild(0).getText(), type);
+ }
+
+ return tableDef;
+ }
+
+ private SetStmt parseSetStatement(final PlanningContextImpl context,
+ final CommonTree ast) {
+ StatementType type;
+ boolean distinct = true;
+ ParseTree left;
+ ParseTree right;
+
+ switch (ast.getType()) {
+ case SQLParser.UNION:
+ type = StatementType.UNION;
+ break;
+ case SQLParser.EXCEPT:
+ type = StatementType.EXCEPT;
+ break;
+ case SQLParser.INTERSECT:
+ type = StatementType.INTERSECT;
+ break;
+ default:
+ throw new InvalidQueryException("Illegal AST:\n" + ast.toStringTree());
+ }
+
+ int idx = 0;
+ left = parseQueryTree(context, (CommonTree) ast.getChild(idx));
+ idx++;
+ int nodeType = ast.getChild(idx).getType();
+ if (nodeType == SQLParser.ALL) {
+ distinct = true;
+ idx++;
+ } else if (nodeType == SQLParser.DISTINCT) {
+ distinct = false;
+ idx++;
+ }
+ right = parseQueryTree(context, (CommonTree) ast.getChild(idx));
+ return new SetStmt(context, type, left, right, distinct);
+ }
+
+ private QueryBlock parseSelectStatement(PlanningContext context,
+ final CommonTree ast) {
+
+ QueryBlock block = new QueryBlock(context);
+
+ CommonTree node;
+ for (int cur = 0; cur < ast.getChildCount(); cur++) {
+ node = (CommonTree) ast.getChild(cur);
+
+ switch (node.getType()) {
+ case SQLParser.FROM:
+ parseFromClause(context, block, node);
+ break;
+
+ case SQLParser.SET_QUALIFIER:
+ parseSetQualifier(block, node);
+ break;
+
+ case SQLParser.SEL_LIST:
+ parseSelectList(context, block, node);
+ break;
+
+ case SQLParser.WHERE:
+ parseWhereClause(context, block, node);
+ break;
+
+ case SQLParser.GROUP_BY:
+ parseGroupByClause(context, block, node);
+ break;
+
+ case SQLParser.HAVING:
+ parseHavingClause(context, block, node);
+ break;
+
+ case SQLParser.ORDER_BY:
+ SortSpec[] sortKeys = parseSortSpecifiers(context, block,
+ (CommonTree) node.getChild(0));
+ block.setSortKeys(sortKeys);
+ break;
+
+ case SQLParser.LIMIT:
+ block.setLimit(parseLimitClause(context, block, node));
+ break;
+
+ default:
+
+ }
+ }
+
+ return block;
+ }
+
+ private void parseSetQualifier(final QueryBlock block, final CommonTree ast) {
+ int idx = 0;
+
+ if (ast.getChild(idx).getType() == SQLParser.DISTINCT) {
+ block.setDistinct();
+ }
+ }
+
+ /**
+ * EBNF: CREATE (UNIQUE?) INDEX n=ID ON t=ID LEFT_PAREN s=sort_specifier_list
+ * RIGHT_PAREN p=param_clause? <br />
+ * AST: ^(CREATE_INDEX $n $t $s $p)
+ *
+ * @param ast
+ */
+ private CreateIndexStmt parseIndexStatement(PlanningContext context,
+ final CommonTree ast) {
+ CreateIndexStmt indexStmt = new CreateIndexStmt(context);
+
+ int idx = 0;
+ boolean unique = false;
+ // the below things are optional
+ if (ast.getChild(idx).getType() == SQLParser.UNIQUE) {
+ unique = true;
+ idx++;
+ }
+
+ IndexMethod method = null;
+ if (ast.getChild(idx).getType() == SQLParser.USING) {
+ method = getIndexMethod(ast.getChild(idx).getText());
+ idx++;
+ }
+
+ // It's optional, so it can be null if there is no params clause.
+ Options params = null;
+ if (ast.getChild(idx).getType() == SQLParser.PARAMS) {
+ params = parseParams((CommonTree) ast.getChild(idx));
+ idx++;
+ }
+
+ // They are required, so they are always filled.
+ String idxName = ast.getChild(idx++).getText();
+ String tbName = ast.getChild(idx++).getText();
+ indexStmt.setIndexName(idxName);
+ indexStmt.setTableName(tbName);
+
+ SortSpec [] sortSpecs = parseSortSpecifiers(context, indexStmt,
+ (CommonTree) ast.getChild(idx++));
+
+ if (unique) {
+ indexStmt.setUnique();
+ }
+ indexStmt.setSortSpecs(sortSpecs);
+
+ if (method != null) {
+ indexStmt.setMethod(method);
+ }
+
+ if (params != null) {
+ indexStmt.setParams(params);
+ }
+
+ return indexStmt;
+ }
+
+ /**
+ * EBNF: table_list -> tableRef (COMMA tableRef)
+ * @param block
+ * @param ast
+ */
+ private void parseFromClause(PlanningContext context,
+ final QueryBlock block, final CommonTree ast) {
+ // implicit join or the from clause on single relation
+ boolean isPrevJoin = false;
+ FromTable table = null;
+ JoinClause joinClause = null;
+ CommonTree node;
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ node = (CommonTree) ast.getChild(i);
+
+ switch (node.getType()) {
+
+ case SQLParser.TABLE:
+ // table (AS ID)?
+ // 0 - a table name, 1 - table alias
+ table = parseTable(node);
+ block.addFromTable(table, true);
+ break;
+ case SQLParser.JOIN:
+ QueryBlock.JoinClause newJoin = parseExplicitJoinClause(context, block, node);
+ if (isPrevJoin) {
+ newJoin.setLeft(joinClause);
+ joinClause = newJoin;
+ } else {
+ newJoin.setLeft(table);
+ isPrevJoin = true;
+ joinClause = newJoin;
+ }
+ break;
+ default:
+ throw new TQLSyntaxError(context.getRawQuery(), "Wrong From Clause");
+ } // switch
+ } // for each derievedTable
+
+ if (joinClause != null) {
+ block.setJoinClause(joinClause);
+ }
+ }
+
+
+ private JoinClause parseExplicitJoinClause(final PlanningContext context,
+ final QueryBlock block,
+ final CommonTree ast) {
+
+ int idx = 0;
+ int parsedJoinType = ast.getChild(idx).getType();
+
+ JoinClause joinClause;
+
+ switch (parsedJoinType) {
+ case SQLParser.CROSS:
+ case SQLParser.UNION:
+ joinClause = parseCrossAndUnionJoin(context, block, ast);
+ break;
+
+ case SQLParser.NATURAL:
+ joinClause = parseNaturalJoinClause(context, block, ast);
+ break;
+
+ case SQLParser.INNER:
+ case SQLParser.OUTER:
+ joinClause = parseQualifiedJoinClause(context, block, ast, 0);
+ break;
+
+ default: // default join (without join type) is inner join
+ joinClause = parseQualifiedJoinClause(context, block, ast, 0);
+ }
+
+ return joinClause;
+ }
+
+ private JoinClause parseNaturalJoinClause(final PlanningContext context,
+ final QueryBlock block, Tree ast) {
+ JoinClause join = parseQualifiedJoinClause(context, block, ast, 1);
+ join.setNatural();
+ return join;
+ }
+
+ private JoinClause parseQualifiedJoinClause(PlanningContext context,
+ QueryBlock block,
+ Tree ast, final int idx) {
+ int childIdx = idx;
+ JoinClause join = null;
+
+ if (ast.getChild(childIdx).getType() == SQLParser.TABLE) { // default join
+ join = new JoinClause(JoinType.INNER);
+ join.setRight(parseTable((CommonTree) ast.getChild(childIdx)));
+ block.addFromTable(join.getRight(), true);
+
+ } else {
+
+ if (ast.getChild(childIdx).getType() == SQLParser.INNER) {
+ join = new JoinClause(JoinType.INNER);
+
+ } else if (ast.getChild(childIdx).getType() == SQLParser.OUTER) {
+
+ switch (ast.getChild(childIdx).getChild(0).getType()) {
+ case SQLParser.LEFT:
+ join = new JoinClause(JoinType.LEFT_OUTER);
+ break;
+ case SQLParser.RIGHT:
+ join = new JoinClause(JoinType.RIGHT_OUTER);
+ break;
+ case SQLParser.FULL:
+ join = new JoinClause(JoinType.FULL_OUTER);
+ break;
+ default:
+ throw new TQLSyntaxError(context.getRawQuery(), "Unknown Join Type");
+ }
+ }
+
+ childIdx++;
+ join.setRight(parseTable((CommonTree) ast.getChild(childIdx)));
+ block.addFromTable(join.getRight(), true);
+ }
+
+ childIdx++;
+
+ if (ast.getChildCount() > childIdx) {
+ CommonTree joinQual = (CommonTree) ast.getChild(childIdx);
+
+ if (joinQual.getType() == SQLParser.ON) {
+ EvalNode joinCond = parseJoinCondition(context, block, joinQual);
+ join.setJoinQual(joinCond);
+
+ } else if (joinQual.getType() == SQLParser.USING) {
+ Column[] joinColumns = parseJoinColumns(context, block, joinQual);
+ join.setJoinColumns(joinColumns);
+ }
+ }
+
+ return join;
+ }
+
+ private JoinClause parseCrossAndUnionJoin(final PlanningContext context,
+ final QueryBlock block, Tree ast) {
+ JoinType joinType;
+
+ if (ast.getChild(0).getType() == SQLParser.CROSS) {
+ joinType = JoinType.CROSS_JOIN;
+ } else if (ast.getChild(0).getType() == SQLParser.UNION) {
+ joinType = JoinType.UNION;
+ } else {
+ throw new IllegalStateException("Neither the AST has cross join or union join:\n" + ast.toStringTree());
+ }
+
+ JoinClause join = new JoinClause(joinType);
+ Preconditions.checkState(ast.getChild(1).getType() == SQLParser.TABLE);
+ join.setRight(parseTable((CommonTree) ast.getChild(1)));
+ block.addFromTable(join.getRight(), true);
+
+ return join;
+ }
+
+ private Column [] parseJoinColumns(final PlanningContext context,
+ final QueryBlock block,
+ final CommonTree ast) {
+ Column [] joinColumns = new Column[ast.getChildCount()];
+
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ joinColumns[i] = checkAndGetColumnByAST(context,
+ block, (CommonTree) ast.getChild(i));
+ }
+ return joinColumns;
+ }
+
+ private EvalNode parseJoinCondition(final PlanningContext context,
+ QueryBlock tree, CommonTree ast) {
+ return createEvalTree(context, tree, ast.getChild(0));
+ }
+
+ private FromTable parseTable(final CommonTree tableAST) {
+ String tableName = tableAST.getChild(0).getText();
+ TableDesc desc = checkAndGetTableByName(tableName);
+ FromTable table;
+
+ if (tableAST.getChildCount() > 1) {
+ table = new FromTable(desc,
+ tableAST.getChild(1).getText());
+ } else {
+ table = new FromTable(desc);
+ }
+
+ return table;
+ }
+
+ /**
+ * This method parses the select list of a query statement.
+ * <pre>
+ * EBNF:
+ *
+ * selectList
+ * : MULTIPLY -> ^(SEL_LIST ALL)
+ * | derivedColumn (COMMA derivedColumn)* -> ^(SEL_LIST derivedColumn+)
+ * ;
+ *
+ * derivedColumn
+ * : bool_expr asClause? -> ^(COLUMN bool_expr asClause?)
+ * ;
+ *
+ * @param block
+ * @param ast
+ */
+ private void parseSelectList(final PlanningContext context,
+ final QueryBlock block, final CommonTree ast) {
+
+ if (ast.getChild(0).getType() == SQLParser.ALL) {
+ block.setProjectAll();
+ } else {
+ CommonTree node;
+ int numTargets = ast.getChildCount();
+ Target [] targets = new Target[numTargets];
+ EvalNode evalTree;
+ String alias;
+
+ // the final one for each target is the alias
+ // EBNF: bool_expr AS? fieldName
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ node = (CommonTree) ast.getChild(i);
+ evalTree = createEvalTree(context, block, node);
+ targets[i] = new Target(evalTree, i);
+ if (node.getChildCount() > 1) {
+ alias = node.getChild(node.getChildCount() - 1).getChild(0).getText();
+ targets[i].setAlias(alias);
+ }
+ }
+
+ block.setTargetList(targets);
+ }
+ }
+
+ private void parseWhereClause(final PlanningContext context,
+ final QueryBlock block, final CommonTree ast) {
+ EvalNode whereCond = createEvalTree(context, block, ast.getChild(0));
+ block.setWhereCondition(whereCond);
+ }
+
+ /**
+ * See 'groupby_clause' rule in NQL.g
+ *
+ * @param block
+ * @param ast
+ */
+ private void parseGroupByClause(final PlanningContext context,
+ final QueryBlock block,
+ final CommonTree ast) {
+ GroupByClause clause = new GroupByClause();
+
+ int idx = 0;
+
+ if (ast.getChild(idx).getType() == SQLParser.EMPTY_GROUPING_SET) {
+ clause.setEmptyGroupSet();
+ } else {
+ // the remain ones are grouping fields.
+ Tree group;
+ List<Column> columnRefs = new ArrayList<Column>();
+ Column [] columns;
+ Column column;
+ for (; idx < ast.getChildCount(); idx++) {
+ group = ast.getChild(idx);
+ switch (group.getType()) {
+ case SQLParser.CUBE:
+ columns = parseColumnReferences(context, block, (CommonTree) group);
+ GroupElement cube = new GroupElement(GroupType.CUBE, columns);
+ clause.addGroupSet(cube);
+ break;
+
+ case SQLParser.ROLLUP:
+ columns = parseColumnReferences(context, block, (CommonTree) group);
+ GroupElement rollup = new GroupElement(GroupType.ROLLUP, columns);
+ clause.addGroupSet(rollup);
+ break;
+
+ case SQLParser.FIELD_NAME:
+ column = checkAndGetColumnByAST(context, block, (CommonTree) group);
+ columnRefs.add(column);
+ break;
+ }
+ }
+
+ if (columnRefs.size() > 0) {
+ Column [] groupingFields = columnRefs.toArray(new Column[columnRefs.size()]);
+ GroupElement g = new GroupElement(GroupType.GROUPBY, groupingFields);
+ clause.addGroupSet(g);
+ }
+ }
+
+ block.setGroupByClause(clause);
+ }
+
+ private void parseHavingClause(final PlanningContext context,
+ final QueryBlock block, final CommonTree ast) {
+ EvalNode evalTree =
+ createEvalTree(context, block, ast.getChild(0));
+ block.setHavingCond(evalTree);
+ }
+
+ /**
+ * Should be given Params Node
+ *
+ * EBNF: WITH LEFT_PAREN param (COMMA param)* RIGHT_PAREN
+ * AST: ^(PARAMS param+)
+ *
+ * @param ast
+ * @return
+ */
+ private static Options parseParams(final CommonTree ast) {
+ Options params = new Options();
+
+ Tree child;
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ child = ast.getChild(i);
+ params.put(child.getChild(0).getText(), child.getChild(1).getText());
+ }
+ return params;
+ }
+
+
+ /**
+ * Should be given SortSpecifiers Node
+ *
+ * EBNF: sort_specifier (COMMA sort_specifier)* -> sort_specifier+
+ *
+ * @param tree
+ * @param ast
+ */
+ private SortSpec[] parseSortSpecifiers(final PlanningContext context,
+ final ParseTree tree,
+ final CommonTree ast) {
+ int numSortKeys = ast.getChildCount();
+ SortSpec[] sortKeys = new SortSpec[numSortKeys];
+ CommonTree node;
+ Column column;
+
+ // Each child has the following EBNF and AST:
+ // EBNF: fn=fieldName a=order_specification? o=null_ordering?
+ // AST: ^(SORT_KEY $fn $a? $o?)
+ for (int i = 0; i < numSortKeys; i++) {
+ node = (CommonTree) ast.getChild(i);
+ column = checkAndGetColumnByAST(context, tree, (CommonTree) node.getChild(0));
+ sortKeys[i] = new SortSpec(column);
+
+ if (node.getChildCount() > 1) {
+ Tree child;
+ for (int j = 1; j < node.getChildCount(); j++) {
+ child = node.getChild(j);
+
+ // AST: ^(ORDER ASC) | ^(ORDER DESC)
+ if (child.getType() == SQLParser.ORDER) {
+ if (child.getChild(0).getType() == SQLParser.DESC) {
+ sortKeys[i].setDescOrder();
+ }
+ } else if (child.getType() == SQLParser.NULL_ORDER) {
+ // AST: ^(NULL_ORDER FIRST) | ^(NULL_ORDER LAST)
+ if (child.getChild(0).getType() == SQLParser.FIRST) {
+ sortKeys[i].setNullFirst();
+ }
+ }
+ }
+ }
+ }
+
+ return sortKeys;
+ }
+
+ private LimitClause parseLimitClause(final PlanningContext context,
+ final ParseTree tree,
+ final CommonTree ast) {
+ EvalNode evalNode = createEvalTree(context, (QueryBlock) tree, ast.getChild(0));
+
+
+ if (evalNode instanceof ConstEval) {
+ ConstEval fetchFirst = (ConstEval) evalNode;
+ LimitClause limitClause = new LimitClause(fetchFirst.getValue().asInt8());
+ return limitClause;
+ }
+
+ throw new TQLSyntaxError(context.getRawQuery(), "LIMIT clause cannot have the parameter "
+ + evalNode);
+ }
+
+ private Column checkAndGetColumnByAST(final PlanningContext context,
+ final ParseTree tree,
+ final CommonTree fieldNode) {
+ Preconditions.checkArgument(SQLParser.FIELD_NAME == fieldNode.getType());
+
+ String columnName = fieldNode.getChild(0).getText();
+ String tableName = null;
+ if (fieldNode.getChildCount() > 1) {
+ tableName = fieldNode.getChild(1).getText();
+ }
+
+ Column column;
+ if(tableName != null) {
+ TableDesc desc;
+ desc = checkAndGetTableByMappedName(context, tree, tableName);
+ column = checkAndGetFieldByName(desc, columnName);
+ } else {
+ column = expectTableByField(context, tree, columnName);
+ }
+
+ return column;
+ }
+
+ private TableDesc checkAndGetTableByMappedName(PlanningContext context,
+ ParseTree tree,
+ final String tableName) {
+ String realName = tree.getTableNameByAlias(tableName);
+ return checkAndGetTableByName(realName);
+ }
+
+ private TableDesc checkAndGetTableByName(final String tableName) {
+ TableDesc desc;
+
+ try {
+ desc = catalog.getTableDesc(tableName);
+ } catch (NoSuchTableException nst) {
+ throw new InvalidQueryException("ERROR: table \"" + tableName
+ + "\" does not exist");
+ }
+
+ return desc;
+ }
+
+ private static Column checkAndGetFieldByName(final TableDesc desc,
+ final String columnName) {
+ Column column;
+
+ column = desc.getMeta().getSchema().getColumn(desc.getId()+"."+columnName);
+ if(column == null) {
+ throw new InvalidQueryException("ERROR: column \"" + columnName
+ + "\" does not exist");
+ }
+
+ return column;
+ }
+
+ /**
+ * determine a column by finding tables which are given by 'from clause'.
+ *
+ * @param tree
+ * @param columnName field name to be find
+ * @return a found column
+ */
+ private Column expectTableByField(final PlanningContext context,
+ final ParseTree tree, String columnName) {
+ TableDesc desc;
+ Schema schema;
+ Column column = null;
+ int count = 0;
+
+ // find a column corresponding to the given column name from tables of the catalog
+ for(String table : tree.getAllTableNames()) {
+ desc =
+ catalog.getTableDesc(table);
+ schema = desc.getMeta().getSchema();
+
+ if(schema.contains(table+"."+columnName)) {
+ column = schema.getColumn(table+"."+columnName);
+ count++;
+ }
+ }
+
+ // find a column corresponding to the given column name from the target list
+ if (tree instanceof QueryBlock) {
+ QueryBlock block = ((QueryBlock)tree);
+ if (block.getTargetList() != null) {
+ for (Target target : block.getTargetList()) {
+ if (target.hasAlias() && target.getAlias().equals(columnName)) {
+ try {
+ column = (Column) target.getColumnSchema().clone();
+ column.setName(target.getAlias());
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ count++;
+ }
+ }
+ }
+ }
+
+ // if there are more than one column, we cannot exactly expect
+ // that this column belongs to which table.
+ if(count > 1)
+ throw new AmbiguousFieldException(columnName);
+
+
+ if(column == null) { // if there are no matched column
+ throw new InvalidQueryException("ERROR: column \"" + columnName
+ + "\" does not exist");
+ }
+
+ return column;
+ }
+
+ private static CommonTree parseTree(final String query) {
+ ANTLRStringStream input = new ANTLRStringStream(query);
+ SQLLexer lexer = new SQLLexer(input);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ SQLParser parser = new SQLParser(tokens);
+
+ CommonTree ast;
+ try {
+ ast = ((CommonTree) parser.statement().getTree());
+ } catch (RecognitionException e) {
+ throw new TQLParseError(e.getMessage());
+ }
+
+ return ast;
+ }
+
+ private static StatementType getCmdType(final CommonTree ast) {
+ switch (ast.getType()) {
+ case SQLParser.STORE:
+ return StatementType.STORE;
+ case SQLParser.SELECT:
+ return StatementType.SELECT;
+ case SQLParser.UNION:
+ return StatementType.UNION;
+ case SQLParser.EXCEPT:
+ return StatementType.EXCEPT;
+ case SQLParser.INTERSECT:
+ return StatementType.INTERSECT;
+ case SQLParser.INSERT:
+ return StatementType.INSERT;
+ case SQLParser.CREATE_INDEX:
+ return StatementType.CREATE_INDEX;
+ case SQLParser.CREATE_TABLE:
+ return StatementType.CREATE_TABLE;
+ case SQLParser.DROP_TABLE:
+ return StatementType.DROP_TABLE;
+ case SQLParser.SHOW_TABLE:
+ return StatementType.SHOW_TABLES;
+ case SQLParser.DESC_TABLE:
+ return StatementType.DESC_TABLE;
+ case SQLParser.SHOW_FUNCTION:
+ return StatementType.SHOW_FUNCTION;
+ default:
+ return null;
+ }
+ }
+
+ private static IndexMethod getIndexMethod(String method) {
+ Preconditions.checkNotNull(method);
+ if (method.equals("bst")) {
+ return IndexMethod.TWO_LEVEL_BIN_TREE;
+ } else if (method.equals("btree")) {
+ return IndexMethod.BTREE;
+ } else if (method.equals("hash")) {
+ return IndexMethod.HASH;
+ } else if (method.equals("bitmap")) {
+ return IndexMethod.BITMAP;
+ } else {
+ throw new TQLParseError("ERROR: unknown index: " + method);
+ }
+ }
+
+ public EvalNode createEvalTree(final PlanningContext context,
+ final QueryBlock tree, final Tree ast) {
+ switch(ast.getType()) {
+
+ // constants
+ case SQLParser.NUMBER:
+ return new ConstEval(DatumFactory.createInt4(
+ Integer.valueOf(ast.getText())));
+
+ case SQLParser.REAL_NUMBER:
+ return new ConstEval(DatumFactory.createFloat4(
+ Float.valueOf(ast.getText())));
+
+ case SQLParser.Character_String_Literal:
+ return new ConstEval(DatumFactory.createText(ast.getText()));
+
+ // unary expression
+ case SQLParser.NOT:
+ return new NotEval(createEvalTree(context, tree, ast.getChild(0)));
+
+ // binary expressions
+ case SQLParser.LIKE:
+ return parseLike(context, tree, ast);
+
+ case SQLParser.IS:
+ return parseIsNullPredicate(context, tree, ast);
+
+ case SQLParser.AND:
+ case SQLParser.OR:
+ case SQLParser.EQUAL:
+ case SQLParser.NOT_EQUAL:
+ case SQLParser.LTH:
+ case SQLParser.LEQ:
+ case SQLParser.GTH:
+ case SQLParser.GEQ:
+ case SQLParser.PLUS:
+ case SQLParser.MINUS:
+ case SQLParser.MULTIPLY:
+ case SQLParser.DIVIDE:
+ case SQLParser.MODULAR:
+ return parseBinaryExpr(context, tree, ast);
+
+ // others
+ case SQLParser.COLUMN:
+ return createEvalTree(context, tree, ast.getChild(0));
+
+ case SQLParser.FIELD_NAME:
+ Column column = checkAndGetColumnByAST(context, tree, (CommonTree) ast);
+ return new FieldEval(column);
+
+ case SQLParser.FUNCTION:
+ String signature = ast.getText();
+
+ EvalNode [] givenArgs = new EvalNode[ast.getChildCount()];
+ DataType [] paramTypes = new DataType[ast.getChildCount()];
+
+ for (int i = 0; i < ast.getChildCount(); i++) {
+ givenArgs[i] = createEvalTree(context, tree, ast.getChild(i));
+ paramTypes[i] = givenArgs[i].getValueType()[0];
+ }
+ if (!catalog.containFunction(signature, paramTypes)) {
+ throw new UndefinedFunctionException(
+ CatalogUtil.getCanonicalName(signature, paramTypes));
+ }
+ FunctionDesc funcDesc = catalog.getFunction(signature, paramTypes);
+
+ try {
+ if (funcDesc.getFuncType() == FunctionType.GENERAL)
+
+ return new FuncCallEval(funcDesc,
+ (GeneralFunction) funcDesc.newInstance(), givenArgs);
+ else {
+ tree.setAggregation();
+
+ return new AggFuncCallEval(funcDesc,
+ (AggFunction) funcDesc.newInstance(), givenArgs);
+ }
+ } catch (InternalException e) {
+ e.printStackTrace();
+ }
+
+ break;
+ case SQLParser.COUNT_VAL:
+ // Getting the first argument
+ EvalNode colRef = createEvalTree(context, tree, ast.getChild(0));
+
+ FunctionDesc countVals = catalog.getFunction("count",
+ CatalogUtil.newDataTypeWithoutLen(Type.ANY));
+ tree.setAggregation();
+ try {
+ return new AggFuncCallEval(countVals, (AggFunction) countVals.newInstance(),
+ new EvalNode [] {colRef});
+ } catch (InternalException e1) {
+ e1.printStackTrace();
+ }
+ break;
+
+ case SQLParser.COUNT_ROWS:
+ FunctionDesc countRows = catalog.getFunction("count", new DataType [] {});
+ tree.setAggregation();
+ try {
+ return new AggFuncCallEval(countRows, (AggFunction) countRows.newInstance(),
+ new EvalNode [] {});
+ } catch (InternalException e) {
+ e.printStackTrace();
+ }
+ break;
+
+ case SQLParser.CASE:
+ return parseCaseWhen(context, tree, ast);
+
+ default:
+ }
+ return null;
+ }
+
+ public IsNullEval parseIsNullPredicate(final PlanningContext context,
+ QueryBlock block, Tree tree) {
+ boolean not;
+
+ Preconditions.checkArgument(tree.getType() == SQLParser.IS, "The AST is not IS (NOT) NULL clause");
+ int idx = 0;
+
+ FieldEval field = (FieldEval) createEvalTree(context, block,
+ tree.getChild(idx++));
+ Preconditions.checkArgument(
+ tree.getChild(idx++).getType() == SQLParser.NULL,
+ "We does not support another kind of IS clause yet");
+ not = tree.getChildCount() == (idx + 1)
+ && tree.getChild(idx).getType() == SQLParser.NOT;
+
+ return new IsNullEval(not, field);
+ }
+
+ /**
+ * The EBNF of case statement
+ * <pre>
+ * searched_case
+ * : CASE s=searched_when_clauses e=else_clause END -> ^(CASE $s $e)
+ * ;
+ *
+ * searched_when_clauses
+ * : searched_when_clause searched_when_clause* -> searched_when_clause+
+ * ;
+ *
+ * searched_when_clause
+ * : WHEN c=search_condition THEN r=result -> ^(WHEN $c $r)
+ * ;
+ *
+ * else_clause
+ * : ELSE r=result -> ^(ELSE $r)
+ * ;
+ * </pre>
+ * @param block
+ * @param tree
+ * @return
+ */
+ public CaseWhenEval parseCaseWhen(final PlanningContext context,
+ final QueryBlock block, final Tree tree) {
+ int idx = 0;
+
+ CaseWhenEval caseEval = new CaseWhenEval();
+ EvalNode cond;
+ EvalNode thenResult;
+ Tree when;
+
+ for (; idx < tree.getChildCount() &&
+ tree.getChild(idx).getType() == SQLParser.WHEN; idx++) {
+
+ when = tree.getChild(idx);
+ cond = createEvalTree(context, block, when.getChild(0));
+ thenResult = createEvalTree(context, block, when.getChild(1));
+ caseEval.addWhen(cond, thenResult);
+ }
+
+ if (tree.getChild(idx) != null &&
+ tree.getChild(idx).getType() == SQLParser.ELSE) {
+ EvalNode elseResult = createEvalTree(context, block,
+ tree.getChild(idx).getChild(0));
+ caseEval.setElseResult(elseResult);
+ }
+
+ return caseEval;
+ }
+
+ public EvalNode parseDigitByTypeInfer(final PlanningContext context,
+ final QueryBlock block, final Tree tree,
+ DataType type) {
+ switch (type.getType()) {
+ case INT2:
+ return new ConstEval(DatumFactory.createInt2(tree.getText()));
+ case INT4:
+ return new ConstEval(DatumFactory.createInt4(tree.getText()));
+ case INT8 :
+ return new ConstEval(DatumFactory.createInt8(tree.getText()));
+ default: return createEvalTree(context, block, tree);
+ }
+ }
+
+ private EvalNode parseRealByTypeInfer(final PlanningContext context,
+ final QueryBlock block, final Tree tree,
+ DataType type) {
+ switch (type.getType()) {
+ case FLOAT4:
+ return new ConstEval(DatumFactory.createFloat4(tree.getText()));
+ case FLOAT8:
+ return new ConstEval(DatumFactory.createFloat8(tree.getText()));
+ default: return createEvalTree(context, block, tree);
+ }
+ }
+
+ private EvalNode parseStringByTypeInfer(final PlanningContext context,
+ final QueryBlock block,
+ final Tree tree,
+ DataType type) {
+ switch (type.getType()) {
+ case CHAR:
+ return new ConstEval(DatumFactory.createChar(tree.getText().charAt(0)));
+ case TEXT:
+ return new ConstEval(DatumFactory.createText(tree.getText()));
+ default: return createEvalTree(context, block, tree);
+ }
+ }
+
+ @VisibleForTesting
+ EvalNode parseBinaryExpr(final PlanningContext context,
+ final QueryBlock block, final Tree tree) {
+ int constId = -1;
+ int fieldId = -1;
+
+ for (int i = 0; i < 2; i++) {
+ if (ParseUtil.isConstant(tree.getChild(i))) {
+ constId = i;
+ } else if (tree.getChild(i).getType() == SQLParser.FIELD_NAME) {
+ fieldId = i;
+ }
+ }
+
+ if (constId != -1 && fieldId != -1) {
+ EvalNode [] exprs = new EvalNode[2];
+ exprs[fieldId] = createEvalTree(context, block,
+ tree.getChild(fieldId));
+
+ Tree constAst = tree.getChild(constId);
+
+ switch (tree.getChild(constId).getType()) {
+ case SQLParser.NUMBER:
+ exprs[constId] = parseDigitByTypeInfer(context, block, constAst,
+ exprs[fieldId].getValueType()[0]);
+ break;
+
+ case SQLParser.REAL_NUMBER:
+ exprs[constId] = parseRealByTypeInfer(context, block, constAst,
+ exprs[fieldId].getValueType()[0]);
+ break;
+
+ case SQLParser.Character_String_Literal:
+ exprs[constId] = parseStringByTypeInfer(context, block, constAst,
+ exprs[fieldId].getValueType()[0]);
+ break;
+
+ default: throw new org.apache.tajo.engine.eval.InvalidEvalException();
+ }
+
+ if (constId == 0) {
+ return new BinaryEval(ParseUtil.getTypeByParseCode(tree.getType()),
+ exprs[constId], exprs[fieldId]);
+ } else {
+ return new BinaryEval(ParseUtil.getTypeByParseCode(tree.getType()),
+ exprs[fieldId], exprs[constId]);
+ }
+
+ } else {
+ return new BinaryEval(ParseUtil.getTypeByParseCode(tree.getType()),
+ createEvalTree(context, block, tree.getChild(0)),
+ createEvalTree(context, block, tree.getChild(1)));
+ }
+ }
+
+ /**
+ * <pre>
+ * like_predicate : fieldName NOT? LIKE string_value_expr
+ * -> ^(LIKE NOT? fieldName string_value_expr)
+ * </pre>
+ * @param block
+ * @param tree
+ * @return
+ */
+ private LikeEval parseLike(final PlanningContext context,
+ final QueryBlock block, final Tree tree) {
+ int idx = 0;
+
+ boolean not = false;
+ if (tree.getChild(idx).getType() == SQLParser.NOT) {
+ not = true;
+ idx++;
+ }
+
+ FieldEval field = (FieldEval) createEvalTree(context, block,
+ tree.getChild(idx));
+ idx++;
+ ConstEval pattern = (ConstEval) createEvalTree(context, block,
+ tree.getChild(idx));
+
+ return new LikeEval(not, field, pattern);
+ }
+
+ /**
+ * It parses the below EBNF.
+ * <pre>
+ * column_reference
+ * : fieldName (COMMA fieldName)* -> fieldName+
+ * ;
+ * </pre>
+ * @param tree
+ * @param parent
+ * @return
+ */
+ private Column [] parseColumnReferences(final PlanningContext context,
+ final ParseTree tree,
+ final CommonTree parent) {
+ Column [] columns = new Column[parent.getChildCount()];
+
+ for (int i = 0; i < columns.length; i++) {
+ columns[i] = checkAndGetColumnByAST(context, tree,
+ (CommonTree) parent.getChild(i));
+ }
+
+ return columns;
+ }
+}