You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/09/04 09:35:02 UTC

[04/10] incubator-calcite git commit: [CALCITE-865] Unknown table type causes NullPointerException in JdbcSchema

[CALCITE-865] Unknown table type causes NullPointerException in JdbcSchema


Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/d69f2c20
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/d69f2c20
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/d69f2c20

Branch: refs/heads/master
Commit: d69f2c20c5a75977d50c182565d8e7b8e011515e
Parents: f98ed96
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 15:09:32 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Sep 3 15:09:32 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   |   4 +
 .../apache/calcite/adapter/jdbc/JdbcSchema.java |   6 +-
 .../apache/calcite/adapter/jdbc/JdbcTable.java  |   3 +-
 .../java/org/apache/calcite/schema/Schema.java  | 105 +++++++++++++++----
 .../main/java/org/apache/calcite/util/Util.java |  22 +++-
 .../apache/calcite/test/JdbcAdapterTest.java    |  35 +++++++
 6 files changed, 153 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index d9fab4d..fe61aaf 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -260,6 +260,10 @@ public interface Meta {
       this.s = s;
     }
 
+    @Override public String toString() {
+      return "Pat[" + s + "]";
+    }
+
     @JsonCreator
     public static Pat of(@JsonProperty("s") String name) {
       return new Pat(name);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
index 6495574..b83c76c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
@@ -201,6 +201,7 @@ public class JdbcSchema implements Schema {
         // returned by Phoenix among others, maps to TableType.SYSTEM_TABLE.
         // We know enum constants are upper-case without spaces, so we can't
         // make things worse.
+        //
         // PostgreSQL returns tableTypeName==null for pg_toast* tables
         // This can happen if you start JdbcSchema off a "public" PG schema
         // The tables are not designed to be queried by users, however we do
@@ -210,7 +211,10 @@ public class JdbcSchema implements Schema {
             ? null
             : tableTypeName.toUpperCase().replace(' ', '_');
         final TableType tableType =
-            Util.enumVal(TableType.class, tableTypeName2);
+            Util.enumVal(TableType.OTHER, tableTypeName2);
+        if (tableType == TableType.OTHER  && tableTypeName2 != null) {
+          System.out.println("Unknown table type: " + tableTypeName2);
+        }
         final JdbcTable table =
             new JdbcTable(this, catalogName, schemaName, tableName, tableType);
         builder.put(tableName, table);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index fe6da60..f820c28 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -47,6 +47,7 @@ import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
 import java.sql.SQLException;
@@ -80,7 +81,7 @@ class JdbcTable extends AbstractQueryableTable
     this.jdbcCatalogName = jdbcCatalogName;
     this.jdbcSchemaName = jdbcSchemaName;
     this.jdbcTableName = tableName;
-    this.jdbcTableType = jdbcTableType;
+    this.jdbcTableType = Preconditions.checkNotNull(jdbcTableType);
   }
 
   public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/schema/Schema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schema.java b/core/src/main/java/org/apache/calcite/schema/Schema.java
index 065ec5d..6745e21 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schema.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schema.java
@@ -144,31 +144,30 @@ public interface Schema {
 
   /** Table type. */
   enum TableType {
-    /** A regular table. */
+    /** A regular table.
+     *
+     * <p>Used by PostgreSQL, MySQL and others. */
     TABLE,
 
     /** A relation whose contents are calculated by evaluating a SQL
-     * expression. */
+     * expression.
+     *
+     * <p>Used by PostgreSQL and others. */
     VIEW,
 
-    /** A table maintained by the system. Data dictionary tables, such as the
-     * "TABLES" and "COLUMNS" table in the "metamodel" schema, examples of
-     * system tables. */
-    SYSTEM_TABLE,
-
-    /** A table that is only visible to one connection. */
-    LOCAL_TEMPORARY,
+    /** Foreign table.
+     *
+     * <p>Used by PostgreSQL. */
+    FOREIGN_TABLE,
 
-    /** A structure, similar to a view, that is the basis for auto-generated
-     * materializations. It is either a single table or a collection of tables
-     * that are joined via many-to-one relationships from a central hub table.
-     * It is not available for queries, but is just used as an intermediate
-     * structure during query planning. */
-    STAR,
+    /** Materialized view.
+     *
+     * <p>Used by PostgreSQL. */
+    MATERIALIZED_VIEW,
 
     /** Index table.
      *
-     * <p>Used by Apache Phoenix. */
+     * <p>Used by Apache Phoenix, PostgreSQL. */
     INDEX,
 
     /** Join table.
@@ -178,12 +177,82 @@ public interface Schema {
 
     /** Sequence table.
      *
-     * <p>Used by Apache Phoenix, and others. Must have a single BIGINT column
-     * called "$seq". */
+     * <p>Used by Apache Phoenix, PostgreSQL and others.
+     * In Phoenix, must have a single BIGINT column called "$seq". */
     SEQUENCE,
 
+    /** A structure, similar to a view, that is the basis for auto-generated
+     * materializations. It is either a single table or a collection of tables
+     * that are joined via many-to-one relationships from a central hub table.
+     * It is not available for queries, but is just used as an intermediate
+     * structure during query planning. */
+    STAR,
+
     /** Stream. */
     STREAM,
+
+    /** Type.
+     *
+     * <p>Used by PostgreSQL. */
+    TYPE,
+
+    /** A table maintained by the system. Data dictionary tables, such as the
+     * "TABLES" and "COLUMNS" table in the "metamodel" schema, examples of
+     * system tables.
+     *
+     * <p>Used by PostgreSQL, MySQL and others. */
+    SYSTEM_TABLE,
+
+    /** System view.
+     *
+     * <p>Used by PostgreSQL, MySQL. */
+    SYSTEM_VIEW,
+
+    /** System index.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_INDEX,
+
+    /** System TOAST index.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_TOAST_INDEX,
+
+    /** System TOAST table.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_TOAST_TABLE,
+
+    /** Temporary index.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_INDEX,
+
+    /** Temporary sequence.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_SEQUENCE,
+
+    /** Temporary table.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_TABLE,
+
+    /** Temporary view.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_VIEW,
+
+    /** A table that is only visible to one connection.
+     *
+     * <p>Used by PostgreSQL, MySQL. */
+    LOCAL_TEMPORARY,
+
+    /** Table type not known to Calcite.
+     *
+     * <p>If you get one of these, please fix the problem by adding an enum
+     * value. */
+    OTHER,
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index 040775f..dbaf0a8 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -1859,11 +1859,29 @@ public class Util {
    * @param <T>   Enum class type
    * @return Enum constant or null
    */
-  @SuppressWarnings({"unchecked" })
   public static synchronized <T extends Enum<T>> T enumVal(
       Class<T> clazz,
       String name) {
-    return (T) ENUM_CONSTANTS.getUnchecked(clazz).get(name);
+    return clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name));
+  }
+
+  /**
+   * Returns the value of an enumeration with a particular or default value if
+   * not found.
+   *
+   * @param default_ Default value (not null)
+   * @param name     Name of enum constant
+   * @param <T>      Enum class type
+   * @return         Enum constant, never null
+   */
+  public static synchronized <T extends Enum<T>> T enumVal(T default_,
+      String name) {
+    final Class<T> clazz = default_.getDeclaringClass();
+    final T t = clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name));
+    if (t == null) {
+      return default_;
+    }
+    return t;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index ea69cae..cc7ec8c 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -16,17 +16,25 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.jdbc.CalciteConnection;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+
 import org.hsqldb.jdbcDriver;
+
 import org.junit.Test;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 
 /**
@@ -350,6 +358,33 @@ public class JdbcAdapterTest {
         .explainContains("SINGLE_VALUE")
         .throws_(expected);
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-865">[CALCITE-865]
+   * Unknown table type causes NullPointerException in JdbcSchema</a>. The issue
+   * occurred because of the "SYSTEM_INDEX" table type when run against
+   * PostgreSQL. */
+  @Test public void testMetadataTables() throws Exception {
+    // The troublesome tables occur in PostgreSQL's system schema.
+    final String model =
+        JdbcTest.FOODMART_MODEL.replace("jdbcSchema: 'foodmart'",
+            "jdbcSchema: null");
+    CalciteAssert.model(
+        model)
+        .doWithConnection(
+            new Function<CalciteConnection, Void>() {
+              public Void apply(CalciteConnection connection) {
+                try {
+                  final ResultSet resultSet =
+                      connection.getMetaData().getTables(null, null, "%", null);
+                  assertFalse(CalciteAssert.toString(resultSet).isEmpty());
+                  return null;
+                } catch (SQLException e) {
+                  throw Throwables.propagate(e);
+                }
+              }
+            });
+  }
 }
 
 // End JdbcAdapterTest.java