You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by rm...@apache.org on 2009/08/23 03:45:24 UTC

svn commit: r806917 - in /hadoop/hive/branches/branch-0.4: ./ jdbc/src/java/org/apache/hadoop/hive/jdbc/ jdbc/src/test/org/apache/hadoop/hive/jdbc/

Author: rmurthy
Date: Sun Aug 23 01:45:24 2009
New Revision: 806917

URL: http://svn.apache.org/viewvc?rev=806917&view=rev
Log:
HIVE-679. Adding the basic JDBC methods to allow querying using the
SQuirrelSQL tool. (Bill Graham via rmurthy)


Modified:
    hadoop/hive/branches/branch-0.4/CHANGES.txt
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveConnection.java
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDatabaseMetaData.java
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDriver.java
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSet.java
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSetMetaData.java
    hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveStatement.java
    hadoop/hive/branches/branch-0.4/jdbc/src/test/org/apache/hadoop/hive/jdbc/TestJdbcDriver.java

Modified: hadoop/hive/branches/branch-0.4/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/CHANGES.txt?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/CHANGES.txt (original)
+++ hadoop/hive/branches/branch-0.4/CHANGES.txt Sun Aug 23 01:45:24 2009
@@ -220,6 +220,9 @@
     HIVE-760. Add version info to META-INF/MANIFEST.MF 
     (Bill Graham via rmurthy)
 
+    HIVE-679. Adding the basic JDBC methods to allow querying using the
+    SQuirrelSQL tool. (Bill Graham via rmurthy)
+
   OPTIMIZATIONS
 
     HIVE-279. Predicate Pushdown support (Prasad Chakka via athusoo).

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveConnection.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveConnection.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveConnection.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveConnection.java Sun Aug 23 01:45:24 2009
@@ -49,7 +49,10 @@
 public class HiveConnection implements java.sql.Connection {
   JdbcSessionState session;
 
+  private TTransport transport;
   private HiveInterface client;
+  boolean isClosed = true;
+  SQLWarning warningChain = null;
 
   private static final String URI_PREFIX = "jdbc:hive://";
   /**
@@ -86,11 +89,12 @@
       }
       catch (Exception e) {
       }
-      TTransport transport = new TSocket(host, port);
+      transport = new TSocket(host, port);
       TProtocol protocol = new TBinaryProtocol(transport);
       client = new HiveClient(protocol);
       transport.open();
     }
+    isClosed = false;
   }
 
   /* (non-Javadoc)
@@ -98,8 +102,7 @@
    */
 
   public void clearWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    this.warningChain = null;
   }
 
   /* (non-Javadoc)
@@ -107,8 +110,12 @@
    */
 
   public void close() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    try {
+      if (transport != null) transport.close();
+    }
+    finally {
+      isClosed = true;
+    }
   }
 
   /* (non-Javadoc)
@@ -173,6 +180,7 @@
    */
 
   public Statement createStatement() throws SQLException {
+    if (isClosed) throw new SQLException("Can't create Statement, connection is closed");
     return new HiveStatement(session, client);
   }
 
