Initial revision.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..decfbf9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*~
+target
+.idea
+*.iml
+settings.xml
+cp.txt
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..b515fc0
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,16 @@
+optiq-csv
+Optiq adapter that reads CSV files.
+Copyright (C) 2013-2013 Julian Hyde
+
+===============================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software 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.
diff --git a/README.md b/README.md
index f8af728..c37c547 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,45 @@
optiq-csv
-=========
+============
-Optiq adapter that reads CSV files.
+Optiq adapter that reads <a href="http://en.wikipedia.org/wiki/Comma-separated_values">CSV</a> files.
+
+Optiq-csv is a nice simple example of how to connect Optiq to your own
+data source and quickly get a full SQL/JDBC interface.
+
+Download and build
+==================
+
+You need Java (1.7 or higher) and maven (2 or higher).
+
+ $ git clone git://github.com/julianhyde/optiq-csv.git
+ $ cd optiq-csv
+ $ mvn compile
+
+Run sqlline
+===========
+
+ $ ./sqlline
+ sqlline> connect jdbc:optiq:model=target/test-classes/model.json admin admin
+
+
+Advanced use
+============
+
+You can also register a CsvSchema as a schema within an Optiq instance.
+Then you can combine with other data sources.
+
+You can write a "vanity JDBC driver" with a different name.
+
+You can add optimizer rules and new implementations of relational
+operators to execute queries more efficiently.
+
+More information
+================
+
+* License: Apache License, Version 2.0.
+* Author: Julian Hyde
+* Blog: http://julianhyde.blogspot.com
+* Project page: http://www.hydromatic.net/optiq-csv
+* Source code: http://github.com/julianhyde/optiq-csv
+* Developers list: http://groups.google.com/group/optiq-dev
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4311ca4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,174 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- The basics. -->
+ <groupId>net.hydromatic</groupId>
+ <artifactId>optiq-csv</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <!-- More project information. -->
+ <name>optiq-csv</name>
+ <description>Optiq provider that reads CSV files.</description>
+ <url>http://github.com/julianhyde/optiq-csv</url>
+ <inceptionYear>2013</inceptionYear>
+ <organization>
+ <name>Julian Hyde</name>
+ <url>http://www.hydromatic.net</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>Apache 2</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
+ </license>
+ </licenses>
+
+ <developers>
+ <developer>
+ <id>julianhyde</id>
+ <name>Julian Hyde</name>
+ <email>julianhyde@gmail.com</email>
+ <url>https://github.com/julianhyde</url>
+ <roles>
+ <role>architect</role>
+ <role>developer</role>
+ </roles>
+ <timezone>-8</timezone>
+ <properties/>
+ </developer>
+ </developers>
+
+ <mailingLists>
+ <mailingList>
+ <name>Optiq developers list</name>
+ <subscribe>optiq-dev-subscribe@googlegroups.com</subscribe>
+ <unsubscribe>optiq-dev-unsubscribe@googlegroups.com</unsubscribe>
+ <post>optiq-dev@googlegroups.com</post>
+ <archive>http://groups.google.com/group/optiq-dev</archive>
+ </mailingList>
+ </mailingLists>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <!-- Environment settings. -->
+ <distributionManagement>
+ <repository>
+ <id>conjars</id>
+ <name>Concurrent Conjars repository</name>
+ <url>http://conjars.org/repo</url>
+ <layout>default</layout>
+ </repository>
+ </distributionManagement>
+
+ <issueManagement/>
+
+ <scm>
+ <connection>scm:git:git://github.com/julianhyde/optiq-csv.git</connection>
+ <developerConnection>scm:git:git@github.com:julianhyde/optiq-csv.git</developerConnection>
+ <url>http://github.com/julianhyde/optiq-csv/tree/master</url>
+ </scm>
+
+ <!-- Dependencies. -->
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.hydromatic</groupId>
+ <artifactId>optiq</artifactId>
+ <version>TRUNK-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>net.hydromatic</groupId>
+ <artifactId>linq4j</artifactId>
+ <version>0.1.3</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.opencsv</groupId>
+ <artifactId>opencsv</artifactId>
+ <version>2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>sqlline</groupId>
+ <artifactId>sqlline</artifactId>
+ <version>1.0.9</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.8.1</version>
+ <configuration>
+ <links>
+ <link>http://docs.oracle.com/javase/7/docs/api/</link>
+ </links>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <repositories>
+ <repository>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ <checksumPolicy>warn</checksumPolicy>
+ </releases>
+ <id>pentaho</id>
+ <name>Pentaho</name>
+ <url>http://repo.pentaho.org/artifactory/repo</url>
+ <layout>default</layout>
+ </repository>
+ <repository>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ <checksumPolicy>warn</checksumPolicy>
+ </releases>
+ <id>conjars</id>
+ <name>Conjars</name>
+ <url>http://conjars.org/repo</url>
+ <layout>default</layout>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ </plugin>
+
+ <!--
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ -->
+ </plugins>
+ </build>
+
+</project>
diff --git a/sqlline b/sqlline
new file mode 100755
index 0000000..aa43805
--- /dev/null
+++ b/sqlline
@@ -0,0 +1,12 @@
+#!/bin/bash
+# sqlline - Script to launch SQL shell
+
+# Build classpath on first call. (To force rebuild, remove cp.txt.)
+if [ ! -f cp.txt ]; then
+ mvn install
+ mvn dependency:build-classpath -Dmdep.outputFile=cp.txt
+fi
+
+java -cp "$(cat cp.txt)" sqlline.SqlLine "$@"
+
+# End sqlline
\ No newline at end of file
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java
new file mode 100644
index 0000000..37cbf56
--- /dev/null
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchema.java
@@ -0,0 +1,118 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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 net.hydromatic.optiq.impl.csv;
+
+import net.hydromatic.linq4j.*;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.*;
+import net.hydromatic.optiq.impl.TableInSchemaImpl;
+
+import org.eigenbase.reltype.RelDataType;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.*;
+
+/**
+ * Schema mapped onto a directory of CSV files. Each table in the schema
+ * is a CSV file in that directory.
+ */
+public class CsvSchema implements Schema {
+ private final Schema parentSchema;
+ private final File directoryFile;
+ private final Expression expression;
+ private Map<String, TableInSchema> map;
+
+ public CsvSchema(
+ Schema parentSchema,
+ File directoryFile,
+ Expression expression)
+ {
+ this.parentSchema = parentSchema;
+ this.directoryFile = directoryFile;
+ this.expression = expression;
+ }
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public List<TableFunction> getTableFunctions(String name) {
+ return Collections.emptyList();
+ }
+
+ public QueryProvider getQueryProvider() {
+ return parentSchema.getQueryProvider();
+ }
+
+ public Collection<TableInSchema> getTables() {
+ return computeMap().values();
+ }
+
+ public <T> CsvTable<T> getTable(String name, Class<T> elementType) {
+ final TableInSchema tableInSchema = computeMap().get(name);
+ return tableInSchema == null
+ ? null
+ : (CsvTable<T>) tableInSchema.getTable(elementType);
+ }
+
+ public Map<String, List<TableFunction>> getTableFunctions() {
+ // this kind of schema does not have table functions
+ return Collections.emptyMap();
+ }
+
+ public Schema getSubSchema(String name) {
+ // this kind of schema does not have sub-schemas
+ return null;
+ }
+
+ public Collection<String> getSubSchemaNames() {
+ // this kind of schema does not have sub-schemas
+ return Collections.emptyList();
+ }
+
+ /** Returns the map of tables by name, populating the map on first use. */
+ private synchronized Map<String, TableInSchema> computeMap() {
+ if (map == null) {
+ map = new HashMap<String, TableInSchema>();
+ File[] files = directoryFile.listFiles(
+ new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".csv");
+ }
+ });
+ for (File file : files) {
+ String tableName = file.getName();
+ if (tableName.endsWith(".csv")) {
+ tableName = tableName.substring(
+ 0, tableName.length() - ".csv".length());
+ }
+ final RelDataType rowType = null;
+ final CsvTable table = new CsvTable(
+ String[].class, rowType, this, tableName);
+ map.put(
+ tableName,
+ new TableInSchemaImpl(this, tableName, TableType.TABLE, table));
+ }
+ }
+ return map;
+ }
+}
+
+// End CsvSchema.java
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchemaFactory.java b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchemaFactory.java
new file mode 100644
index 0000000..14802f2
--- /dev/null
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvSchemaFactory.java
@@ -0,0 +1,45 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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 net.hydromatic.optiq.impl.csv;
+
+import net.hydromatic.optiq.*;
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * Factory that creates a {@link CsvSchema}.
+ *
+ * <p>Allows a custom schema to be included in a model.json file.</p>
+ */
+public class CsvSchemaFactory implements SchemaFactory {
+ public Schema create(MutableSchema parentSchema, String name,
+ Map<String, Object> operand) {
+ Map map = (Map) operand;
+ String directory = (String) map.get("directory");
+ final CsvSchema schema =
+ new CsvSchema(
+ parentSchema,
+ new File(directory),
+ parentSchema.getSubSchemaExpression(name, CsvSchema.class));
+ parentSchema.addSchema(name, schema);
+ return schema;
+ }
+}
+
+// End CsvSchemaFactory.java
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/CsvTable.java b/src/main/java/net/hydromatic/optiq/impl/csv/CsvTable.java
new file mode 100644
index 0000000..70cf232
--- /dev/null
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvTable.java
@@ -0,0 +1,128 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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 net.hydromatic.optiq.impl.csv;
+
+import net.hydromatic.linq4j.*;
+import net.hydromatic.linq4j.expressions.Expression;
+import net.hydromatic.linq4j.expressions.Expressions;
+import net.hydromatic.optiq.*;
+
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.RelOptTable;
+import org.eigenbase.relopt.RelOptUtil;
+import org.eigenbase.reltype.RelDataType;
+
+import java.lang.reflect.Type;
+import java.util.Iterator;
+
+/**
+ * Table based on a CSV file.
+ */
+class CsvTable<T>
+ extends AbstractQueryable<T>
+ implements TranslatableTable<T>
+{
+ private final Type elementType;
+ private final RelDataType rowType;
+ final CsvSchema schema;
+ private final String tableName;
+
+ public CsvTable(
+ Type elementType,
+ RelDataType rowType,
+ CsvSchema schema,
+ String tableName)
+ {
+ this.elementType = elementType;
+ this.rowType = rowType;
+ this.schema = schema;
+ this.tableName = tableName;
+ assert elementType != null;
+ assert rowType != null;
+ assert schema != null;
+ assert tableName != null;
+ }
+
+ public String toString() {
+ return "CsvTable {" + tableName + "}";
+ }
+
+ public QueryProvider getProvider() {
+ return schema.getQueryProvider();
+ }
+
+ public DataContext getDataContext() {
+ return schema;
+ }
+
+ public Type getElementType() {
+ return elementType;
+ }
+
+ public RelDataType getRowType() {
+ return rowType;
+ }
+
+ public Statistic getStatistic() {
+ return Statistics.UNKNOWN;
+ }
+
+ public Expression getExpression() {
+ return Expressions.call(
+ schema.getExpression(),
+ "getTable",
+ Expressions.<Expression>list()
+ .append(Expressions.constant(tableName))
+ .appendIf(
+ elementType instanceof Class,
+ Expressions.constant(elementType)));
+ }
+
+ public Iterator<T> iterator() {
+ return Linq4j.enumeratorIterator(enumerator());
+ }
+
+ public Enumerator<T> enumerator() {
+ return new Enumerator<T>() {
+ public T current() {
+ return null;
+ }
+
+ public boolean moveNext() {
+ return false;
+ }
+
+ public void reset() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public RelNode toRel(
+ RelOptTable.ToRelContext context,
+ RelOptTable relOptTable)
+ {
+ return new CsvTableScan(
+ context.getCluster(),
+ relOptTable,
+ this,
+ RelOptUtil.getFieldNameList(relOptTable.getRowType()));
+ }
+}
+
+// End CsvTable.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
new file mode 100644
index 0000000..861f293
--- /dev/null
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/CsvTableScan.java
@@ -0,0 +1,92 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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 net.hydromatic.optiq.impl.csv;
+
+import net.hydromatic.linq4j.expressions.*;
+import net.hydromatic.optiq.impl.java.JavaTypeFactory;
+import net.hydromatic.optiq.rules.java.*;
+
+import org.eigenbase.rel.TableAccessRelBase;
+import org.eigenbase.relopt.*;
+import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.reltype.RelDataTypeFactory;
+import org.eigenbase.util.Pair;
+
+import java.util.*;
+
+/**
+ * Relational expression representing a scan of a CSV file.
+ *
+ * <p>Like any table scan, it serves as a leaf node of a query tree.</p>
+ */
+public class CsvTableScan
+ extends TableAccessRelBase
+ implements EnumerableRel
+{
+ final CsvTable csvTable;
+ final List<String> fieldList;
+ final PhysType physType;
+
+ protected CsvTableScan(
+ RelOptCluster cluster,
+ RelOptTable table,
+ CsvTable csvTable,
+ List<String> fieldList)
+ {
+ super(
+ cluster, cluster.traitSetOf(Convention.NONE), table);
+ this.csvTable = csvTable;
+ this.fieldList = fieldList;
+ this.physType =
+ PhysTypeImpl.of(
+ (JavaTypeFactory) cluster.getTypeFactory(),
+ getRowType(),
+ (EnumerableConvention) getConvention());
+
+ assert csvTable != null;
+ }
+
+ public PhysType getPhysType() {
+ return physType;
+ }
+
+ @Override
+ public void explain(RelOptPlanWriter pw) {
+ pw.explain(
+ this,
+ Collections.singletonList(
+ Pair.<String, Object>of("table", table.getQualifiedName())));
+ }
+
+ @Override
+ public RelDataType deriveRowType() {
+ final RelDataTypeFactory.FieldInfoBuilder builder =
+ new RelDataTypeFactory.FieldInfoBuilder();
+ for (String field : fieldList) {
+ builder.add(table.getRowType().getField(field));
+ }
+ return getCluster().getTypeFactory().createStructType(builder);
+ }
+
+ public BlockExpression implement(EnumerableRelImplementor implementor) {
+ Expression expression = null;
+ return Blocks.toBlock(expression);
+ }
+}
+
+// End CsvTableScan.java
diff --git a/src/main/java/net/hydromatic/optiq/impl/csv/package-info.java b/src/main/java/net/hydromatic/optiq/impl/csv/package-info.java
new file mode 100644
index 0000000..e4bf8dd
--- /dev/null
+++ b/src/main/java/net/hydromatic/optiq/impl/csv/package-info.java
@@ -0,0 +1,28 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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.
+*/
+
+/**
+ * Optiq query provider that reads from CSV (comma-separated value) files.
+ *
+ * <p>An optiq schema maps onto a directory, and each CSV file in that
+ * directory appears as a table. Full SQL operations are available on
+ * those tables.</p>
+ */
+package net.hydromatic.optiq.impl.csv;
+
+// End package-info.java
diff --git a/src/test/java/net/hydromatic/optiq/test/CsvTest.java b/src/test/java/net/hydromatic/optiq/test/CsvTest.java
new file mode 100644
index 0000000..7cbd033
--- /dev/null
+++ b/src/test/java/net/hydromatic/optiq/test/CsvTest.java
@@ -0,0 +1,110 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde 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 net.hydromatic.optiq.test;
+
+import junit.framework.TestCase;
+
+import java.io.PrintStream;
+import java.sql.*;
+import java.util.Properties;
+
+/**
+ * Unit test of the Optiq adapter for CSV.
+ */
+public class CsvTest extends TestCase {
+ private void close(Connection connection, Statement statement) {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException e) {
+ // ignore
+ }
+ }
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Tests the vanity driver.
+ */
+ public void _testVanityDriver() throws SQLException {
+ Properties info = new Properties();
+ Connection connection =
+ DriverManager.getConnection("jdbc:csv:", info);
+ connection.close();
+ }
+
+ /**
+ * Tests the vanity driver with properties in the URL.
+ */
+ public void _testVanityDriverArgsInUrl() throws SQLException {
+ Connection connection =
+ DriverManager.getConnection(
+ "jdbc:csv:"
+ + "directory='foo'");
+ connection.close();
+ }
+
+ /**
+ * Reads from a table.
+ */
+ public void testSelect() throws SQLException {
+ checkSql("select * from EMPS");
+ }
+
+ private void checkSql(String sql) throws SQLException {
+ Connection connection = null;
+ Statement statement = null;
+ try {
+ Properties info = new Properties();
+ info.put("model", "target/test-classes/model.json");
+ connection = DriverManager.getConnection("jdbc:optiq:", info);
+ statement = connection.createStatement();
+ final ResultSet resultSet =
+ statement.executeQuery(
+ sql);
+ output(resultSet, System.out);
+ } finally {
+ close(connection, statement);
+ }
+ }
+
+ private void output(ResultSet resultSet, PrintStream out)
+ throws SQLException {
+ final ResultSetMetaData metaData = resultSet.getMetaData();
+ final int columnCount = metaData.getColumnCount();
+ while (resultSet.next()) {
+ for (int i = 1;; i++) {
+ out.print(resultSet.getString(i));
+ if (i < columnCount) {
+ out.print(", ");
+ } else {
+ out.println();
+ break;
+ }
+ }
+ }
+ }
+}
+
+// End CsvTest.java
diff --git a/src/test/resources/model.json b/src/test/resources/model.json
new file mode 100644
index 0000000..d8556c6
--- /dev/null
+++ b/src/test/resources/model.json
@@ -0,0 +1,14 @@
+{
+ version: '1.0',
+ defaultSchema: 'SALES',
+ schemas: [
+ {
+ name: 'SALES',
+ type: 'custom',
+ factory: 'net.hydromatic.optiq.impl.csv.CsvSchemaFactory',
+ operand: {
+ directory: 'target/test-classes/sales'
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/sales/DEPTS.csv b/src/test/resources/sales/DEPTS.csv
new file mode 100644
index 0000000..b240228
--- /dev/null
+++ b/src/test/resources/sales/DEPTS.csv
@@ -0,0 +1,4 @@
+DEPTNO:int,NAME:string
+10,"Sales"
+20,"Marketing"
+30,"Accounts"
\ No newline at end of file
diff --git a/src/test/resources/sales/EMPS.csv b/src/test/resources/sales/EMPS.csv
new file mode 100644
index 0000000..c5951fb
--- /dev/null
+++ b/src/test/resources/sales/EMPS.csv
@@ -0,0 +1,6 @@
+EMPNO:int,NAME:string,DEPTNO:Integer,GENDER:string,CITY:string,EMPID:int,AGE:int,SLACKER:boolean,MANAGER:boolean,JOINEDAT:date
+100,"Fred",10,,,30,25,true,false,"1996-08-03"
+110,"Eric",20,"M","San Francisco",3,80,,false,"2001-01-01"
+110,"John",40,"M","Vancouver",2,,false,true,"2002-05-03"
+120,"Wilma",20,"F",,1,5,,true,"2005-09-07"
+130,"Alice",40,"F","Vancouver",2,,false,true,"2007-01-01"