Permalink
Browse files

Adding a client driver for a JDBC database to be interfaced

with YCSB.
  • Loading branch information...
1 parent 664f3d1 commit 9c808f361b3a5455164e4fb9ac62fca8c5880fda @sudiptodas sudiptodas committed Dec 10, 2010
View
5 build.xml
@@ -44,6 +44,11 @@
<property name="db.dir" value="db/voldemort"/>
<antcall target="dbcompile"/>
</target>
+
+ <target name="dbcompile-jdbc" depends="compile">
+ <property name="db.dir" value="db/jdbc"/>
+ <antcall target="dbcompile"/>
+ </target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
View
6 db/jdbc/conf/db.properties
@@ -0,0 +1,6 @@
+# Properties file that contains database connection information.
+
+jdbc.driver=org.h2.Driver
+db.url=jdbc:h2:tcp://foo.com:9092/~/h2/ycsb
+db.user=sa
+db.passwd=
View
6 db/jdbc/conf/h2.properties
@@ -0,0 +1,6 @@
+# Properties file that contains database connection information.
+
+jdbc.driver=org.h2.Driver
+db.url=jdbc:h2:tcp://foo.com:9092/~/h2/ycsb
+db.user=sa
+db.passwd=
View
1 db/jdbc/sql/README
@@ -0,0 +1 @@
+Contains all the SQL statements used by the JDBC client.
View
12 db/jdbc/sql/create_table.sql
@@ -0,0 +1,12 @@
+-- Creates a Table.
+
+-- Drop the table if it exists;
+DROP TABLE IF EXISTS USERTABLE;
+
+-- Create the user table with 5 fields.
+CREATE TABLE usertable(KEY VARCHAR PRIMARY KEY,
+ FIELD1 VARCHAR, FIELD2 VARCHAR,
+ FIELD3 VARCHAR, FIELD4 VARCHAR,
+ FIELD5 VARCHAR, FIELD6 VARCHAR,
+ FIELD7 VARCHAR, FIELD8 VARCHAR,
+ FIELD9 VARCHAR, FIELD10 VARCHAR);
View
178 db/jdbc/src/com/yahoo/ycsb/db/JdbcDBCli.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
+ *
+ * Licensed 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. See accompanying
+ * LICENSE file.
+ */
+package com.yahoo.ycsb.db;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Execute a JDBC command line.
+ *
+ * @author sudipto
+ *
+ */
+public class JdbcDBCli implements JdbcDBClientConstants {
+
+ private static void usageMessage() {
+ System.out.println("JdbcCli. Options:");
+ System.out.println(" -p key=value properties defined.");
+ System.out.println(" -P location of the properties file to load.");
+ System.out.println(" -c SQL command to execute.");
+ }
+
+ private static void executeCommand(Properties props, String sql)
+ throws SQLException {
+ String driver = props.getProperty(DRIVER_CLASS);
+ String username = props.getProperty(CONNECTION_USER);
+ String password = props.getProperty(CONNECTION_PASSWD, "");
+ String url = props.getProperty(CONNECTION_URL);
+ if (driver == null || username == null || url == null) {
+ throw new SQLException("Missing connection information.");
+ }
+
+ Connection conn = null;
+
+ try {
+ Class.forName(driver);
+
+ conn = DriverManager.getConnection(url, username, password);
+ Statement stmt = conn.createStatement();
+ stmt.execute(sql);
+ System.out.println("Command \"" + sql + "\" successfully executed.");
+ } catch (ClassNotFoundException e) {
+ throw new SQLException("JDBC Driver class not found.");
+ } finally {
+ if (conn != null) {
+ System.out.println("Closing database connection.");
+ conn.close();
+ }
+ }
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+
+ if (args.length == 0) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ Properties props = new Properties();
+ Properties fileprops = new Properties();
+ String sql = null;
+
+ // parse arguments
+ int argindex = 0;
+ while (args[argindex].startsWith("-")) {
+ if (args[argindex].compareTo("-P") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ String propfile = args[argindex];
+ argindex++;
+
+ Properties myfileprops = new Properties();
+ try {
+ myfileprops.load(new FileInputStream(propfile));
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ System.exit(0);
+ }
+
+ // Issue #5 - remove call to stringPropertyNames to make compilable
+ // under Java 1.5
+ for (Enumeration<?> e = myfileprops.propertyNames(); e
+ .hasMoreElements();) {
+ String prop = (String) e.nextElement();
+
+ fileprops.setProperty(prop, myfileprops.getProperty(prop));
+ }
+
+ } else if (args[argindex].compareTo("-p") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ int eq = args[argindex].indexOf('=');
+ if (eq < 0) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ String name = args[argindex].substring(0, eq);
+ String value = args[argindex].substring(eq + 1);
+ props.put(name, value);
+ argindex++;
+ } else if (args[argindex].compareTo("-c") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ sql = args[argindex++];
+ } else {
+ System.out.println("Unknown option " + args[argindex]);
+ usageMessage();
+ System.exit(0);
+ }
+
+ if (argindex >= args.length) {
+ break;
+ }
+ }
+
+ if (argindex != args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ // overwrite file properties with properties from the command line
+
+ // Issue #5 - remove call to stringPropertyNames to make compilable under
+ // Java 1.5
+ for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements();) {
+ String prop = (String) e.nextElement();
+
+ fileprops.setProperty(prop, props.getProperty(prop));
+ }
+
+ if (sql == null) {
+ System.err.println("Missing command.");
+ usageMessage();
+ System.exit(1);
+ }
+
+ try {
+ executeCommand(fileprops, sql);
+ } catch (SQLException e) {
+ System.err.println("Error in executing command. " + e);
+ System.exit(1);
+ }
+ }
+
+}
View
410 db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClient.java
@@ -0,0 +1,410 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
+ *
+ * Licensed 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. See accompanying
+ * LICENSE file.
+ */
+
+package com.yahoo.ycsb.db;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.yahoo.ycsb.DB;
+import com.yahoo.ycsb.DBException;
+
+/**
+ * A class that wraps a JDBC compliant database to allow it to be interfaced with YCSB.
+ * This class extends {@link DB} and implements the database interface used by YCSB client.
+ *
+ * <br> Each client will have its own instance of this class. This client is
+ * not thread safe.
+ *
+ * <br> This interface expects a schema <key> <field1> <field2> <field3> ...
+ * All attributes are of type VARCHAR. All accesses are through the primary key. Therefore,
+ * only one index on the primary key is needed.
+ *
+ * <p> The following options must be passed when using this database client.
+ *
+ * <ul>
+ * <li><b>db.driver</b> The JDBC driver class to use.</li>
+ * <li><b>db.url</b> The Database connection URL.</li>
+ * <li><b>db.user</b> User name for the connection.</li>
+ * <li><b>db.passwd</b> Password for the connection.</li>
+ * </ul>
+ *
+ * @author sudipto
+ *
+ */
+public class JdbcDBClient extends DB implements JdbcDBClientConstants {
+
+ private Connection conn;
+ private boolean initialized = false;
+ private Properties props;
+ private static final String DEFAULT_PROP = "";
+ private ConcurrentMap<StatementType, PreparedStatement> cachedStatements;
+
+ /**
+ * The statement type for the prepared statements.
+ */
+ private static class StatementType {
+
+ enum Type {
+ INSERT(1),
+ DELETE(2),
+ READ(3),
+ UPDATE(4),
+ SCAN(5),
+ ;
+ int internalType;
+ private Type(int type) {
+ internalType = type;
+ }
+
+ int getHashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + internalType;
+ return result;
+ }
+ }
+
+ Type type;
+ int numFields;
+ String tableName;
+
+ StatementType(Type type, String tableName, int numFields) {
+ this.type = type;
+ this.tableName = tableName;
+ this.numFields = numFields;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + numFields;
+ result = prime * result
+ + ((tableName == null) ? 0 : tableName.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.getHashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StatementType other = (StatementType) obj;
+ if (numFields != other.numFields)
+ return false;
+ if (tableName == null) {
+ if (other.tableName != null)
+ return false;
+ } else if (!tableName.equals(other.tableName))
+ return false;
+ if (type != other.type)
+ return false;
+ return true;
+ }
+ }
+
+ /**
+ * Initialize the database connection and set it up for sending requests to the database.
+ * This must be called once per client.
+ * @throws
+ */
+ @Override
+ public void init() throws DBException {
+ if (initialized) {
+ System.err.println("Client connection already initialized.");
+ return;
+ }
+ props = getProperties();
+ String url = props.getProperty(CONNECTION_URL, DEFAULT_PROP);
+ String user = props.getProperty(CONNECTION_USER, DEFAULT_PROP);
+ String passwd = props.getProperty(CONNECTION_PASSWD, DEFAULT_PROP);
+ String driver = props.getProperty(DRIVER_CLASS);
+ try {
+ if (driver != null) {
+ Class.forName(driver);
+ }
+ conn = DriverManager.getConnection(url, user, passwd);
+ // Since there is no explicit commit method in the DB interface, all
+ // operations should auto commit.
+ conn.setAutoCommit(true);
+ cachedStatements = new ConcurrentHashMap<StatementType, PreparedStatement>();
+ } catch (ClassNotFoundException e) {
+ System.err.println("Error in initializing the JDBS driver: " + e);
+ throw new DBException(e);
+ } catch (SQLException e) {
+ System.err.println("Error in database operation: " + e);
+ throw new DBException(e);
+ } catch (NumberFormatException e) {
+ System.err.println("Invalid value for fieldcount property. " + e);
+ throw new DBException(e);
+ }
+ initialized = true;
+ }
+
+ @Override
+ public void cleanup() throws DBException {
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ System.err.println("Error in closing the connection. " + e);
+ throw new DBException(e);
+ }
+ }
+
+ private PreparedStatement createAndCacheInsertStatement(StatementType insertType)
+ throws SQLException {
+ StringBuilder insert = new StringBuilder("INSERT INTO ");
+ insert.append(insertType.tableName);
+ insert.append(" VALUES(?");
+ for (int i = 0; i < insertType.numFields; i++) {
+ insert.append(",?");
+ }
+ insert.append(");");
+ PreparedStatement insertStatement = conn.prepareStatement(insert.toString());
+ PreparedStatement stmt = cachedStatements.putIfAbsent(insertType, insertStatement);
+ if (stmt == null) return insertStatement;
+ else return stmt;
+ }
+
+ private PreparedStatement createAndCacheReadStatement(StatementType readType)
+ throws SQLException {
+ StringBuilder read = new StringBuilder("SELECT * FROM ");
+ read.append(readType.tableName);
+ read.append(" WHERE ");
+ read.append(PRIMARY_KEY);
+ read.append(" = ");
+ read.append("?;");
+ PreparedStatement readStatement = conn.prepareStatement(read.toString());
+ PreparedStatement stmt = cachedStatements.putIfAbsent(readType, readStatement);
+ if (stmt == null) return readStatement;
+ else return stmt;
+ }
+
+ private PreparedStatement createAndCacheDeleteStatement(StatementType deleteType)
+ throws SQLException {
+ StringBuilder delete = new StringBuilder("DELETE FROM ");
+ delete.append(deleteType.tableName);
+ delete.append(" WHERE ");
+ delete.append(PRIMARY_KEY);
+ delete.append(" = ?;");
+ PreparedStatement deleteStatement = conn.prepareStatement(delete.toString());
+ PreparedStatement stmt = cachedStatements.putIfAbsent(deleteType, deleteStatement);
+ if (stmt == null) return deleteStatement;
+ else return stmt;
+ }
+
+ private PreparedStatement createAndCacheUpdateStatement(StatementType updateType)
+ throws SQLException {
+ StringBuilder update = new StringBuilder("UPDATE ");
+ update.append(updateType.tableName);
+ update.append(" SET ");
+ for (int i = 1; i <= updateType.numFields; i++) {
+ update.append(COLUMN_PREFIX);
+ update.append(i);
+ update.append("=?");
+ if (i < updateType.numFields) update.append(", ");
+ }
+ update.append(" WHERE ");
+ update.append(PRIMARY_KEY);
+ update.append(" = ?;");
+ PreparedStatement insertStatement = conn.prepareStatement(update.toString());
+ PreparedStatement stmt = cachedStatements.putIfAbsent(updateType, insertStatement);
+ if (stmt == null) return insertStatement;
+ else return stmt;
+ }
+
+ private PreparedStatement createAndCacheScanStatement(StatementType scanType)
+ throws SQLException {
+ StringBuilder select = new StringBuilder("SELECT * FROM ");
+ select.append(scanType.tableName);
+ select.append(" WHERE ");
+ select.append(PRIMARY_KEY);
+ select.append(" >= ");
+ select.append("?;");
+ PreparedStatement scanStatement = conn.prepareStatement(select.toString());
+ PreparedStatement stmt = cachedStatements.putIfAbsent(scanType, scanStatement);
+ if (stmt == null) return scanStatement;
+ else return stmt;
+ }
+
+ @Override
+ public int read(String tableName, String key, Set<String> fields,
+ HashMap<String, String> result) {
+ if (tableName == null) {
+ return -1;
+ }
+ if (key == null) {
+ return -1;
+ }
+ try {
+ StatementType type = new StatementType(StatementType.Type.READ, tableName, 1);
+ PreparedStatement readStatement = cachedStatements.get(type);
+ if (readStatement == null) {
+ readStatement = createAndCacheReadStatement(type);
+ }
+ readStatement.setString(1, key);
+ ResultSet resultSet = readStatement.executeQuery();
+ if (!resultSet.next()) {
+ resultSet.close();
+ return 1;
+ }
+ if (result != null && fields != null) {
+ for (String field : fields) {
+ String value = resultSet.getString(field);
+ result.put(field, value);
+ }
+ }
+ resultSet.close();
+ return SUCCESS;
+ } catch (SQLException e) {
+ return -2;
+ }
+ }
+
+ @Override
+ public int scan(String tableName, String startKey, int recordcount,
+ Set<String> fields, Vector<HashMap<String, String>> result) {
+ if (tableName == null) {
+ return -1;
+ }
+ if (startKey == null) {
+ return -1;
+ }
+ try {
+ StatementType type = new StatementType(StatementType.Type.SCAN, tableName, 1);
+ PreparedStatement scanStatement = cachedStatements.get(type);
+ if (scanStatement == null) {
+ scanStatement = createAndCacheScanStatement(type);
+ }
+ scanStatement.setString(1, startKey);
+ ResultSet resultSet = scanStatement.executeQuery();
+ for (int i = 0; i < recordcount && resultSet.next(); i++) {
+ if (result != null && fields != null) {
+ HashMap<String, String> values = new HashMap<String, String>();
+ for (String field : fields) {
+ String value = resultSet.getString(field);
+ values.put(field, value);
+ }
+ result.add(values);
+ }
+ }
+ resultSet.close();
+ return SUCCESS;
+ } catch (SQLException e) {
+ System.err.println("Error in processing scan of table: " + tableName + e);
+ return -2;
+ }
+ }
+
+ @Override
+ public int update(String tableName, String key, HashMap<String, String> values) {
+ if (tableName == null) {
+ return -1;
+ }
+ if (key == null) {
+ return -1;
+ }
+ try {
+ int numFields = values.size();
+ StatementType type = new StatementType(StatementType.Type.UPDATE, tableName, numFields);
+ PreparedStatement updateStatement = cachedStatements.get(type);
+ if (updateStatement == null) {
+ updateStatement = createAndCacheUpdateStatement(type);
+ }
+ int index = 1;
+ for (Map.Entry<String, String> entry : values.entrySet()) {
+ updateStatement.setString(index++, entry.getValue());
+ }
+ updateStatement.setString(index, key);
+ int result = updateStatement.executeUpdate();
+ if (result == 1) return SUCCESS;
+ else return 1;
+ } catch (SQLException e) {
+ System.err.println("Error in processing update to table: " + tableName + e);
+ return -1;
+ }
+ }
+
+ @Override
+ public int insert(String tableName, String key, HashMap<String, String> values) {
+ if (tableName == null) {
+ return -1;
+ }
+ if (key == null) {
+ return -1;
+ }
+ try {
+ int numFields = values.size();
+ StatementType type = new StatementType(StatementType.Type.INSERT, tableName, numFields);
+ PreparedStatement insertStatement = cachedStatements.get(type);
+ if (insertStatement == null) {
+ insertStatement = createAndCacheInsertStatement(type);
+ }
+ insertStatement.setString(1, key);
+ int index = 2;
+ for (Map.Entry<String, String> entry : values.entrySet()) {
+ String field = entry.getValue();
+ insertStatement.setString(index++, field);
+ }
+ int result = insertStatement.executeUpdate();
+ if (result == 1) return SUCCESS;
+ else return 1;
+ } catch (SQLException e) {
+ System.err.println("Error in processing insert to table: " + tableName + e);
+ return -1;
+ }
+ }
+
+ @Override
+ public int delete(String tableName, String key) {
+ if (tableName == null) {
+ return -1;
+ }
+ if (key == null) {
+ return -1;
+ }
+ try {
+ StatementType type = new StatementType(StatementType.Type.DELETE, tableName, 1);
+ PreparedStatement deleteStatement = cachedStatements.get(type);
+ if (deleteStatement == null) {
+ deleteStatement = createAndCacheDeleteStatement(type);
+ }
+ deleteStatement.setString(1, key);
+ int result = deleteStatement.executeUpdate();
+ if (result == 1) return SUCCESS;
+ else return 1;
+ } catch (SQLException e) {
+ System.err.println("Error in processing delete to table: " + tableName + e);
+ return -1;
+ }
+ }
+}
View
56 db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClientConstants.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
+ *
+ * Licensed 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. See accompanying
+ * LICENSE file.
+ */
+package com.yahoo.ycsb.db;
+
+/**
+ * Constants used by the JDBC client.
+ *
+ * @author sudipto
+ *
+ */
+public interface JdbcDBClientConstants {
+
+ /** The class to use as the jdbc driver. */
+ public static final String DRIVER_CLASS = "db.driver";
+
+ /** The URL to connect to the database. */
+ public static final String CONNECTION_URL = "db.url";
+
+ /** The user name to use to connect to the database. */
+ public static final String CONNECTION_USER = "db.user";
+
+ /** The password to use for establishing the connection. */
+ public static final String CONNECTION_PASSWD = "db.passwd";
+
+ /** The name of the property for the number of fields in a record. */
+ public static final String FIELD_COUNT_PROPERTY="fieldcount";
+
+ /** Default number of fields in a record. */
+ public static final String FIELD_COUNT_PROPERTY_DEFAULT="10";
+
+ /** Representing a NULL value. */
+ public static final String NULL_VALUE = "NULL";
+
+ /** The code to return when the call succeeds. */
+ public static final int SUCCESS = 0;
+
+ /** The primary key in the user table.*/
+ public static String PRIMARY_KEY = "KEY";
+
+ /** The field name prefix in the table.*/
+ public static String COLUMN_PREFIX = "FIELD";
+}
View
220 db/jdbc/src/com/yahoo/ycsb/db/JdbcDBCreateTable.java
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
+ *
+ * Licensed 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. See accompanying
+ * LICENSE file.
+ */
+package com.yahoo.ycsb.db;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Utility class to create the table to be used by the benchmark.
+ *
+ * @author sudipto
+ *
+ */
+public class JdbcDBCreateTable implements JdbcDBClientConstants {
+
+ private static void usageMessage() {
+ System.out.println("Create Table Client. Options:");
+ System.out.println(" -p key=value properties defined.");
+ System.out.println(" -P location of the properties file to load.");
+ System.out.println(" -n name of the table.");
+ System.out.println(" -f number of fields (default 10).");
+ }
+
+ private static void createTable(Properties props, String tablename)
+ throws SQLException {
+ String driver = props.getProperty(DRIVER_CLASS);
+ String username = props.getProperty(CONNECTION_USER);
+ String password = props.getProperty(CONNECTION_PASSWD, "");
+ String url = props.getProperty(CONNECTION_URL);
+ int fieldcount = Integer.parseInt(props.getProperty(FIELD_COUNT_PROPERTY,
+ FIELD_COUNT_PROPERTY_DEFAULT));
+
+ if (driver == null || username == null || url == null) {
+ throw new SQLException("Missing connection information.");
+ }
+
+ Connection conn = null;
+
+ try {
+ Class.forName(driver);
+
+ conn = DriverManager.getConnection(url, username, password);
+ Statement stmt = conn.createStatement();
+
+ StringBuilder sql = new StringBuilder("DROP TABLE IF EXISTS ");
+ sql.append(tablename);
+ sql.append(";");
+
+ stmt.execute(sql.toString());
+
+ sql = new StringBuilder("CREATE TABLE ");
+ sql.append(tablename);
+ sql.append(" (KEY VARCHAR PRIMARY KEY");
+
+ for (int idx = 0; idx < fieldcount; idx++) {
+ sql.append(", FIELD");
+ sql.append(idx);
+ sql.append(" VARCHAR");
+ }
+ sql.append(");");
+
+ stmt.execute(sql.toString());
+
+ System.out.println("Table " + tablename + " created..");
+ } catch (ClassNotFoundException e) {
+ throw new SQLException("JDBC Driver class not found.");
+ } finally {
+ if (conn != null) {
+ System.out.println("Closing database connection.");
+ conn.close();
+ }
+ }
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+
+ if (args.length == 0) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ String tablename = null;
+ int fieldcount = -1;
+ Properties props = new Properties();
+ Properties fileprops = new Properties();
+
+ // parse arguments
+ int argindex = 0;
+ while (args[argindex].startsWith("-")) {
+ if (args[argindex].compareTo("-P") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ String propfile = args[argindex];
+ argindex++;
+
+ Properties myfileprops = new Properties();
+ try {
+ myfileprops.load(new FileInputStream(propfile));
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ System.exit(0);
+ }
+
+ // Issue #5 - remove call to stringPropertyNames to make compilable
+ // under Java 1.5
+ for (Enumeration<?> e = myfileprops.propertyNames(); e
+ .hasMoreElements();) {
+ String prop = (String) e.nextElement();
+
+ fileprops.setProperty(prop, myfileprops.getProperty(prop));
+ }
+
+ } else if (args[argindex].compareTo("-p") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ int eq = args[argindex].indexOf('=');
+ if (eq < 0) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ String name = args[argindex].substring(0, eq);
+ String value = args[argindex].substring(eq + 1);
+ props.put(name, value);
+ argindex++;
+ } else if (args[argindex].compareTo("-n") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ tablename = args[argindex++];
+ } else if (args[argindex].compareTo("-f") == 0) {
+ argindex++;
+ if (argindex >= args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+ try {
+ fieldcount = Integer.parseInt(args[argindex++]);
+ } catch (NumberFormatException e) {
+ System.err.println("Invalid number for field count");
+ usageMessage();
+ System.exit(1);
+ }
+ } else {
+ System.out.println("Unknown option " + args[argindex]);
+ usageMessage();
+ System.exit(0);
+ }
+
+ if (argindex >= args.length) {
+ break;
+ }
+ }
+
+ if (argindex != args.length) {
+ usageMessage();
+ System.exit(0);
+ }
+
+ // overwrite file properties with properties from the command line
+
+ // Issue #5 - remove call to stringPropertyNames to make compilable under
+ // Java 1.5
+ for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements();) {
+ String prop = (String) e.nextElement();
+
+ fileprops.setProperty(prop, props.getProperty(prop));
+ }
+
+ props = fileprops;
+
+ if (tablename == null) {
+ System.err.println("table name missing.");
+ usageMessage();
+ System.exit(1);
+ }
+
+ if (fieldcount > 0) {
+ props.setProperty(FIELD_COUNT_PROPERTY, String.valueOf(fieldcount));
+ }
+
+ try {
+ createTable(props, tablename);
+ } catch (SQLException e) {
+ System.err.println("Error in creating table. " + e);
+ System.exit(1);
+ }
+ }
+}

0 comments on commit 9c808f3

Please sign in to comment.