@@ -283,8 +291,7 @@
    */
 
   public SQLWarning getWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.warningChain;
   }
 
   /* (non-Javadoc)
@@ -292,8 +299,7 @@
    */
 
   public boolean isClosed() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return isClosed;
   }
 
   /* (non-Javadoc)

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDatabaseMetaData.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDatabaseMetaData.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDatabaseMetaData.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDatabaseMetaData.java Sun Aug 23 01:45:24 2009
@@ -22,6 +22,10 @@
 import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
+import java.net.URL;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.io.IOException;
 
 public class HiveDatabaseMetaData implements java.sql.DatabaseMetaData {
 
@@ -216,8 +220,7 @@
    */
 
   public String getDatabaseProductName() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return "Hive";
   }
 
   /* (non-Javadoc)
@@ -225,8 +228,7 @@
    */
 
   public String getDatabaseProductVersion() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return "0";
   }
 
   /* (non-Javadoc)
@@ -261,7 +263,7 @@
    */
 
   public String getDriverName() throws SQLException {
-    return new String("hive");
+    return fetchManifestAttribute(Attributes.Name.IMPLEMENTATION_TITLE);
   }
 
   /* (non-Javadoc)
@@ -269,7 +271,7 @@
    */
 
   public String getDriverVersion() throws SQLException {
-    return new String("0");
+   return fetchManifestAttribute(Attributes.Name.IMPLEMENTATION_VERSION);
   }
 
   /* (non-Javadoc)
@@ -581,8 +583,8 @@
 
   public ResultSet getProcedures(String catalog, String schemaPattern,
       String procedureNamePattern) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    //TODO: return empty result set here
+    return null;
   }
 
   /* (non-Javadoc)
@@ -1065,8 +1067,7 @@
    */
 
   public boolean supportsCatalogsInTableDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return false;
   }
 
   /* (non-Javadoc)
@@ -1275,8 +1276,7 @@
    */
 
   public boolean supportsMultipleResultSets() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return false;
   }
 
   /* (non-Javadoc)
@@ -1419,8 +1419,7 @@
    */
 
   public boolean supportsSchemasInDataManipulation() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return false;
   }
 
   /* (non-Javadoc)
@@ -1455,8 +1454,7 @@
    */
 
   public boolean supportsSchemasInTableDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return false;
   }
 
   /* (non-Javadoc)
@@ -1491,8 +1489,7 @@
    */
 
   public boolean supportsStoredProcedures() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return false;
   }
 
   /* (non-Javadoc)
@@ -1622,4 +1619,44 @@
     throw new SQLException("Method not supported");
   }
 
+  /**
+   * Lazy-load manifest attributes as needed.
+   */
+  private static Attributes manifestAttributes = null;
+
+  /**
+   * Loads the manifest attributes from the jar.
+   * @throws java.net.MalformedURLException
+   * @throws IOException
+   */
+  private synchronized void loadManifestAttributes() throws IOException {
+    if(manifestAttributes != null) return;
+    Class clazz = this.getClass();
+    String classContainer = clazz.getProtectionDomain().getCodeSource().getLocation().toString();
+    URL manifestUrl = new URL("jar:" + classContainer + "!/META-INF/MANIFEST.MF");
+    Manifest manifest = new Manifest(manifestUrl.openStream());
+    manifestAttributes = manifest.getMainAttributes();
+  }
+
+  /**
+   * Helper to initialize attributes and return one.
+   *
+   * @param attributeName
+   * @return
+   * @throws SQLException
+   */
+  private String fetchManifestAttribute(Attributes.Name attributeName) throws SQLException {
+    try {
+      loadManifestAttributes();
+    } catch (IOException e) {
+      throw new SQLException("Couldn't load manifest attributes.", e);
+    }
+    return manifestAttributes.getValue(attributeName);
+  }
+ 
+  public static void main(String[] args) throws SQLException {
+    HiveDatabaseMetaData meta = new HiveDatabaseMetaData();
+    System.out.println("DriverName: " + meta.getDriverName());
+    System.out.println("DriverVersion: " + meta.getDriverVersion());
+  }
 }

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDriver.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDriver.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDriver.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveDriver.java Sun Aug 23 01:45:24 2009
@@ -50,6 +50,31 @@
   private static final boolean JDBC_COMPLIANT = false;
 
   /**
+   * The required prefix for the connection url
+   */
+  private static final String URL_PREFIX = "jdbc:hive://";
+
+  /**
+   * If host is provided, without a port
+   */
+  private static final String DEFAULT_PORT = "10000";
+
+  /**
+   * Property key for the database name
+   */
+  private static final String DBNAME_PROPERTY_KEY = "DBNAME";
+
+  /**
+   * Property key for the Hive Server host
+   */
+  private static final String HOST_PROPERTY_KEY = "HOST";
+
+  /**
+   * Property key for the Hive Server port
+   */
+  private static final String PORT_PROPERTY_KEY = "PORT";
+
+  /**
    *
    */
   public HiveDriver() {
@@ -75,7 +100,7 @@
    */
 
   public boolean acceptsURL(String url) throws SQLException {
-    return Pattern.matches("jdbc:hive://", url);
+    return Pattern.matches(URL_PREFIX, url);
   }
 
 
@@ -103,11 +128,38 @@
     return MINOR_VERSION;
   }
 
