Read column types from header of CSV file.
diff --git a/README.md b/README.md
index c37c547..4d85705 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
Download and build
==================
-You need Java (1.7 or higher) and maven (2 or higher).
+You need Java (1.5 or higher; 1.7 preferred) and maven (2 or higher).
$ git clone git://github.com/julianhyde/optiq-csv.git
$ cd optiq-csv
@@ -19,7 +19,10 @@
===========
$ ./sqlline
- sqlline> connect jdbc:optiq:model=target/test-classes/model.json admin admin
+ sqlline> !connect jdbc:optiq:model=target/test-classes/model.json admin admin
+ sqlline> select * from emp;
+ sqlline> !tables
+ sqlline> !quit
Advanced use
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java
index 37cbf56..8f97ad3 100644
--- a/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java
@@ -17,16 +17,19 @@
*/
package net.hydromatic.optiq.impl.csv;
+import au.com.bytecode.opencsv.CSVReader;
import net.hydromatic.linq4j.*;
import net.hydromatic.linq4j.expressions.Expression;
import net.hydromatic.optiq.*;
import net.hydromatic.optiq.impl.TableInSchemaImpl;
+import net.hydromatic.optiq.impl.java.JavaTypeFactory;
+import net.hydromatic.optiq.jdbc.OptiqConnection;
import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.util.Pair;
-import java.io.File;
-import java.io.FilenameFilter;
+import java.io.*;
import java.util.*;
/**
@@ -37,6 +40,8 @@
private final Schema parentSchema;
private final File directoryFile;
private final Expression expression;
+ private final JavaTypeFactory typeFactory;
+ private final RelDataType stringType;
private Map<String, TableInSchema> map;
public CsvSchema(
@@ -47,6 +52,8 @@
this.parentSchema = parentSchema;
this.directoryFile = directoryFile;
this.expression = expression;
+ this.typeFactory = ((OptiqConnection) getQueryProvider()).getTypeFactory();
+ this.stringType = typeFactory.createJavaType(String.class);
}
public Expression getExpression() {
@@ -103,9 +110,9 @@
tableName = tableName.substring(
0, tableName.length() - ".csv".length());
}
- final RelDataType rowType = null;
- final CsvTable table = new CsvTable(
- String[].class, rowType, this, tableName);
+ final RelDataType rowType = deduceRowType(file);
+ final CsvTable table =
+ new CsvTable(String[].class, rowType, this, tableName);
map.put(
tableName,
new TableInSchemaImpl(this, tableName, TableType.TABLE, table));
@@ -113,6 +120,54 @@
}
return map;
}
+
+ private RelDataType deduceRowType(File file) {
+ final List<RelDataType> types = new ArrayList<RelDataType>();
+ final List<String> names = new ArrayList<String>();
+ CSVReader reader = null;
+ try {
+ reader = new CSVReader(new FileReader(file));
+ final String[] strings = reader.readNext();
+ for (String string : strings) {
+ RelDataType type;
+ String name;
+ final int colon = string.indexOf(':');
+ if (colon >= 0) {
+ name = string.substring(0, colon);
+ String typeString = string.substring(colon + 1);
+ if (typeString.equals("String")) {
+ type = stringType;
+ } else {
+ try {
+ type = typeFactory.createJavaType(Class.forName(typeString));
+ } catch (ClassNotFoundException e) {
+ type = stringType;
+ }
+ }
+ } else {
+ name = string;
+ type = stringType;
+ }
+ names.add(name);
+ types.add(type);
+ }
+ } catch (IOException e) {
+ // ignore
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ if (names.isEmpty()) {
+ names.add("line");
+ types.add(stringType);
+ }
+ return typeFactory.createStructType(Pair.zip(names, types));
+ }
}
// End CsvSchema.java
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/CsvTableScan.java b/src/main/java/net/hydromatic/optiq/impl/csv/CsvTableScan.java
index 861f293..d029be7 100644
--- a/src/main/java/net/hydromatic/optiq/impl/csv/CsvTableScan.java
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvTableScan.java
@@ -21,6 +21,7 @@
import net.hydromatic.optiq.impl.java.JavaTypeFactory;
import net.hydromatic.optiq.rules.java.*;
+import org.eigenbase.rel.RelNode;
import org.eigenbase.rel.TableAccessRelBase;
import org.eigenbase.relopt.*;
import org.eigenbase.reltype.RelDataType;
@@ -49,7 +50,7 @@
List<String> fieldList)
{
super(
- cluster, cluster.traitSetOf(Convention.NONE), table);
+ cluster, cluster.traitSetOf(EnumerableConvention.ARRAY), table);
this.csvTable = csvTable;
this.fieldList = fieldList;
this.physType =
@@ -66,6 +67,12 @@
}
@Override
+ public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ assert inputs.isEmpty();
+ return new CsvTableScan(getCluster(), table, csvTable, fieldList);
+ }
+
+ @Override
public void explain(RelOptPlanWriter pw) {
pw.explain(
this,