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"