-
   public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
       throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    if (info == null) {
+      info = new Properties();
+    }
+
+    if ((url != null) && url.startsWith(URL_PREFIX)) {
+      info = parseURL(url, info);
+    }
+
+    DriverPropertyInfo hostProp = new DriverPropertyInfo(HOST_PROPERTY_KEY,
+                                        info.getProperty(HOST_PROPERTY_KEY, ""));
+    hostProp.required = false;
+    hostProp.description = "Hostname of Hive Server";
+
+    DriverPropertyInfo portProp = new DriverPropertyInfo(PORT_PROPERTY_KEY,
+                                        info.getProperty(PORT_PROPERTY_KEY, ""));
+    portProp.required = false;
+    portProp.description = "Port number of Hive Server";
+
+    DriverPropertyInfo dbProp = new DriverPropertyInfo(DBNAME_PROPERTY_KEY,
+                                      info.getProperty(DBNAME_PROPERTY_KEY, "default"));
+    dbProp.required = false;
+    dbProp.description = "Database name";
+
+    DriverPropertyInfo[] dpi = new DriverPropertyInfo[3];
+
+    dpi[0] = hostProp;
+    dpi[1] = portProp;
+    dpi[2] = dbProp;
+
+    return dpi;
   }
 
   /**
@@ -118,4 +170,49 @@
     return JDBC_COMPLIANT;
   }
 
+  /**
+   * Takes a url in the form of jdbc:hive://[hostname]:[port]/[db_name] and parses it.
+   * Everything after jdbc:hive// is optional.
+   *
+   * @param url
+   * @param defaults
+   * @return
+   * @throws java.sql.SQLException
+   */
+  private Properties parseURL(String url, Properties defaults)
+      throws java.sql.SQLException {
+    Properties urlProps = (defaults != null) ? new Properties(defaults)
+        : new Properties();
+
+    if (url == null || !url.startsWith(URL_PREFIX)) {
+      throw new SQLException("Invalid connection url: " + url);
+    }
+
+    if (url.length() <= URL_PREFIX.length()) return urlProps;
+
+    // [hostname]:[port]/[db_name]
+    String connectionInfo = url.substring(URL_PREFIX.length());
+
+    // [hostname]:[port] [db_name]
+    String[] hostPortAndDatabase = connectionInfo.split("/", 2);
+
+    // [hostname]:[port]
+    if (hostPortAndDatabase[0].length() > 0) {
+      String[] hostAndPort = hostPortAndDatabase[0].split(":", 2);
+      urlProps.put(HOST_PROPERTY_KEY, hostAndPort[0]);
+      if (hostAndPort.length > 1) {
+        urlProps.put(PORT_PROPERTY_KEY, hostAndPort[1]);
+      }
+      else {
+        urlProps.put(PORT_PROPERTY_KEY, DEFAULT_PORT);
+      }
+    }
+
+    // [db_name]
+    if (hostPortAndDatabase.length > 1) {
+      urlProps.put(DBNAME_PROPERTY_KEY, hostPortAndDatabase[1]);
+    }
+
+    return urlProps;
+  }
 }

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSet.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSet.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSet.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSet.java Sun Aug 23 01:45:24 2009
@@ -58,20 +58,31 @@
   List<String> columnNames;
   List<String> columnTypes;
 
+  SQLWarning warningChain = null;
+  boolean wasNull = false;
+  int maxRows = 0;
+  int rowsFetched = 0;
+
   /**
    *
    */
   @SuppressWarnings("unchecked")
-  public HiveResultSet(HiveInterface client) {
+  public HiveResultSet(HiveInterface client, int maxRows) throws SQLException {
     this.client = client;
     this.row = new ArrayList();
+    this.maxRows = maxRows;
     initDynamicSerde();
   }
 
+  @SuppressWarnings("unchecked")
+  public HiveResultSet(HiveInterface client) throws SQLException {
+    this(client, 0);
+  }
+
   /**
    * Instantiate the dynamic serde used to deserialize the result row
    */
-  public void initDynamicSerde() {
+  public void initDynamicSerde() throws SQLException {
     try {
       Schema fullSchema = client.getThriftSchema();
       List<FieldSchema> schema = fullSchema.getFieldSchemas();
@@ -79,12 +90,14 @@
       columnTypes = new ArrayList<String>();
       
       String serDDL;
-      
+
       if ((schema != null) && (!schema.isEmpty())) {
         serDDL = new String("struct result { ");
         for (int pos = 0; pos < schema.size(); pos++) {
           if (pos != 0)
             serDDL = serDDL.concat(",");
+          columnTypes.add(schema.get(pos).getType());
+          columnNames.add(schema.get(pos).getName());
           serDDL = serDDL.concat(schema.get(pos).getType());
           serDDL = serDDL.concat(" ");
           serDDL = serDDL.concat(schema.get(pos).getName());
@@ -104,8 +117,7 @@
       ds.initialize(new Configuration(), dsp);
     } catch (Exception ex) {
       ex.printStackTrace();
-      System.exit(1);
-      // TODO: Decide what to do here.
+      throw new SQLException("Could not create ResultSet: " + ex.getMessage());
     }
   }
 
@@ -150,8 +162,7 @@
    */
 
   public void clearWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    warningChain = null;
   }
 
   /* (non-Javadoc)
@@ -305,7 +316,7 @@
    */
 
   public boolean getBoolean(int columnIndex) throws SQLException {
-    Object obj = row.get(columnIndex-1);
+    Object obj = getObject(columnIndex);
     if (Number.class.isInstance(obj)) {
       return ((Number)obj).intValue() != 0;
     }
@@ -326,7 +337,7 @@
    */
 
   public byte getByte(int columnIndex) throws SQLException {
-    Object obj = row.get(columnIndex-1);
+    Object obj = getObject(columnIndex);
     if (Number.class.isInstance(obj)) {
       return ((Number)obj).byteValue();
     }
@@ -419,8 +430,11 @@
    */
 
   public Date getDate(int columnIndex) throws SQLException {
+    Object obj = getObject(columnIndex);
+    if (obj == null) return null;
+
     try {
-      return Date.valueOf((String)row.get(columnIndex-1));
+      return Date.valueOf((String)obj);
     }
     catch (Exception e) {
     throw new SQLException("Cannot convert column " + columnIndex + " to date: " + e.toString());
@@ -460,7 +474,7 @@
 
   public double getDouble(int columnIndex) throws SQLException {
     try {
-      Object obj = row.get(columnIndex-1);
+      Object obj = getObject(columnIndex);
       if (Number.class.isInstance(obj)) {
         return ((Number)obj).doubleValue();
       }
@@ -504,7 +518,7 @@
 
   public float getFloat(int columnIndex) throws SQLException {
     try {
-      Object obj = row.get(columnIndex-1);
+      Object obj = getObject(columnIndex);
       if (Number.class.isInstance(obj)) {
         return ((Number)obj).floatValue();
       }
@@ -538,7 +552,7 @@
 
   public int getInt(int columnIndex) throws SQLException {
     try {
-      Object obj = row.get(columnIndex-1);
+      Object obj = getObject(columnIndex);
       if (Number.class.isInstance(obj)) {
         return ((Number)obj).intValue();
       }
@@ -564,7 +578,7 @@
 
   public long getLong(int columnIndex) throws SQLException {
     try {
-      Object obj = row.get(columnIndex-1);
+      Object obj = getObject(columnIndex);
       if (Number.class.isInstance(obj)) {
         return ((Number)obj).longValue();
       }
@@ -651,7 +665,18 @@
    */
 
   public Object getObject(int columnIndex) throws SQLException {
+    if (row == null) {
+      throw new SQLException("No row found.");
+    }
+
+    if (columnIndex > row.size()) {
+      throw new SQLException("Invalid columnIndex: " + columnIndex);
+    }
+
     try {
+      this.wasNull = false;
+      if (row.get(columnIndex-1) == null) this.wasNull = true;
+
       return row.get(columnIndex-1);
     }
     catch (Exception e) {
@@ -757,7 +782,7 @@
 
   public short getShort(int columnIndex) throws SQLException {
     try {
-      Object obj = row.get(columnIndex-1);
+      Object obj = getObject(columnIndex);
       if (Number.class.isInstance(obj)) {
         return ((Number)obj).shortValue();
       }
@@ -793,7 +818,10 @@
 
   public String getString(int columnIndex) throws SQLException {
     // Column index starts from 1, not 0.
-    return row.get(columnIndex - 1).toString();
+    Object obj = getObject(columnIndex);
+    if (obj == null) return null;
+
+    return obj.toString();
   }
 
   /* (non-Javadoc)
@@ -929,8 +957,7 @@
    */
 
   public SQLWarning getWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return warningChain;
   }
 
   /* (non-Javadoc)
@@ -1022,9 +1049,12 @@
    */
 
   public boolean next() throws SQLException {
+    if (this.maxRows > 0 && this.rowsFetched >= this.maxRows) return false;
+
     String row_str = "";
     try {
       row_str = (String)client.fetchOne();
+      this.rowsFetched++;
       if (!row_str.equals("")) {
         Object o = ds.deserialize(new BytesWritable(row_str.getBytes()));
         row = (ArrayList<?>)o;
@@ -1903,8 +1933,7 @@
    */
 
   public boolean wasNull() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.wasNull;
   }
 
   /* (non-Javadoc)

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSetMetaData.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSetMetaData.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSetMetaData.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveResultSetMetaData.java Sun Aug 23 01:45:24 2009
@@ -18,13 +18,17 @@
 
 package org.apache.hadoop.hive.jdbc;
 
+import org.apache.hadoop.hive.serde.Constants;
+
 import java.sql.SQLException;
+import java.sql.ResultSetMetaData;
+import java.sql.Types;
 import java.util.List;
 
 public class HiveResultSetMetaData implements java.sql.ResultSetMetaData {
   List<String> columnNames;
   List<String> columnTypes;
-  
+
   public HiveResultSetMetaData(List<String> columnNames, List<String> columnTypes) {
     this.columnNames = columnNames;
     this.columnTypes = columnTypes;
@@ -61,8 +65,22 @@
    */
 
   public int getColumnDisplaySize(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+
+    // taking a stab at appropriate values
+    switch(getColumnType(column)) {
+      case Types.VARCHAR:
+      case Types.BIGINT:
+        return 32;
+      case Types.TINYINT:
+        return 2;
+      case Types.BOOLEAN:
+        return 8;
+      case Types.DOUBLE:
+      case Types.INTEGER:
+        return 16;
+      default:
+        return 32;
+    }
   }
 
   /* (non-Javadoc)
@@ -87,8 +105,31 @@
    */
 
   public int getColumnType(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    if (columnTypes == null)
+      throw new SQLException("Could not determine column type name for ResultSet");
+
+    if (column < 1 || column > columnTypes.size())
+      throw new SQLException("Invalid column value: " + column);
+
+    // we need to convert the thrift type to the SQL type
+    String type = columnTypes.get(column-1);
+
+    // we need to convert the thrift type to the SQL type
+    //TODO: this would be better handled in an enum
+    if ("string".equals(type))
+      return Types.VARCHAR;
+    else if ("bool".equals(type))
+      return Types.BOOLEAN;
+    else if ("double".equals(type))
+      return Types.DOUBLE;
+    else if ("byte".equals(type))
+      return Types.TINYINT;
+    else if ("i32".equals(type))
+      return Types.INTEGER;
+    else if ("i64".equals(type))
+      return Types.BIGINT;
+
+    throw new SQLException("Inrecognized column type: " + type);
   }
 
   /* (non-Javadoc)
@@ -96,7 +137,30 @@
    */
 
   public String getColumnTypeName(int column) throws SQLException {
-    return columnTypes.get(column-1);
+    if (columnTypes == null)
+      throw new SQLException("Could not determine column type name for ResultSet");
+
+    if (column < 1 || column > columnTypes.size())
+      throw new SQLException("Invalid column value: " + column);
+
+    // we need to convert the thrift type to the SQL type name
+    //TODO: this would be better handled in an enum
+    String type = columnTypes.get(column-1);
+    if ("string".equals(type))
+      return Constants.STRING_TYPE_NAME;
+    else if ("double".equals(type))
+      return Constants.DOUBLE_TYPE_NAME;
+    
+    else if ("bool".equals(type))
+      return Constants.BOOLEAN_TYPE_NAME;
+    else if ("byte".equals(type))
+      return Constants.TINYINT_TYPE_NAME;
+    else if ("i32".equals(type))
+      return Constants.INT_TYPE_NAME;
+    else if ("i64".equals(type))
+      return Constants.BIGINT_TYPE_NAME;
+
+    throw new SQLException("Inrecognized column type: " + type);
   }
 
   /* (non-Javadoc)
@@ -104,8 +168,9 @@
    */
 
   public int getPrecision(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    if (Types.DOUBLE == getColumnType(column)) return -1; //Do we have a precision limit?
+
+    return 0;
   }
 
   /* (non-Javadoc)
@@ -113,8 +178,9 @@
    */
 
   public int getScale(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    if (Types.DOUBLE == getColumnType(column)) return -1; //Do we have a scale limit?
+
+    return 0;
   }
 
   /* (non-Javadoc)
@@ -140,8 +206,8 @@
    */
 
   public boolean isAutoIncrement(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    // Hive doesn't have an auto-increment concept
+    return false;
   }
 
   /* (non-Javadoc)
@@ -158,8 +224,8 @@
    */
 
   public boolean isCurrency(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    // Hive doesn't support a currency type
+    return false;
   }
 
   /* (non-Javadoc)
@@ -176,8 +242,8 @@
    */
 
   public int isNullable(int column) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    // Hive doesn't have the concept of not-null
+    return ResultSetMetaData.columnNullable;
   }
 
   /* (non-Javadoc)

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveStatement.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveStatement.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveStatement.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveStatement.java Sun Aug 23 01:45:24 2009
@@ -29,6 +29,30 @@
   JdbcSessionState session;
   HiveInterface client;
   /**
+   * We need to keep a reference to the result set to support the following:
+   * <code>
+   * statement.execute(String sql);
+   * statement.getResultSet();
+   * </code>
+   */
+  ResultSet resultSet = null;
+
+  /**
+   * The maximum number of rows this statement should return (0 => all rows)
+   */
+  int maxRows = 0;
+
+  /**
+   * Add SQLWarnings to the warningChain if needed
+   */
+  SQLWarning warningChain = null;
+
+  /**
+   * Keep state so we can fail certain calls made after close();
+   */
+  boolean isClosed = false;
+
+  /**
    *
    */
   public HiveStatement(JdbcSessionState session, HiveInterface client) {
@@ -68,8 +92,7 @@
    */
 
   public void clearWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    this.warningChain = null;
   }
 
   /* (non-Javadoc)
@@ -77,8 +100,10 @@
    */
 
   public void close() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    //TODO: how to properly shut down the client?
+    client = null;
+    resultSet = null;
+    isClosed = true;
   }
 
   /* (non-Javadoc)
@@ -86,7 +111,11 @@
    */
 
   public boolean execute(String sql) throws SQLException {
-    return true;
+    ResultSet rs = executeQuery(sql);
+
+    //TODO: this should really check if there are results, but there's no easy
+    //way to do that without calling rs.next();
+    return rs != null;
   }
 
   /* (non-Javadoc)
@@ -132,12 +161,17 @@
    */
 
   public ResultSet executeQuery(String sql) throws SQLException {
+    if (this.isClosed)
+      throw new SQLException("Can't execute after statement has been closed");
+
     try {
+      this.resultSet = null;
       client.execute(sql);
     } catch (Exception ex) {
       throw new SQLException(ex.toString());
     }
-    return new HiveResultSet(client);
+    this.resultSet = new HiveResultSet(client, maxRows);
+    return this.resultSet;
   }
 
   /* (non-Javadoc)
@@ -233,8 +267,7 @@
    */
 
   public int getMaxRows() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.maxRows;
   }
 
   /* (non-Javadoc)
@@ -269,8 +302,7 @@
    */
 
   public ResultSet getResultSet() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.resultSet;
   }
 
   /* (non-Javadoc)
@@ -305,8 +337,7 @@
    */
 
   public int getUpdateCount() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return 0;
   }
 
   /* (non-Javadoc)
@@ -314,8 +345,7 @@
    */
 
   public SQLWarning getWarnings() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.warningChain;
   }
 
   /* (non-Javadoc)
@@ -323,8 +353,7 @@
    */
 
   public boolean isClosed() throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    return this.isClosed;
   }
 
   /* (non-Javadoc)
@@ -386,8 +415,8 @@
    */
 
   public void setMaxRows(int max) throws SQLException {
-    // TODO Auto-generated method stub
-    throw new SQLException("Method not supported");
+    if (max < 0) throw new SQLException("max must be >= 0");
+    this.maxRows = max;
   }
 
   /* (non-Javadoc)

Modified: hadoop/hive/branches/branch-0.4/jdbc/src/test/org/apache/hadoop/hive/jdbc/TestJdbcDriver.java
URL: http://svn.apache.org/viewvc/hadoop/hive/branches/branch-0.4/jdbc/src/test/org/apache/hadoop/hive/jdbc/TestJdbcDriver.java?rev=806917&r1=806916&r2=806917&view=diff
==============================================================================
--- hadoop/hive/branches/branch-0.4/jdbc/src/test/org/apache/hadoop/hive/jdbc/TestJdbcDriver.java (original)
+++ hadoop/hive/branches/branch-0.4/jdbc/src/test/org/apache/hadoop/hive/jdbc/TestJdbcDriver.java Sun Aug 23 01:45:24 2009
@@ -20,18 +20,15 @@
 
 import java.sql.SQLException;
 import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.Statement;
-import java.sql.Driver;
 import java.sql.DriverManager;
-import java.util.Properties;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverPropertyInfo;
+import java.sql.ResultSetMetaData;
+import java.sql.Types;
 import junit.framework.TestCase;
-import javax.naming.*;
-import javax.naming.directory.*;
-import javax.sql.DataSource;
 import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.hive.conf.HiveConf;
 
 public class TestJdbcDriver extends TestCase {
@@ -62,6 +59,7 @@
       con = DriverManager.getConnection("jdbc:hive://", "", "");
     }
     assertNotNull("Connection is null", con);
+    assertFalse("Connection should not be closed", con.isClosed());
     Statement stmt = con.createStatement();
     assertNotNull("Statement is null", stmt);
 
@@ -110,33 +108,53 @@
     res = stmt.executeQuery("drop table " + partitionedTableName);
     assertFalse(res.next());
 
+    con.close();
+    assertTrue("Connection should be closed", con.isClosed());
+
+    Exception expectedException = null;
+    try {
+      con.createStatement();
+    }
+    catch(Exception e) {
+      expectedException = e;
+    }
+    
+    assertNotNull("createStatement() on closed connection should throw exception",
+                  expectedException);
   }
 
   public final void testSelectAll() throws Exception {
+    doTestSelectAll(this.tableName, -1); // tests not setting maxRows  (return all)
+    doTestSelectAll(this.tableName, 0);  // tests setting maxRows to 0 (return all)
+  }
+
+  public final void testSelectAllPartioned() throws Exception {
+    doTestSelectAll(this.partitionedTableName, -1); // tests not setting maxRows  (return all)
+    doTestSelectAll(this.partitionedTableName, 0);  // tests setting maxRows to 0 (return all)
+  }
+
+  public final void testSelectAllMaxRows() throws Exception {
+    doTestSelectAll(this.tableName, 100);
+  }
+
+  private final void doTestSelectAll(String tableName, int maxRows) throws Exception {
     Statement stmt = con.createStatement();
-    assertNotNull("Statement is null", stmt);
+    if (maxRows >= 0) stmt.setMaxRows(maxRows);
 
-    ResultSet res;
+    //JDBC says that 0 means return all, which is the default
+    int expectedMaxRows = maxRows < 1 ? 0 : maxRows;
 
-    // TODO: There is no schema for show tables or describe table.
-    /*
-    stmt.executeQuery("drop table michi1");
-    stmt.executeQuery("drop table michi2");
-    stmt.executeQuery("drop table michi3");
-    stmt.executeQuery("create table michi1 (num int)");
-    stmt.executeQuery("create table michi2 (num int)");
-    stmt.executeQuery("create table michi3 (num int)");
+    assertNotNull("Statement is null", stmt);
+    assertEquals("Statement max rows not as expected", expectedMaxRows, stmt.getMaxRows());
+    assertFalse("Statement should not be closed", stmt.isClosed());
 
-    res = stmt.executeQuery("show tables");
-    res = stmt.executeQuery("describe michi1");
-    while (res.next()) {
-      System.out.println(res.getString(0));
-    }
-    */
+    ResultSet res;
 
     // run some queries
     res = stmt.executeQuery("select * from " + tableName);
     assertNotNull("ResultSet is null", res);
+    assertTrue("getResultSet() not returning expected ResultSet", res == stmt.getResultSet());
+    assertEquals("get update count not as expected", 0, stmt.getUpdateCount());
     int i = 0;
 
     boolean moreRow = res.next();
@@ -146,6 +164,10 @@
         res.getInt(1);
         res.getString(1);
         res.getString(2);
+        assertFalse("Last result value was not null", res.wasNull());
+        assertNull("No warnings should be found on ResultSet", res.getWarnings());
+        res.clearWarnings(); //verifying that method is supported
+        
         //System.out.println(res.getString(1) + " " + res.getString(2));
         assertEquals("getInt and getString don't align for the same result value",
                 String.valueOf(res.getInt(1)), res.getString(1));
@@ -159,47 +181,22 @@
         throw new Exception(e.toString());
       }
     }
-    // supposed to get 500 rows
-    assertEquals(500, i);
+
+    // supposed to get 500 rows if maxRows isn't set
+    int expectedRowCount = maxRows > 0 ? maxRows : 500;
+    assertEquals("Incorrect number of rows returned", expectedRowCount, i);
 
     // should have no more rows
     assertEquals(false, moreRow);
-  }
 
-  public final void testSelectAllPartitioned() throws Exception {
-    Statement stmt = con.createStatement();
-    assertNotNull("Statement is null", stmt);
+    assertNull("No warnings should be found on statement", stmt.getWarnings());
+    stmt.clearWarnings(); //verifying that method is supported
 
-    // run some queries
-    ResultSet res = stmt.executeQuery("select * from " + partitionedTableName);
-    assertNotNull("ResultSet is null", res);
-    int i = 0;
-
-    boolean moreRow = res.next();
-    while (moreRow) {
-      try {
-        i++;
-        res.getInt(1);
-        res.getString(1);
-        res.getString(2);
-        //System.out.println(res.getString(1) + " " + res.getString(2));
-        assertEquals("getInt and getString don't align for the same result value",
-                String.valueOf(res.getInt(1)), res.getString(1));
-        assertEquals("Unexpected result found",
-                "val_" + res.getString(1), res.getString(2));
-        moreRow = res.next();
-      }
-      catch (SQLException e) {
-        System.out.println(e.toString());
-        e.printStackTrace();
-        throw new Exception(e.toString());
-      }
-    }
-    // supposed to get 500 rows
-    assertEquals(500, i);
+    assertNull("No warnings should be found on connection", con.getWarnings());
+    con.clearWarnings(); //verifying that method is supported
 
-    // should have no more rows
-    assertEquals(false, moreRow);
+    stmt.close();
+    assertTrue("Statement should be closed", stmt.isClosed());
   }
 
   public void testShowTables() throws SQLException {
@@ -237,4 +234,80 @@
 
   }
 
+  public void testDatabaseMetaData() throws SQLException {
+    DatabaseMetaData meta = con.getMetaData();
+
+    assertEquals("Hive", meta.getDatabaseProductName());
+    assertEquals("0", meta.getDatabaseProductVersion());
+    assertNull(meta.getProcedures(null, null, null));
+    assertFalse(meta.supportsCatalogsInTableDefinitions());
+    assertFalse(meta.supportsSchemasInTableDefinitions());
+    assertFalse(meta.supportsSchemasInDataManipulation());
+    assertFalse(meta.supportsMultipleResultSets());
+    assertFalse(meta.supportsStoredProcedures());
+  }
+
+  public void testResultSetMetaData() throws SQLException {
+    Statement stmt = con.createStatement();
+    ResultSet res = stmt.executeQuery("drop table " + tableName);
+
+    //creating a table with tinyint is failing currently so not including
+    res = stmt.executeQuery("create table " + tableName + " (a string, b boolean, c bigint, d int, f double)");
+    res = stmt.executeQuery("select * from " + tableName + " limit 1");
+
+    ResultSetMetaData meta = res.getMetaData();
+    assertEquals("Unexpected column type", Types.VARCHAR, meta.getColumnType(1));
+    assertEquals("Unexpected column type", Types.BOOLEAN, meta.getColumnType(2));
+    assertEquals("Unexpected column type", Types.BIGINT,  meta.getColumnType(3));
+    assertEquals("Unexpected column type", Types.INTEGER, meta.getColumnType(4));
+    assertEquals("Unexpected column type", Types.DOUBLE,  meta.getColumnType(5));
+    assertEquals("Unexpected column type name", "string", meta.getColumnTypeName(1));
+    assertEquals("Unexpected column type name", "boolean",   meta.getColumnTypeName(2));
+    assertEquals("Unexpected column type name", "bigint",    meta.getColumnTypeName(3));
+    assertEquals("Unexpected column type name", "int",    meta.getColumnTypeName(4));
+    assertEquals("Unexpected column type name", "double", meta.getColumnTypeName(5));
+    assertEquals("Unexpected column display size", 32, meta.getColumnDisplaySize(1));
+    assertEquals("Unexpected column display size", 8,  meta.getColumnDisplaySize(2));
+    assertEquals("Unexpected column display size", 32, meta.getColumnDisplaySize(3));
+    assertEquals("Unexpected column display size", 16, meta.getColumnDisplaySize(4));
+    assertEquals("Unexpected column display size", 16, meta.getColumnDisplaySize(5));
+
+    for (int i = 1; i <= 5; i++) {
+      assertFalse(meta.isAutoIncrement(i));
+      assertFalse(meta.isCurrency(i));
+      assertEquals(ResultSetMetaData.columnNullable, meta.isNullable(i));
+
+      int expectedPrecision = i == 5 ? -1 : 0;
+      int expectedScale     = i == 5 ? -1 : 0;
+      assertEquals("Unexpected precision", expectedPrecision, meta.getPrecision(i));
+      assertEquals("Unexpected scale", expectedScale, meta.getScale(i));
+    }
+  }
+
+  // [url] [host] [port] [db]
+  private static final String[][] URL_PROPERTIES = new String[][] {
+          {"jdbc:hive://", "", "", "default"},
+          {"jdbc:hive://localhost:10001/default", "localhost", "10001", "default"},
+          {"jdbc:hive://localhost/notdefault", "localhost", "10000", "notdefault"},
+          {"jdbc:hive://foo:1243", "foo", "1243", "default"}
+  };
+  
+  public void testDriverProperties() throws SQLException {
+    HiveDriver driver = new HiveDriver();
+
+    for (String[] testValues : URL_PROPERTIES) {
+      DriverPropertyInfo[] dpi = driver.getPropertyInfo(testValues[0], null);
+      assertEquals("unexpected DriverPropertyInfo array size", 3, dpi.length);
+      assertDpi(dpi[0], "HOST", testValues[1]);
+      assertDpi(dpi[1], "PORT", testValues[2]);
+      assertDpi(dpi[2], "DBNAME", testValues[3]);
+    }
+
+  }
+
+  private static void assertDpi(DriverPropertyInfo dpi, String name, String value) {
+    assertEquals("Invalid DriverPropertyInfo name", name, dpi.name);
+    assertEquals("Invalid DriverPropertyInfo value", value, dpi.value);
+    assertEquals("Invalid DriverPropertyInfo required", false, dpi.required);
+  }
 }