Repository: mkitzan/constexpr-sql Branch: master Commit: ba98a31224ce Files: 59 Total size: 234.1 KB Directory structure: gitextract_sm4g9zum/ ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── example.cpp ├── generator.py ├── include/ │ ├── cexpr/ │ │ └── string.hpp │ ├── ra/ │ │ ├── cross.hpp │ │ ├── join.hpp │ │ ├── natural.hpp │ │ ├── operation.hpp │ │ ├── projection.hpp │ │ ├── relation.hpp │ │ ├── rename.hpp │ │ └── selection.hpp │ └── sql/ │ ├── column.hpp │ ├── index.hpp │ ├── predicate.hpp │ ├── query.hpp │ ├── row.hpp │ ├── schema.hpp │ └── tokens.hpp ├── single-header/ │ └── sql.hpp └── tests/ ├── data/ │ ├── authored.tsv │ ├── books.tsv │ ├── collected.tsv │ └── stories.tsv ├── data.hpp ├── perf/ │ ├── data/ │ │ ├── lib-query0 │ │ ├── lib-query1 │ │ ├── lib-query2 │ │ ├── lib-query3 │ │ ├── lib-query4 │ │ ├── lib-query5 │ │ ├── query0 │ │ ├── query1 │ │ ├── query2 │ │ ├── query3 │ │ ├── query4 │ │ └── query5 │ ├── queries/ │ │ ├── lib-query0.cpp │ │ ├── lib-query1.cpp │ │ ├── lib-query2.cpp │ │ ├── lib-query3.cpp │ │ ├── lib-query4.cpp │ │ ├── lib-query5.cpp │ │ ├── query0.cpp │ │ ├── query1.cpp │ │ ├── query2.cpp │ │ ├── query3.cpp │ │ ├── query4.cpp │ │ └── query5.cpp │ ├── runner.sh │ └── scripts/ │ └── runner.py ├── runner.sh └── scripts/ ├── compose.py ├── generate.py ├── runner.py └── select.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto ================================================ FILE: .gitignore ================================================ tests/*.txt tests/test.cpp tests/test tests/queries/* .vscode/* example .DS_STORE ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 Michael Kitzan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Constexpr SQL A light weight single header alternative to DBMS This library was developed during my honors project at the [University of Victoria](https://www.uvic.ca/engineering/computerscience/index.php) under the supervision of [Bill Bird](https://github.com/billbird). The original development occurred in this [Metaprogramming Optimization](https://github.com/mkitzan/metaprogramming-optimization) repository, but was moved into a new, dedicated, home repository. The project was inspired and influenced by [Hana Dusíková](https://github.com/hanickadot)'s great [Compile Time Regular Expressions](https://github.com/hanickadot/compile-time-regular-expressions) library (CTRE). Maintenance may slow in the near future due to my employer's open source software policy. I will be looking into getting approval to continue maintaining this project. ## Library Features and Compiler Support Supported features: - SQL query syntax for data processing - `SELECT` data querying - `AS` column renaming - `CROSS JOIN` (note: all column names of each relation must be unique) - `NATURAL JOIN` (note: natural join will attempt to join on the first column of each relation) - `WHERE` clause predicates on numeric and `std::string` types - Wildcard selection with `*` - Nested queries - Uppercase and lowercase SQL keywords - Modern `!=` and legacy `<>` not-equal operator - Standard SQL operator precedence in `WHERE` clause - Schemas support all default constructable types - Indexes for schemas (used for sorting the data) - Range loop and structured binding declaration support - [Loading data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) from files (no header row) - [Storing data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L210) from `sql::schema` and `sql::query` objects to files - Element querying from `sql::row` objects with [`sql::get<"column-name">`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) Unsupported features (future work): - `INNER JOIN`, `OUTER JOIN`, `LEFT JOIN`, and `RIGHT JOIN` - `GROUP BY`, `HAVING`, and `ORDER BY` (using indexes can simulate some of these features) - `IN` operation within `WHERE` clause - Template argument error detection As of April 2020, Constexpr SQL is only supported by **`GCC 9.0+`**. The compiler support is constrained because of the widespread use of the new `C++20` feature ["Class Types in Non-Type Template Parameters"](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf) (proposal `P0732R2`) which is only implemented by `GCC 9.0+`. Library users specify SQL queries and column labels with string literals which are converted into `constexpr` objects all of which relies on functionality from `P0732R2`. ## Example The following example shows usage of all class templates a user is expected to define to use the library. ```c++ #include #include #include "sql.hpp" using books = sql::schema< "books", sql::index<"title">, sql::column<"title", std::string>, sql::column<"genre", std::string>, sql::column<"year", unsigned>, sql::column<"pages", unsigned> >; using authored = sql::schema< "authored", sql::index<>, sql::column<"title", std::string>, sql::column<"name", std::string> >; using query = sql::query< "SELECT title AS book, name AS author, year, pages " "FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") " "WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"", books, authored >; int main() { authored a{ sql::load("tests/data/authored.tsv", '\t') }; books b{ sql::load("tests/data/books.tsv", '\t') }; for (query q{ b, a }; auto const& [book, author, year, pages] : q) { std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n'; } return 0; } ``` [`sql::schema`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp) defines a relation used in a query. [`sql::index`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp) defines how an `sql::schema` sorts its data (unsorted if unspecified). [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) types are used to define the rows in an `sql::schema`. [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) wraps a query statement and the `sql::schema` types the query will operate on. [`sql::load`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) can be used to load data from a file into an `sql::schema`. The example is from [`example.cpp`](https://github.com/mkitzan/constexpr-sql/blob/master/example.cpp) in the root of the repository, and can be compiled and executed with the following command: ```shell g++ -std=c++2a -pedantic -Wall -Wextra -Werror -O3 -Isingle-header/ -o example example.cpp && ./example ``` It is strongly recommended to compile with optimizations enabled, otherwise expect template bloat. Use of multiple objects of the same `sql::query` type is considered **undefined behavior** (due to issues involving static members). Instantiating `sql::query` objects should be performed within a guarded scope, like in the example. However, there are no use restrictions to `sql::schema` types. `sql::schema` types may be used multiple times within a single query or in many queries at once. There are more examples and information in [`presentation.pdf`](https://github.com/mkitzan/constexpr-sql/blob/master/presentation.pdf) at the root of the repository. ## Correctness and Performance Testing The library has a significant testing system which is composed of two script pipelines. All tests use the data from another project of mine called [`Terminus`](https://github.com/mkitzan/terminus) which is a library database shell. The correctness testing pipeline generates nearly 1.5 million test queries, then Constexpr SQL's output is compared against the output of `SQLite3` performing the same queries. The performance testing pipeline executes six different SQL queries implemented using Constexpr SQL and hand coded SQL. The queries are executed over 65 thousand times (256 for `CROSS JOIN` due to computational complexity), and the execution timing is captured using the Linux `time` tool. The [`runner.sh`](https://github.com/mkitzan/constexpr-sql/blob/master/tests/runner.sh) script in the `tests` directory will execute correctness testing, and the [`runner.sh`](https://github.com/mkitzan/constexpr-sql/tree/master/tests/perf/runner.sh) script in `tests/perf` will execute performance testing. ## Important Class Templates and Implementation Details The following sections provide a high-level description about how the library is implemented. Hopefully, the sections will provide useful code and document references to others looking to write similar libraries. ### Class Template: `sql::schema` The `sql::schema` class template represents relational schemas and, when instantiated, SQL tables. The class template is parameterized on three template parameters: `Name`, `Index`, and `Col` template parameter pack. `Name` defines the SQL table name which is matched against table names in a query's `FROM` statement. The `Index` template argument is used to support `GROUP BY` statements by using [**SFINAE**](https://en.cppreference.com/w/cpp/language/sfinae) to select the [underlying column data container](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L25) (`std::vector` or `std::multiset`). The `Index` template argument, when fully specified, provides the [comparator functor](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp#L15) used by the `std::multiset` container. The `Cols` template parameter pack is expanded into the `sql::row` type for the schema. `sql::schema` objects support [**structured binding declarations**](https://en.cppreference.com/w/cpp/language/structured_binding) which is facilitated partly through the `sql::schema` API and partly through [`std` namespace injections from `sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L131) helping to satisfy the [argument dependant lookup](https://en.cppreference.com/w/cpp/language/adl) of the [`get` function](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L97). Reference the example [earlier](https://github.com/mkitzan/constexpr-sql#example) for proper usage of `sql::schema`. Notice in the example the string literal as a template argument. String literals are lvalue reference types which are passed as `const` pointers. Normally, pointers can not be used as template arguments. With the new C++20 feature mentioned [earlier](https://github.com/mkitzan/constexpr-sql#library-features-and-compiler-support), a [`cexpr::string`](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp) constructor template can be [deduced](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) to turn the string literal into a `constexpr` object. The deduction is enabled through [`cexpr::string`'s class template argument deduction guide](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp#L144) which provides a mapping of constructor arguments to template parameters. ### Class Template: `sql::query` The [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) class template is the user interface to the SQL query parser. The class is templated on a `cexpr::string` object (the SQL query) and a template parameter pack of `sql::schema` types. At compile time, the SQL query string is parsed into the relational algebra expression tree representing the query's computation. The constructor to a fully specified `sql::query` class takes a variadic pack of `sql::schema` objects which it uses to seed the relational algebra expression tree with iterators to data. The `sql::query` object can then be used in a range loop with structured binding declarations like in the example. The relational algebra expression tree uses static members to hold data, so only one object of a single fully specified `sql::query` class can exist at once in the program. To ensure this the object should be constructed within a guarded scope like in the example. It's worth noting that even though this class template's source file is the largest among the code base, nearly all of it is only live during compilation to parse the SQL query. In fact, the [runtime interface](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L666) is deliberately insubstantial, merely providing an wrapper to support range loops and structured binding declarations. In compliance with range loop syntax, `sql::query` has an associated iterator class [`sql::query_iterator`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L189). `sql::query_iterator` wraps the type representing the relational algebra expression and handles all of the idiosyncrasies of its usage in favor of the familiar [`forward iterator`](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) interface. When an [`sql::query_iterator` is dereferenced](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L211), it returns a constant reference to an `sql::row` object representing the current row of output from the query stream. ### Class Template: `sql::row` The [`sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp) class template is a template recursive linked-list (similar to [`std::tuple`](https://en.cppreference.com/w/cpp/utility/tuple)). A template recursive linked-list is a template metaprogramming pattern which expresses a type analogous to a traditional linked-list. `sql::row` implements this pattern with two template parameters `Col` and `Next`. `Col` represents the [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) which the node in list holds a data element from. `Next` represents the type of the next node in the list, which is either another `sql::row` type or [`sql::void_row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L12). Because the next node is expressed as a type the template linked-list does not incur the overhead of holding a next pointer nor the run time cost of dereferencing a pointer to iterate (also makes better use of the cache). A quirk to this pattern is that the node data type need not be homogenous across the list, instead the list may be composed of heterogenous data types. Also, template linked-list access is computed at compile time, so the run time cost is constant. The example does not demonstrate the [`sql::get`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) helper function. This helper function allows the user to query a specific element from an `sql::row` object by column name. Additionally, `sql::row` has [**ML**-like](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) functions for getting the `head` and `tail` of the object. ### Relational Algebra Expression Nodes At the moment, [`ra::projection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/projection.hpp), [`ra::rename`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/rename.hpp), [`ra::cross`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/cross.hpp), [`ra::natural`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/natural.hpp), [`ra::selection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/selection.hpp), and [`ra::relation`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/relation.hpp) are the only relational algebra nodes implemented. `ra::projection` and `ra::rename` are unary operators which take a single `sql::row` from their `Input` relational algebra operator and fold their operation over the row before propagating the transformed row to their `Output`. The `fold` is implemented as a template recursive function. `ra::cross` outputs the cross product of two relations. `ra::natural` implements a natural join between two relations using a hash table buffer of the right relation for performance. `ra::selection` uses a predicate function constructed from a `WHERE` clause to filter rows in a query. `ra::relation` is the only terminal node in the expression tree which is used for retrieving the next input in the stream. These operators are composable types and are used to serialize the relational algebra expression tree. Individual objects of each type are not instantiated to compose the expression tree. Instead to ensure the expression tree is a zero overhead abstraction, the types implement a `static` member function `next` used to request data from its input type. The actual `constexpr` template recursive recursive descent SQL parser will serialize these individual nodes together into the appropriate expression tree. ### Constexpr Parsing As a proof of concept for `constexpr` parsing, two math expression parsers were implemented in old repository: [`cexpr::prefix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp) and [`cexpr::infix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/infix.hpp). `cexpr::prefix` demonstrates the fundamental method of `constexpr` parsing an expression tree into a class template. `cexpr::infix` extends this to perform `constepxr` recursive descent parsing. `cexpr::infix` and the SQL query parser are a whole order of magnitude more complex, because there's recursive function template instantiations to many different function templates. The explanation of `constexpr` parsing is illustrated through `cexpr::prefix` for simplicity. The expression tree created while parsing is a template recursive tree which shares similar properties to the template linked-list (discussed [earlier](https://github.com/mkitzan/constexpr-sql#class-template-sqlrow)). A notable benefit to this data structure is that because the tree is composed of types rather than data values, the tree can be used to express computation models (expression trees) rather than just a tree based container. Fundamentally, the parsing is accomplished by calling a template recursive `static constexpr` parsing function member parameterized on the token position which the parser's "cursor" is standing on ([`Pos`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L39) template parameter). At each "cursor" position, the function uses the token to decide the how to proceed. If the token indicates the start of an operation, the parser recurses the immediate left subexpression ("cursor" + 1). On return, the left subexpression will report the depth in the token stream it recursed at which point the right subexpression will pick up at this position. This control flow is expressed in [this line](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L47) of [`cexpr::prefix::parse`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L40). Once both left and right subexpressions are parsed, the new node's type is formed ([`decltype`](https://en.cppreference.com/w/cpp/language/decltype) left and right subexpressions) which is then propagated to the caller. Otherwise, if the token indicates a terminal, then an appropriate terminal node is constructed. It is necessary that the "cursor" position is unique across template instantiations, otherwise template memoization will lead to "infinite" recursion. The few ancillary class templates used to support this parsing and the math node `struct` templates can be found in the [`templ` namespace](https://github.com/mkitzan/metaprogramming-optimization/tree/master/include/templ) of the old repository. There is also a [driver program](https://github.com/mkitzan/metaprogramming-optimization/blob/master/resources/parser/equation.cpp) using the parsers in the old repository. In the Constexpr SQL parser, all of the entities in the `templ` namespace were replaced for more template metaprogramming idiomatic structures. ================================================ FILE: example.cpp ================================================ #include #include #include "sql.hpp" using books = sql::schema< "books", sql::index<"title">, sql::column<"title", std::string>, sql::column<"genre", std::string>, sql::column<"year", unsigned>, sql::column<"pages", unsigned> >; using authored = sql::schema< "authored", sql::index<>, sql::column<"title", std::string>, sql::column<"name", std::string> >; using query = sql::query< "SELECT title AS book, name AS author, year, pages " "FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") " "WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"", books, authored >; int main() { authored a{ sql::load("tests/data/authored.tsv", '\t') }; books b{ sql::load("tests/data/books.tsv", '\t') }; for (query q{ b, a }; auto const& [book, author, year, pages] : q) { std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n'; } return 0; } ================================================ FILE: generator.py ================================================ import os def include(header, incs, root, included): file = open("include/" + root, "r") for line in file: if line == "#pragma once\n" or line == "\n": pass elif line[:10] == "#include \"": if not line in included: included += [line] include(header, incs, line[10:-2], included) elif line[:10] == "#include <": incs += [line] else: header.write(line) break for line in file: header.write(line) header.write("\n") return included, incs def main(): header = open("temp", "w") included, incs = include(header, [], "sql/schema.hpp", []) included, incs = include(header, incs, "sql/query.hpp", included) header.close() header = open("single-header/sql.hpp", "w") header.write("#pragma once\n\n") for line in sorted(set(incs)): header.write(line) header.write("\n") for line in open("temp"): header.write(line) os.remove("temp") if __name__ == "__main__": main() ================================================ FILE: include/cexpr/string.hpp ================================================ #pragma once #include #include #include namespace cexpr { template class string { public: using char_type = Char; constexpr string() noexcept : size_{ 0 }, string_{ 0 } {} constexpr string(const Char(&s)[N]) noexcept : string{} { for(; s[size_]; ++size_) { string_[size_] = s[size_]; } } constexpr string(cexpr::string const& s) noexcept : string{} { for (; s[size_]; ++size_) { string_[size_] = s[size_]; } } constexpr string(std::basic_string_view const& s) noexcept : string{} { if (s.length() < N) { for (; size_ < s.length(); ++size_) { string_[size_] = s[size_]; } } } constexpr void fill(const Char* begin, const Char* end) noexcept { fill_from(begin, end, begin()); } constexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept { if (end - begin < N) { for (auto curr{ start }; begin != end; ++begin, ++curr) { *curr = *begin; } } } inline constexpr std::size_t capacity() const noexcept { return N - 1; } inline constexpr std::size_t size() const noexcept { return size_; } inline constexpr Char* begin() noexcept { return string_; } inline constexpr const Char* cbegin() const noexcept { return string_; } inline constexpr Char* end() noexcept { return &string_[size_]; } inline constexpr const Char* cend() const noexcept { return &string_[size_]; } inline constexpr Char& operator[](std::size_t i) { return string_[i]; } inline constexpr Char const& operator[](std::size_t i) const { return string_[i]; } template constexpr bool operator==(string const& other) const noexcept { if constexpr (N != OtherN) { return false; } std::size_t i{}; for (; i < N && string_[i] == other[i]; ++i); return i == N; } template constexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept { if constexpr (N != OtherN) { return false; } std::size_t i{}; for (; i < N && string_[i] == other[i]; ++i); return i == N; } template inline bool operator==(std::basic_string const& other) const noexcept { return other == string_; } template inline bool operator!=(std::basic_string const& other) const noexcept { return !(other == string_); } private: std::size_t size_; Char string_[N]; }; template string(const Char[N]) -> string; template inline bool operator==(std::basic_string const& str, string const& cstr) noexcept { return cstr == str; } template inline bool operator!=(std::basic_string const& str, string const& cstr) noexcept { return cstr != str; } } // namespace cexpr ================================================ FILE: include/ra/cross.hpp ================================================ #pragma once #include "ra/join.hpp" #include "ra/relation.hpp" namespace ra { template class cross : public ra::join { using join_type = ra::join; public: using output_type = join_type::output_type; static auto&& next() { try { copy(join_type::output_row, RightInput::next()); } catch(ra::data_end const& e) { copy(join_type::output_row, LeftInput::next()); RightInput::reset(); copy(join_type::output_row, RightInput::next()); } return std::move(join_type::output_row); } }; } // namespace ra ================================================ FILE: include/ra/join.hpp ================================================ #pragma once #include #include "ra/operation.hpp" #include "sql/row.hpp" namespace ra { namespace { template constexpr auto recr_merge() { if constexpr (std::is_same_v) { return Right{}; } else { using next = decltype(recr_merge()); return sql::row{}; } } template inline constexpr auto merge() { if constexpr (Left::column::name == Right::column::name) { return recr_merge(); } else { return recr_merge(); } } template constexpr void recr_copy(Dest& dest, Row const& src) { if constexpr (std::is_same_v) { return; } else { dest.head() = src.head(); recr_copy(dest.tail(), src.tail()); } } template inline constexpr void copy(Dest& dest, Row const& src) { if constexpr (Dest::column::name == Row::column::name) { recr_copy(dest, src); } else { copy(dest.tail(), src); } } } // namespace template class join : public ra::binary { using binary_type = ra::binary; using left_type = typename binary_type::left_type; using right_type = typename binary_type::right_type; public: using output_type = decltype(merge()); template static inline void seed(Inputs const&... rs) { binary_type::seed(rs...); copy(output_row, LeftInput::next()); } static inline void reset() { binary_type::reset(); copy(output_row, LeftInput::next()); } static output_type output_row; }; template typename join::output_type join::output_row{}; } // namespace ra ================================================ FILE: include/ra/natural.hpp ================================================ #pragma once #include #include #include #include "ra/join.hpp" #include "ra/relation.hpp" namespace ra { template class natural : public ra::join { using join_type = ra::join; using key_type = std::remove_cvref_t; using value_type = std::vector>; using map_type = std::unordered_map; public: using output_type = join_type::output_type; template static void seed(Inputs const&... rs) { join_type::seed(rs...); if (row_cache.empty()) { try { for (;;) { auto const& row{ RightInput::next() }; row_cache[row.head()].push_back(row.tail()); } } catch(ra::data_end const& e) { RightInput::reset(); } } auto const& active{ row_cache[join_type::output_row.head()] }; curr = active.cbegin(); end = active.cend(); } static auto&& next() { while (curr == end) { copy(join_type::output_row, LeftInput::next()); auto const& active{ row_cache[join_type::output_row.head()] }; curr = active.cbegin(); end = active.cend(); } copy(join_type::output_row, *curr++); return std::move(join_type::output_row); } private: static map_type row_cache; static value_type::const_iterator curr; static value_type::const_iterator end; }; template typename natural::map_type natural::row_cache{}; template typename natural::value_type::const_iterator natural::curr; template typename natural::value_type::const_iterator natural::end; } // namespace ra ================================================ FILE: include/ra/operation.hpp ================================================ #pragma once #include namespace ra { template class unary { public: using input_type = std::remove_cvref_t; template static inline void seed(Inputs const&... rs) { Input::seed(rs...); } static inline void reset() { Input::reset(); } }; template class binary { public: using left_type = std::remove_cvref_t; using right_type = std::remove_cvref_t; template static inline void seed(Inputs const&... rs) { LeftInput::seed(rs...); RightInput::seed(rs...); } static inline void reset() { LeftInput::reset(); RightInput::reset(); } }; } // namespace ra ================================================ FILE: include/ra/projection.hpp ================================================ #pragma once #include "ra/operation.hpp" #include "sql/row.hpp" namespace ra { template class projection : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = Output; static auto&& next() { fold(output_row, Input::next()); return std::move(output_row); } private: template static inline constexpr void fold(Dest& dest, input_type const& src) { if constexpr (Dest::depth == 0) { return; } else { dest.head() = sql::get(src); fold(dest.tail(), src); } } static output_type output_row; }; template typename projection::output_type projection::output_row{}; } // namespace ra ================================================ FILE: include/ra/relation.hpp ================================================ #pragma once #include #include namespace ra { struct data_end : std::exception {}; // Id template parameter allows unique ra::relation types to be instantiated from // a single sql::schema type (for queries referencing a schema multiple times). template class relation { public: using output_type = Schema::row_type&; static auto& next() { if (curr != end) { return *curr++; } else { throw ra::data_end{}; } } template static void seed(Input const& r, Inputs const&... rs) noexcept { if constexpr (std::is_same_v) { curr = r.begin(); begin = r.begin(); end = r.end(); } else { seed(rs...); } } static inline void reset() noexcept { curr = begin; } private: static Schema::const_iterator curr; static Schema::const_iterator begin; static Schema::const_iterator end; }; template Schema::const_iterator relation::curr{}; template Schema::const_iterator relation::begin{}; template Schema::const_iterator relation::end{}; } // namespace ra ================================================ FILE: include/ra/rename.hpp ================================================ #pragma once #include "ra/operation.hpp" #include "sql/row.hpp" namespace ra { template class rename : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = Output; static auto&& next() { fold(output_row, Input::next()); return std::move(output_row); } private: template static inline constexpr void fold(Dest& dest, Src const& src) { if constexpr (Dest::depth == 0) { return; } else { dest.head() = src.head(); fold(dest.tail(), src.tail()); } } static output_type output_row; }; template typename rename::output_type rename::output_row{}; } // namespace ra ================================================ FILE: include/ra/selection.hpp ================================================ #pragma once #include "ra/operation.hpp" namespace ra { template class selection : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = input_type; static auto&& next() { output_row = Input::next(); while(!Predicate::eval(output_row)) { output_row = Input::next(); } return std::move(output_row); } private: static output_type output_row; }; template typename selection::output_type selection::output_row{}; } // namespace ra ================================================ FILE: include/sql/column.hpp ================================================ #pragma once #include "cexpr/string.hpp" namespace sql { template struct column { static constexpr auto name{ Name }; using type = Type; }; } // namespace sql ================================================ FILE: include/sql/index.hpp ================================================ #pragma once #include #include "cexpr/string.hpp" #include "sql/row.hpp" namespace sql { template struct index { template struct comparator { bool operator()(Row const& left, Row const& right) const noexcept { return compare(left, right); } private: template bool compare(Row const& left, Row const& right) const noexcept { auto const& l{ sql::get(left) }; auto const& r{ sql::get(right) }; if constexpr (sizeof...(Cols) != 0) { if (l == r) { return compare(left, right); } } return l < r; } }; }; } // namespace sql ================================================ FILE: include/sql/predicate.hpp ================================================ #pragma once #include #include "cexpr/string.hpp" namespace sql { namespace { // shim to allow all value types like double or float to be used as non-type template parameters. template struct value { constexpr value(Type v) : val{ v } {} Type val; }; } // namespace template struct operation { static constexpr bool eval(Row const& row) noexcept { if constexpr (Op == "=") { return Left::eval(row) == Right::eval(row); } else if constexpr (Op == ">") { return Left::eval(row) > Right::eval(row); } else if constexpr(Op == "<") { return Left::eval(row) < Right::eval(row); } else if constexpr(Op == ">=") { return Left::eval(row) >= Right::eval(row); } else if constexpr(Op == "<=") { return Left::eval(row) <= Right::eval(row); } else if constexpr(Op == "!=" || Op == "<>") { return Left::eval(row) != Right::eval(row); } else if constexpr(Op == "AND") { return Left::eval(row) && Right::eval(row); } else if constexpr(Op == "OR") { return Left::eval(row) || Right::eval(row); } else if constexpr(Op == "NOT") { return !Left::eval(row); } } }; template struct variable { static constexpr auto eval(Row const& row) noexcept { return sql::get(row); } }; template struct constant { static constexpr auto eval([[maybe_unused]] Row const& row) noexcept { return Const.val; } }; } // namespace sql ================================================ FILE: include/sql/query.hpp ================================================ #pragma once #include #include #include #include #include "cexpr/string.hpp" #include "ra/cross.hpp" #include "ra/join.hpp" #include "ra/natural.hpp" #include "ra/projection.hpp" #include "ra/relation.hpp" #include "ra/rename.hpp" #include "ra/selection.hpp" #include "sql/column.hpp" #include "sql/tokens.hpp" #include "sql/predicate.hpp" #include "sql/row.hpp" namespace sql { // anonymous namespace to hold helper data structures and functions namespace { template struct context { using node = Node; static constexpr std::size_t pos = Pos; }; template struct colinfo { using type = Type; static constexpr std::size_t name = Name; static constexpr std::size_t next = Next; }; template constexpr bool exists() noexcept { if constexpr (std::is_same_v) { return false; } else { if constexpr (Row::column::name == Name) { return true; } else { return exists(); } } } template constexpr value convert(cexpr::string const& str) noexcept { auto curr{ str.cbegin() }, end{ str.cend() }; constexpr Char dot{ '.' }, zro{ '0' }, min{ '-' }; Type acc{}, sign{ 1 }, scalar{ 10 }; if (*curr == min) { sign = -1; ++curr; } while (curr != end && *curr != dot) { acc = (acc * scalar) + (*curr - zro); ++curr; } if (curr != end && *curr == dot) { scalar = 1; ++curr; while(curr != end) { acc += (*curr - zro) * (scalar /= Type{ 10 }); ++curr; } } return value{ acc * sign }; } inline constexpr bool isquote(std::string_view const& tv) noexcept { return tv == "\"" || tv == "'"; } inline constexpr bool isor(std::string_view const& tv) noexcept { return tv == "OR" || tv == "or"; } inline constexpr bool isand(std::string_view const& tv) noexcept { return tv == "AND" || tv == "and"; } inline constexpr bool isnot(std::string_view const& tv) noexcept { return tv == "NOT" || tv == "not"; } inline constexpr bool isnatural(std::string_view const& tv) noexcept { return tv == "NATURAL" || tv == "natural"; } inline constexpr bool isjoin(std::string_view const& tv) noexcept { return tv == "JOIN" || tv == "join"; } inline constexpr bool iswhere(std::string_view const& tv) noexcept { return tv == "WHERE" || tv == "where"; } inline constexpr bool isfrom(std::string_view const& tv) noexcept { return tv == "FROM" || tv == "from"; } inline constexpr bool isas(std::string_view const& tv) noexcept { return tv == "AS" || tv == "as"; } inline constexpr bool isselect(std::string_view const& tv) noexcept { return tv == "SELECT" || tv == "select"; } inline constexpr bool iscomma(std::string_view const& tv) noexcept { return tv == ","; } constexpr bool isintegral(std::string_view const& tv) noexcept { bool result{ false }; for (auto c : tv) { result |= (c == '.'); } return !result; } constexpr bool isdigit(char c) noexcept { return (c >= '0' && c <= '9') || c == '-' || c == '.'; } constexpr bool iscomp(char c) noexcept { return c == '=' || c == '!' || c == '<' || c == '>'; } constexpr bool iscolumn(std::string_view const& tv) noexcept { return !iscomma(tv) && !isas(tv) && !isfrom(tv); } constexpr bool isseparator(std::string_view const& tv) noexcept { return iscomma(tv) || isfrom(tv); } } // namespace // structured binding compliant iterator for query objects template class query_iterator { public: using row_type = std::remove_cvref_t; // seeds row datamember for first dereference query_iterator(bool end) : end_{ end }, row_{} { operator++(); } inline bool operator==(query_iterator const& it) const noexcept { return end_ == it.end_; } inline bool operator!=(query_iterator const& it) const noexcept { return !(*this == it); } inline row_type const& operator*() const noexcept { return row_; } query_iterator& operator++() { if (!end_) { try { row_ = Expr::next(); } catch (ra::data_end const& e) { end_ = true; } } return *this; } private: bool end_{}; row_type row_{}; }; template class query { private: // where predicate terminal parsing template static constexpr auto parse_terms() { if constexpr (tokens_[Pos] == "(") { constexpr auto next{ parse_or() }; using node = typename decltype(next)::node; static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); return context{}; } else if constexpr (isquote(tokens_[Pos])) { constexpr cexpr::string name{ tokens_[Pos + 1] }; using str = decltype(name); using node = sql::constant{ name }, Row>; static_assert(isquote(tokens_[Pos + 2]), "No closing quote found."); return context{}; } else if constexpr (isdigit(tokens_[Pos][0])) { constexpr cexpr::string name{ tokens_[Pos] }; using val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{}); using node = sql::constant(name), Row>; return context{}; } else { constexpr cexpr::string name{ tokens_[Pos] }; using node = sql::variable; return context{}; } } // parses a single compare operation template static constexpr auto recurse_comparison() { if constexpr (!iscomp(tokens_[Left::pos][0])) { return Left{}; } else { constexpr auto next{ parse_terms() }; constexpr cexpr::string name{ tokens_[Left::pos] }; using ranode = typename decltype(next)::node; using node = sql::operation; return context{}; } } // descend further and attempt to parse a compare operation template static constexpr auto parse_comparison() { using left = decltype(parse_terms()); return recurse_comparison(); } // attempt to parse a negation operation then descend further template static constexpr auto parse_negation() { if constexpr (isnot(tokens_[Pos])) { constexpr auto next{ parse_comparison() }; using ranode = typename decltype(next)::node; using node = sql::operation<"NOT", Row, ranode>; return context{}; } else { return parse_comparison(); } } // recursively parse chained AND operations template static constexpr auto recurse_and() { if constexpr (!isand(tokens_[Left::pos])) { return Left{}; } else { constexpr auto next{ parse_negation() }; using ranode = typename decltype(next)::node; using node = sql::operation<"AND", Row, typename Left::node, ranode>; return recurse_and, Row>(); } } // descend further then attempt to parse AND operations template static constexpr auto parse_and() { using left = decltype(parse_negation()); return recurse_and(); } // recursively parse chained OR operations template static constexpr auto recurse_or() { if constexpr (!isor(tokens_[Left::pos])) { return Left{}; } else { constexpr auto next{ parse_and() }; using ranode = typename decltype(next)::node; using node = sql::operation<"OR", Row, typename Left::node, ranode>; return recurse_or, Row>(); } } // descend further then attempt to parse OR operations template static constexpr auto parse_or() { using left = decltype(parse_and()); return recurse_or(); } // find correct schema for terminal relation template static constexpr auto recurse_schemas() { if constexpr (Name == Schema::name) { return ra::relation{}; } else { static_assert(sizeof...(Others) != 0, "Schema name used in JOIN was not provided."); return recurse_schemas(); } } // wrapper function to determine terminal relation template static constexpr auto parse_schema() { if constexpr (tokens_[Pos] == "(") { constexpr auto next{ parse_root() }; using node = typename decltype(next)::node; static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); return context{}; } else { constexpr cexpr::string name{ tokens_[Pos] }; using node = decltype(recurse_schemas()); return context{}; } } // stub which will choose the specific join RA node template static constexpr auto choose_join() { if constexpr (isnatural(tokens_[Pos])) { return ra::natural{}; } else { return ra::cross{}; } } // parses join colinfo if a join is present else returns the single relation terminal template static constexpr auto parse_join() { constexpr auto lnext{ parse_schema() }; using lnode = typename decltype(lnext)::node; if constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1])) { constexpr auto rnext{ parse_schema() }; using rnode = typename decltype(rnext)::node; using join = decltype(choose_join()); return context{}; } else { return context{}; } } // starting point to parse everything after the from keyword template static constexpr auto parse_from() { static_assert(isfrom(tokens_[Pos]), "Expected 'FROM' token not found."); constexpr auto next{ parse_join() }; using node = typename decltype(next)::node; if constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos])) { using output = std::remove_cvref_t; constexpr auto predicate{ parse_or() }; using pnext = typename decltype(predicate)::node; using snode = ra::selection; return context{}; } else { return context{}; } } // recursively searches all schemas for the a matching column template static constexpr auto recurse_types() { if constexpr (sql::exists()) { return decltype(sql::get(typename Schema::row_type{})){}; } else { static_assert(sizeof...(Others) != 0, "Column name was not present in any schema."); return recurse_types(); } } // wrapper to determine the type for the the column template static constexpr auto column_type() { constexpr cexpr::string name{ tokens_[Pos] }; return recurse_types(); } // asserts token is column separator, and if comma returns one past the comma else start position template static constexpr std::size_t next_column() { static_assert(isseparator(tokens_[Pos]), "Expected ',' or 'FROM' token following column."); if constexpr (iscomma(tokens_[Pos])) { return Pos + 1; } else { return Pos; } } template static constexpr auto parse_colinfo() { static_assert(iscolumn(tokens_[Pos]), "Invalid token starting column delcaration."); constexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) }; using col = decltype(column_type()); if constexpr (Rename && rename) { constexpr auto next{ next_column() }; return colinfo{}; } else if constexpr (rename) { constexpr auto next{ next_column() }; return colinfo{}; } else { constexpr auto next{ next_column() }; return colinfo{}; } } // recursively parse all columns projected/renamed in the query template static constexpr auto recurse_columns() { if constexpr (isfrom(tokens_[Pos])) { return context{}; } else { constexpr auto info{ parse_colinfo() }; constexpr cexpr::string name{ tokens_[info.name] }; constexpr auto child{ recurse_columns() }; using next = std::remove_const_t; using col = std::remove_const_t{})>; using node = sql::row; return context{}; } } // wrapper to parse columns as a projection RA node template static constexpr auto parse_projection() { constexpr auto proj{ recurse_columns() }; constexpr auto next{ parse_from() }; using ranode = typename decltype(proj)::node; using node = ra::projection; return context{}; } // wrapper to parse columns as a rename RA node template static constexpr auto parse_rename() { constexpr auto next = parse_projection(); using ranode = typename decltype(recurse_columns())::node; using node = ra::rename; return context{}; } // attempts to match column rename operation pattern on a column template static constexpr bool has_rename() { if constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2])) { return false; } else if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2])) { return true; } else { constexpr bool comma{ iscomma(tokens_[Pos + 1]) }; static_assert(comma || isfrom(tokens_[Pos + 1]), "Expected ',' or 'FROM' token following column."); if constexpr (comma) { return has_rename(); } else { return has_rename(); } } } // decide RA node to root the expression tree template static constexpr auto parse_root() { static_assert(isselect(tokens_[Pos]), "Expected 'SELECT' token not found."); if constexpr (tokens_[Pos + 1] == "*") { return parse_from(); } else if constexpr (has_rename()) { return parse_rename(); } else { return parse_projection(); } } static constexpr sql::tokens tokens_{ Str }; using expression = typename decltype(parse_root<0>())::node; bool empty_; public: using iterator = query_iterator; using row_type = expression::output_type; query(Schemas const&... tables) { try { expression::seed(tables...); empty_ = false; } catch(ra::data_end const& e) { empty_ = true; } } ~query() { expression::reset(); } inline iterator begin() const { return iterator{ empty_ }; } inline iterator end() const { return iterator{ true }; } }; } // namespace sql ================================================ FILE: include/sql/row.hpp ================================================ #pragma once #include #include #include #include "cexpr/string.hpp" namespace sql { struct void_row { static constexpr std::size_t depth{ 0 }; }; template class row { public: using column = Col; using next = Next; static constexpr std::size_t depth{ 1 + next::depth }; row() = default; template row(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... } {} template row(column::type&& val, ColTs&&... vals) : value_{ std::forward(val) }, next_{ std::forward(vals)... } {} inline constexpr next const& tail() const noexcept { return next_; } inline constexpr next& tail() noexcept { return next_; } inline constexpr column::type const& head() const noexcept { return value_; } inline constexpr column::type& head() noexcept { return value_; } private: column::type value_; next next_; }; template struct variadic_row { private: static inline constexpr auto resolve() noexcept { if constexpr (sizeof...(Cols) != 0) { return typename variadic_row::row_type{}; } else { return void_row{}; } } public: using row_type = row; }; // user function to query row elements by column name template constexpr auto const& get(Row const& r) noexcept { static_assert(!std::is_same_v, "Name does not match a column name."); if constexpr (Row::column::name == Name) { return r.head(); } else { return get(r.tail()); } } // compiler function used by structured binding declaration template constexpr auto const& get(Row const& r) noexcept { static_assert(Pos < Row::depth, "Position is larger than number of row columns."); if constexpr (Pos == 0) { return r.head(); } else { return get(r.tail()); } } // function to assign a value to a column's value in a row template constexpr void set(Row& r, Type const& value) { static_assert(!std::is_same_v, "Name does not match a column name."); if constexpr (Row::column::name == Name) { r.head() = value; } else { set(r.tail(), value); } } } // namespace sql // STL injections to allow row to be used in structured binding declarations namespace std { template class tuple_size> : public integral_constant::depth> {}; template struct tuple_element> { using type = decltype(sql::get(sql::row{})); }; } // namespace std ================================================ FILE: include/sql/schema.hpp ================================================ #pragma once #include #include #include #include #include #include "cexpr/string.hpp" #include "sql/column.hpp" #include "sql/index.hpp" #include "sql/row.hpp" namespace sql { template class schema { public: static constexpr auto name{ Name }; using row_type = sql::variadic_row::row_type; using container = typename std::conditional_t< std::is_same_v>, std::vector, std::multiset> >; using const_iterator = typename container::const_iterator; schema() = default; template schema(std::vector const& col, Types const&... cols) : schema{} { insert(col, cols...); } template schema(std::vector&& col, Types&&... cols) : schema{} { insert(std::forward(col), std::forward(cols)...); } template inline void emplace(Types const&... vals) { if constexpr (std::is_same_v>) { table_.emplace_back(vals...); } else { table_.emplace(vals...); } } template inline void emplace(Types&&... vals) { if constexpr (std::is_same_v>) { table_.emplace_back(vals...); } else { table_.emplace(vals...); } } template void insert(std::vector const& col, Types const&... cols) { for (std::size_t i{}; i < col.size(); ++i) { emplace(col[i], cols[i]...); } } template void insert(std::vector&& col, Types&&... cols) { for (std::size_t i{}; i < col.size(); ++i) { emplace(std::forward(col[i]), std::forward(cols[i])...); } } void insert(row_type const& row) { if constexpr (std::is_same_v>) { table_.push_back(row); } else { table_.insert(row); } } void insert(row_type&& row) { if constexpr (std::is_same_v>) { table_.push_back(std::forward(row)); } else { table_.insert(std::forward(row)); } } inline const_iterator begin() const noexcept { return table_.begin(); } inline const_iterator end() const noexcept { return table_.end(); } private: container table_; }; namespace { template void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim) { if constexpr (!std::is_same_v) { if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { std::getline(fstr, row.head()); } else { std::getline(fstr, row.head(), delim); } } else { fstr >> row.head(); } fill(fstr, row.tail(), delim); } } template void fill(std::fstream& fstr, Row const& row, char delim) { if constexpr (!std::is_same_v) { fstr << row.head(); if constexpr (std::is_same_v) { fstr << '\n'; } else { fstr << delim; } fill(fstr, row.tail(), delim); } } } // namespace // helper function for users to load a data into a schema from a file template Schema load(std::string const& file, char delim) { auto fstr{ std::fstream(file, fstr.in) }; Schema table{}; typename Schema::row_type row{}; while (fstr) { fill(fstr, row, delim); table.insert(std::move(row)); // in case last stream extraction did not remove newline if (fstr.get() != '\n') { fstr.unget(); } } return table; } // for compat with previous versions template inline Schema load(std::string const& file) { return load(file, Delim); } // will work with schema and query objects template void store(Type const& data, std::string const& file, char delim) { auto fstr{ std::fstream(file, fstr.out) }; for (auto const& row : data) { fill(fstr, row, delim); } } // for devs who want to use the previous format template inline void store(Type const& data, std::string const& file) { store(data, file, Delim); } } // namespace sql ================================================ FILE: include/sql/tokens.hpp ================================================ #pragma once #include #include #include #include #include "cexpr/string.hpp" namespace sql { namespace { template constexpr bool whitespace(Char curr) { return curr == Char{ ' ' } || curr == Char{ '\t' } || curr == Char{ '\n' }; } template constexpr bool syntax(Char curr) { return curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } || curr == Char{ '\'' } || curr == Char{ '\"' } || curr == Char{ '=' }; } template constexpr const Char* skip(const Char *curr, const Char *end) { for (; curr != end && whitespace(*curr); ++curr); return curr; } template constexpr const Char* next(const Char *curr, const Char *end) { Char c{ *curr }; if (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' }) { ++curr; if (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' })) { ++curr; } } else if (syntax(c)) { ++curr; } else { for (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr); } return curr; } } // namespace template class tokens { public: using token_view = std::basic_string_view; constexpr tokens() = default; template constexpr tokens(cexpr::string const& cs) : tokens_{} { auto curr{ cs.cbegin() }, last{ cs.cbegin() }; const auto end{ cs.cend() }; std::size_t i{}; while (curr < end) { curr = skip(curr, end); last = curr; last = next(last, end); if (*curr == Char{ '\"' } || *curr == Char{ '\'' }) { tokens_[i++] = token_view{ curr, 1 }; for (char c{ *curr++ }; last != end && *last != c; ++last); } auto len{ reinterpret_cast(last) - reinterpret_cast(curr) }; tokens_[i++] = token_view{ curr, len }; if (*last == Char{ '\"' } || *last == Char{ '\'' }) { tokens_[i++] = token_view{ last, 1 }; ++last; } curr = last; } } constexpr std::size_t count() const noexcept { return Count; } constexpr token_view* begin() noexcept { return tokens_.begin(); } constexpr const token_view* cbegin() const noexcept { return tokens_.cbegin(); } constexpr token_view* end() noexcept { return tokens_.end(); } constexpr const token_view* cend() const noexcept { return tokens_.cend(); } constexpr token_view& operator[](std::size_t i) { return tokens_[i]; } constexpr token_view const& operator[](std::size_t i) const { return tokens_[i]; } private: std::array tokens_; }; template constexpr std::size_t preprocess(cexpr::string const& cs) noexcept { auto begin{ cs.cbegin() }; const auto end{ cs.cend() }; std::size_t count{ 1 }; while (begin < end) { begin = skip(begin, end); begin = next(begin, end); ++count; } return count; } } // namespace sql ================================================ FILE: single-header/sql.hpp ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace cexpr { template class string { public: using char_type = Char; constexpr string() noexcept : size_{ 0 }, string_{ 0 } {} constexpr string(const Char(&s)[N]) noexcept : string{} { for(; s[size_]; ++size_) { string_[size_] = s[size_]; } } constexpr string(cexpr::string const& s) noexcept : string{} { for (; s[size_]; ++size_) { string_[size_] = s[size_]; } } constexpr string(std::basic_string_view const& s) noexcept : string{} { if (s.length() < N) { for (; size_ < s.length(); ++size_) { string_[size_] = s[size_]; } } } constexpr void fill(const Char* begin, const Char* end) noexcept { fill_from(begin, end, begin()); } constexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept { if (end - begin < N) { for (auto curr{ start }; begin != end; ++begin, ++curr) { *curr = *begin; } } } inline constexpr std::size_t capacity() const noexcept { return N - 1; } inline constexpr std::size_t size() const noexcept { return size_; } inline constexpr Char* begin() noexcept { return string_; } inline constexpr const Char* cbegin() const noexcept { return string_; } inline constexpr Char* end() noexcept { return &string_[size_]; } inline constexpr const Char* cend() const noexcept { return &string_[size_]; } inline constexpr Char& operator[](std::size_t i) { return string_[i]; } inline constexpr Char const& operator[](std::size_t i) const { return string_[i]; } template constexpr bool operator==(string const& other) const noexcept { if constexpr (N != OtherN) { return false; } std::size_t i{}; for (; i < N && string_[i] == other[i]; ++i); return i == N; } template constexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept { if constexpr (N != OtherN) { return false; } std::size_t i{}; for (; i < N && string_[i] == other[i]; ++i); return i == N; } template inline bool operator==(std::basic_string const& other) const noexcept { return other == string_; } template inline bool operator!=(std::basic_string const& other) const noexcept { return !(other == string_); } private: std::size_t size_; Char string_[N]; }; template string(const Char[N]) -> string; template inline bool operator==(std::basic_string const& str, string const& cstr) noexcept { return cstr == str; } template inline bool operator!=(std::basic_string const& str, string const& cstr) noexcept { return cstr != str; } } // namespace cexpr namespace sql { template struct column { static constexpr auto name{ Name }; using type = Type; }; } // namespace sql namespace sql { struct void_row { static constexpr std::size_t depth{ 0 }; }; template class row { public: using column = Col; using next = Next; static constexpr std::size_t depth{ 1 + next::depth }; row() = default; template row(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... } {} template row(column::type&& val, ColTs&&... vals) : value_{ std::forward(val) }, next_{ std::forward(vals)... } {} inline constexpr next const& tail() const noexcept { return next_; } inline constexpr next& tail() noexcept { return next_; } inline constexpr column::type const& head() const noexcept { return value_; } inline constexpr column::type& head() noexcept { return value_; } private: column::type value_; next next_; }; template struct variadic_row { private: static inline constexpr auto resolve() noexcept { if constexpr (sizeof...(Cols) != 0) { return typename variadic_row::row_type{}; } else { return void_row{}; } } public: using row_type = row; }; // user function to query row elements by column name template constexpr auto const& get(Row const& r) noexcept { static_assert(!std::is_same_v, "Name does not match a column name."); if constexpr (Row::column::name == Name) { return r.head(); } else { return get(r.tail()); } } // compiler function used by structured binding declaration template constexpr auto const& get(Row const& r) noexcept { static_assert(Pos < Row::depth, "Position is larger than number of row columns."); if constexpr (Pos == 0) { return r.head(); } else { return get(r.tail()); } } // function to assign a value to a column's value in a row template constexpr void set(Row& r, Type const& value) { static_assert(!std::is_same_v, "Name does not match a column name."); if constexpr (Row::column::name == Name) { r.head() = value; } else { set(r.tail(), value); } } } // namespace sql // STL injections to allow row to be used in structured binding declarations namespace std { template class tuple_size> : public integral_constant::depth> {}; template struct tuple_element> { using type = decltype(sql::get(sql::row{})); }; } // namespace std namespace sql { template struct index { template struct comparator { bool operator()(Row const& left, Row const& right) const noexcept { return compare(left, right); } private: template bool compare(Row const& left, Row const& right) const noexcept { auto const& l{ sql::get(left) }; auto const& r{ sql::get(right) }; if constexpr (sizeof...(Cols) != 0) { if (l == r) { return compare(left, right); } } return l < r; } }; }; } // namespace sql namespace sql { template class schema { public: static constexpr auto name{ Name }; using row_type = sql::variadic_row::row_type; using container = typename std::conditional_t< std::is_same_v>, std::vector, std::multiset> >; using const_iterator = typename container::const_iterator; schema() = default; template schema(std::vector const& col, Types const&... cols) : schema{} { insert(col, cols...); } template schema(std::vector&& col, Types&&... cols) : schema{} { insert(std::forward(col), std::forward(cols)...); } template inline void emplace(Types const&... vals) { if constexpr (std::is_same_v>) { table_.emplace_back(vals...); } else { table_.emplace(vals...); } } template inline void emplace(Types&&... vals) { if constexpr (std::is_same_v>) { table_.emplace_back(vals...); } else { table_.emplace(vals...); } } template void insert(std::vector const& col, Types const&... cols) { for (std::size_t i{}; i < col.size(); ++i) { emplace(col[i], cols[i]...); } } template void insert(std::vector&& col, Types&&... cols) { for (std::size_t i{}; i < col.size(); ++i) { emplace(std::forward(col[i]), std::forward(cols[i])...); } } void insert(row_type const& row) { if constexpr (std::is_same_v>) { table_.push_back(row); } else { table_.insert(row); } } void insert(row_type&& row) { if constexpr (std::is_same_v>) { table_.push_back(std::forward(row)); } else { table_.insert(std::forward(row)); } } inline const_iterator begin() const noexcept { return table_.begin(); } inline const_iterator end() const noexcept { return table_.end(); } private: container table_; }; namespace { template void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim) { if constexpr (!std::is_same_v) { if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { std::getline(fstr, row.head()); } else { std::getline(fstr, row.head(), delim); } } else { fstr >> row.head(); } fill(fstr, row.tail(), delim); } } template void fill(std::fstream& fstr, Row const& row, char delim) { if constexpr (!std::is_same_v) { fstr << row.head(); if constexpr (std::is_same_v) { fstr << '\n'; } else { fstr << delim; } fill(fstr, row.tail(), delim); } } } // namespace // helper function for users to load a data into a schema from a file template Schema load(std::string const& file, char delim) { auto fstr{ std::fstream(file, fstr.in) }; Schema table{}; typename Schema::row_type row{}; while (fstr) { fill(fstr, row, delim); table.insert(std::move(row)); // in case last stream extraction did not remove newline if (fstr.get() != '\n') { fstr.unget(); } } return table; } // for compat with previous versions template inline Schema load(std::string const& file) { return load(file, Delim); } // will work with schema and query objects template void store(Type const& data, std::string const& file, char delim) { auto fstr{ std::fstream(file, fstr.out) }; for (auto const& row : data) { fill(fstr, row, delim); } } // for devs who want to use the previous format template inline void store(Type const& data, std::string const& file) { store(data, file, Delim); } } // namespace sql namespace ra { template class unary { public: using input_type = std::remove_cvref_t; template static inline void seed(Inputs const&... rs) { Input::seed(rs...); } static inline void reset() { Input::reset(); } }; template class binary { public: using left_type = std::remove_cvref_t; using right_type = std::remove_cvref_t; template static inline void seed(Inputs const&... rs) { LeftInput::seed(rs...); RightInput::seed(rs...); } static inline void reset() { LeftInput::reset(); RightInput::reset(); } }; } // namespace ra namespace ra { namespace { template constexpr auto recr_merge() { if constexpr (std::is_same_v) { return Right{}; } else { using next = decltype(recr_merge()); return sql::row{}; } } template inline constexpr auto merge() { if constexpr (Left::column::name == Right::column::name) { return recr_merge(); } else { return recr_merge(); } } template constexpr void recr_copy(Dest& dest, Row const& src) { if constexpr (std::is_same_v) { return; } else { dest.head() = src.head(); recr_copy(dest.tail(), src.tail()); } } template inline constexpr void copy(Dest& dest, Row const& src) { if constexpr (Dest::column::name == Row::column::name) { recr_copy(dest, src); } else { copy(dest.tail(), src); } } } // namespace template class join : public ra::binary { using binary_type = ra::binary; using left_type = typename binary_type::left_type; using right_type = typename binary_type::right_type; public: using output_type = decltype(merge()); template static inline void seed(Inputs const&... rs) { binary_type::seed(rs...); copy(output_row, LeftInput::next()); } static inline void reset() { binary_type::reset(); copy(output_row, LeftInput::next()); } static output_type output_row; }; template typename join::output_type join::output_row{}; } // namespace ra namespace ra { struct data_end : std::exception {}; // Id template parameter allows unique ra::relation types to be instantiated from // a single sql::schema type (for queries referencing a schema multiple times). template class relation { public: using output_type = Schema::row_type&; static auto& next() { if (curr != end) { return *curr++; } else { throw ra::data_end{}; } } template static void seed(Input const& r, Inputs const&... rs) noexcept { if constexpr (std::is_same_v) { curr = r.begin(); begin = r.begin(); end = r.end(); } else { seed(rs...); } } static inline void reset() noexcept { curr = begin; } private: static Schema::const_iterator curr; static Schema::const_iterator begin; static Schema::const_iterator end; }; template Schema::const_iterator relation::curr{}; template Schema::const_iterator relation::begin{}; template Schema::const_iterator relation::end{}; } // namespace ra namespace ra { template class cross : public ra::join { using join_type = ra::join; public: using output_type = join_type::output_type; static auto&& next() { try { copy(join_type::output_row, RightInput::next()); } catch(ra::data_end const& e) { copy(join_type::output_row, LeftInput::next()); RightInput::reset(); copy(join_type::output_row, RightInput::next()); } return std::move(join_type::output_row); } }; } // namespace ra namespace ra { template class natural : public ra::join { using join_type = ra::join; using key_type = std::remove_cvref_t; using value_type = std::vector>; using map_type = std::unordered_map; public: using output_type = join_type::output_type; template static void seed(Inputs const&... rs) { join_type::seed(rs...); if (row_cache.empty()) { try { for (;;) { auto const& row{ RightInput::next() }; row_cache[row.head()].push_back(row.tail()); } } catch(ra::data_end const& e) { RightInput::reset(); } } auto const& active{ row_cache[join_type::output_row.head()] }; curr = active.cbegin(); end = active.cend(); } static auto&& next() { while (curr == end) { copy(join_type::output_row, LeftInput::next()); auto const& active{ row_cache[join_type::output_row.head()] }; curr = active.cbegin(); end = active.cend(); } copy(join_type::output_row, *curr++); return std::move(join_type::output_row); } private: static map_type row_cache; static value_type::const_iterator curr; static value_type::const_iterator end; }; template typename natural::map_type natural::row_cache{}; template typename natural::value_type::const_iterator natural::curr; template typename natural::value_type::const_iterator natural::end; } // namespace ra namespace ra { template class projection : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = Output; static auto&& next() { fold(output_row, Input::next()); return std::move(output_row); } private: template static inline constexpr void fold(Dest& dest, input_type const& src) { if constexpr (Dest::depth == 0) { return; } else { dest.head() = sql::get(src); fold(dest.tail(), src); } } static output_type output_row; }; template typename projection::output_type projection::output_row{}; } // namespace ra namespace ra { template class rename : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = Output; static auto&& next() { fold(output_row, Input::next()); return std::move(output_row); } private: template static inline constexpr void fold(Dest& dest, Src const& src) { if constexpr (Dest::depth == 0) { return; } else { dest.head() = src.head(); fold(dest.tail(), src.tail()); } } static output_type output_row; }; template typename rename::output_type rename::output_row{}; } // namespace ra namespace ra { template class selection : public ra::unary { using input_type = typename ra::unary::input_type; public: using output_type = input_type; static auto&& next() { output_row = Input::next(); while(!Predicate::eval(output_row)) { output_row = Input::next(); } return std::move(output_row); } private: static output_type output_row; }; template typename selection::output_type selection::output_row{}; } // namespace ra namespace sql { namespace { template constexpr bool whitespace(Char curr) { return curr == Char{ ' ' } || curr == Char{ '\t' } || curr == Char{ '\n' }; } template constexpr bool syntax(Char curr) { return curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } || curr == Char{ '\'' } || curr == Char{ '\"' } || curr == Char{ '=' }; } template constexpr const Char* skip(const Char *curr, const Char *end) { for (; curr != end && whitespace(*curr); ++curr); return curr; } template constexpr const Char* next(const Char *curr, const Char *end) { Char c{ *curr }; if (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' }) { ++curr; if (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' })) { ++curr; } } else if (syntax(c)) { ++curr; } else { for (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr); } return curr; } } // namespace template class tokens { public: using token_view = std::basic_string_view; constexpr tokens() = default; template constexpr tokens(cexpr::string const& cs) : tokens_{} { auto curr{ cs.cbegin() }, last{ cs.cbegin() }; const auto end{ cs.cend() }; std::size_t i{}; while (curr < end) { curr = skip(curr, end); last = curr; last = next(last, end); if (*curr == Char{ '\"' } || *curr == Char{ '\'' }) { tokens_[i++] = token_view{ curr, 1 }; for (char c{ *curr++ }; last != end && *last != c; ++last); } auto len{ reinterpret_cast(last) - reinterpret_cast(curr) }; tokens_[i++] = token_view{ curr, len }; if (*last == Char{ '\"' } || *last == Char{ '\'' }) { tokens_[i++] = token_view{ last, 1 }; ++last; } curr = last; } } constexpr std::size_t count() const noexcept { return Count; } constexpr token_view* begin() noexcept { return tokens_.begin(); } constexpr const token_view* cbegin() const noexcept { return tokens_.cbegin(); } constexpr token_view* end() noexcept { return tokens_.end(); } constexpr const token_view* cend() const noexcept { return tokens_.cend(); } constexpr token_view& operator[](std::size_t i) { return tokens_[i]; } constexpr token_view const& operator[](std::size_t i) const { return tokens_[i]; } private: std::array tokens_; }; template constexpr std::size_t preprocess(cexpr::string const& cs) noexcept { auto begin{ cs.cbegin() }; const auto end{ cs.cend() }; std::size_t count{ 1 }; while (begin < end) { begin = skip(begin, end); begin = next(begin, end); ++count; } return count; } } // namespace sql namespace sql { namespace { // shim to allow all value types like double or float to be used as non-type template parameters. template struct value { constexpr value(Type v) : val{ v } {} Type val; }; } // namespace template struct operation { static constexpr bool eval(Row const& row) noexcept { if constexpr (Op == "=") { return Left::eval(row) == Right::eval(row); } else if constexpr (Op == ">") { return Left::eval(row) > Right::eval(row); } else if constexpr(Op == "<") { return Left::eval(row) < Right::eval(row); } else if constexpr(Op == ">=") { return Left::eval(row) >= Right::eval(row); } else if constexpr(Op == "<=") { return Left::eval(row) <= Right::eval(row); } else if constexpr(Op == "!=" || Op == "<>") { return Left::eval(row) != Right::eval(row); } else if constexpr(Op == "AND") { return Left::eval(row) && Right::eval(row); } else if constexpr(Op == "OR") { return Left::eval(row) || Right::eval(row); } else if constexpr(Op == "NOT") { return !Left::eval(row); } } }; template struct variable { static constexpr auto eval(Row const& row) noexcept { return sql::get(row); } }; template struct constant { static constexpr auto eval([[maybe_unused]] Row const& row) noexcept { return Const.val; } }; } // namespace sql namespace sql { // anonymous namespace to hold helper data structures and functions namespace { template struct context { using node = Node; static constexpr std::size_t pos = Pos; }; template struct colinfo { using type = Type; static constexpr std::size_t name = Name; static constexpr std::size_t next = Next; }; template constexpr bool exists() noexcept { if constexpr (std::is_same_v) { return false; } else { if constexpr (Row::column::name == Name) { return true; } else { return exists(); } } } template constexpr value convert(cexpr::string const& str) noexcept { auto curr{ str.cbegin() }, end{ str.cend() }; constexpr Char dot{ '.' }, zro{ '0' }, min{ '-' }; Type acc{}, sign{ 1 }, scalar{ 10 }; if (*curr == min) { sign = -1; ++curr; } while (curr != end && *curr != dot) { acc = (acc * scalar) + (*curr - zro); ++curr; } if (curr != end && *curr == dot) { scalar = 1; ++curr; while(curr != end) { acc += (*curr - zro) * (scalar /= Type{ 10 }); ++curr; } } return value{ acc * sign }; } inline constexpr bool isquote(std::string_view const& tv) noexcept { return tv == "\"" || tv == "'"; } inline constexpr bool isor(std::string_view const& tv) noexcept { return tv == "OR" || tv == "or"; } inline constexpr bool isand(std::string_view const& tv) noexcept { return tv == "AND" || tv == "and"; } inline constexpr bool isnot(std::string_view const& tv) noexcept { return tv == "NOT" || tv == "not"; } inline constexpr bool isnatural(std::string_view const& tv) noexcept { return tv == "NATURAL" || tv == "natural"; } inline constexpr bool isjoin(std::string_view const& tv) noexcept { return tv == "JOIN" || tv == "join"; } inline constexpr bool iswhere(std::string_view const& tv) noexcept { return tv == "WHERE" || tv == "where"; } inline constexpr bool isfrom(std::string_view const& tv) noexcept { return tv == "FROM" || tv == "from"; } inline constexpr bool isas(std::string_view const& tv) noexcept { return tv == "AS" || tv == "as"; } inline constexpr bool isselect(std::string_view const& tv) noexcept { return tv == "SELECT" || tv == "select"; } inline constexpr bool iscomma(std::string_view const& tv) noexcept { return tv == ","; } constexpr bool isintegral(std::string_view const& tv) noexcept { bool result{ false }; for (auto c : tv) { result |= (c == '.'); } return !result; } constexpr bool isdigit(char c) noexcept { return (c >= '0' && c <= '9') || c == '-' || c == '.'; } constexpr bool iscomp(char c) noexcept { return c == '=' || c == '!' || c == '<' || c == '>'; } constexpr bool iscolumn(std::string_view const& tv) noexcept { return !iscomma(tv) && !isas(tv) && !isfrom(tv); } constexpr bool isseparator(std::string_view const& tv) noexcept { return iscomma(tv) || isfrom(tv); } } // namespace // structured binding compliant iterator for query objects template class query_iterator { public: using row_type = std::remove_cvref_t; // seeds row datamember for first dereference query_iterator(bool end) : end_{ end }, row_{} { operator++(); } inline bool operator==(query_iterator const& it) const noexcept { return end_ == it.end_; } inline bool operator!=(query_iterator const& it) const noexcept { return !(*this == it); } inline row_type const& operator*() const noexcept { return row_; } query_iterator& operator++() { if (!end_) { try { row_ = Expr::next(); } catch (ra::data_end const& e) { end_ = true; } } return *this; } private: bool end_{}; row_type row_{}; }; template class query { private: // where predicate terminal parsing template static constexpr auto parse_terms() { if constexpr (tokens_[Pos] == "(") { constexpr auto next{ parse_or() }; using node = typename decltype(next)::node; static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); return context{}; } else if constexpr (isquote(tokens_[Pos])) { constexpr cexpr::string name{ tokens_[Pos + 1] }; using str = decltype(name); using node = sql::constant{ name }, Row>; static_assert(isquote(tokens_[Pos + 2]), "No closing quote found."); return context{}; } else if constexpr (isdigit(tokens_[Pos][0])) { constexpr cexpr::string name{ tokens_[Pos] }; using val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{}); using node = sql::constant(name), Row>; return context{}; } else { constexpr cexpr::string name{ tokens_[Pos] }; using node = sql::variable; return context{}; } } // parses a single compare operation template static constexpr auto recurse_comparison() { if constexpr (!iscomp(tokens_[Left::pos][0])) { return Left{}; } else { constexpr auto next{ parse_terms() }; constexpr cexpr::string name{ tokens_[Left::pos] }; using ranode = typename decltype(next)::node; using node = sql::operation; return context{}; } } // descend further and attempt to parse a compare operation template static constexpr auto parse_comparison() { using left = decltype(parse_terms()); return recurse_comparison(); } // attempt to parse a negation operation then descend further template static constexpr auto parse_negation() { if constexpr (isnot(tokens_[Pos])) { constexpr auto next{ parse_comparison() }; using ranode = typename decltype(next)::node; using node = sql::operation<"NOT", Row, ranode>; return context{}; } else { return parse_comparison(); } } // recursively parse chained AND operations template static constexpr auto recurse_and() { if constexpr (!isand(tokens_[Left::pos])) { return Left{}; } else { constexpr auto next{ parse_negation() }; using ranode = typename decltype(next)::node; using node = sql::operation<"AND", Row, typename Left::node, ranode>; return recurse_and, Row>(); } } // descend further then attempt to parse AND operations template static constexpr auto parse_and() { using left = decltype(parse_negation()); return recurse_and(); } // recursively parse chained OR operations template static constexpr auto recurse_or() { if constexpr (!isor(tokens_[Left::pos])) { return Left{}; } else { constexpr auto next{ parse_and() }; using ranode = typename decltype(next)::node; using node = sql::operation<"OR", Row, typename Left::node, ranode>; return recurse_or, Row>(); } } // descend further then attempt to parse OR operations template static constexpr auto parse_or() { using left = decltype(parse_and()); return recurse_or(); } // find correct schema for terminal relation template static constexpr auto recurse_schemas() { if constexpr (Name == Schema::name) { return ra::relation{}; } else { static_assert(sizeof...(Others) != 0, "Schema name used in JOIN was not provided."); return recurse_schemas(); } } // wrapper function to determine terminal relation template static constexpr auto parse_schema() { if constexpr (tokens_[Pos] == "(") { constexpr auto next{ parse_root() }; using node = typename decltype(next)::node; static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); return context{}; } else { constexpr cexpr::string name{ tokens_[Pos] }; using node = decltype(recurse_schemas()); return context{}; } } // stub which will choose the specific join RA node template static constexpr auto choose_join() { if constexpr (isnatural(tokens_[Pos])) { return ra::natural{}; } else { return ra::cross{}; } } // parses join colinfo if a join is present else returns the single relation terminal template static constexpr auto parse_join() { constexpr auto lnext{ parse_schema() }; using lnode = typename decltype(lnext)::node; if constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1])) { constexpr auto rnext{ parse_schema() }; using rnode = typename decltype(rnext)::node; using join = decltype(choose_join()); return context{}; } else { return context{}; } } // starting point to parse everything after the from keyword template static constexpr auto parse_from() { static_assert(isfrom(tokens_[Pos]), "Expected 'FROM' token not found."); constexpr auto next{ parse_join() }; using node = typename decltype(next)::node; if constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos])) { using output = std::remove_cvref_t; constexpr auto predicate{ parse_or() }; using pnext = typename decltype(predicate)::node; using snode = ra::selection; return context{}; } else { return context{}; } } // recursively searches all schemas for the a matching column template static constexpr auto recurse_types() { if constexpr (sql::exists()) { return decltype(sql::get(typename Schema::row_type{})){}; } else { static_assert(sizeof...(Others) != 0, "Column name was not present in any schema."); return recurse_types(); } } // wrapper to determine the type for the the column template static constexpr auto column_type() { constexpr cexpr::string name{ tokens_[Pos] }; return recurse_types(); } // asserts token is column separator, and if comma returns one past the comma else start position template static constexpr std::size_t next_column() { static_assert(isseparator(tokens_[Pos]), "Expected ',' or 'FROM' token following column."); if constexpr (iscomma(tokens_[Pos])) { return Pos + 1; } else { return Pos; } } template static constexpr auto parse_colinfo() { static_assert(iscolumn(tokens_[Pos]), "Invalid token starting column delcaration."); constexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) }; using col = decltype(column_type()); if constexpr (Rename && rename) { constexpr auto next{ next_column() }; return colinfo{}; } else if constexpr (rename) { constexpr auto next{ next_column() }; return colinfo{}; } else { constexpr auto next{ next_column() }; return colinfo{}; } } // recursively parse all columns projected/renamed in the query template static constexpr auto recurse_columns() { if constexpr (isfrom(tokens_[Pos])) { return context{}; } else { constexpr auto info{ parse_colinfo() }; constexpr cexpr::string name{ tokens_[info.name] }; constexpr auto child{ recurse_columns() }; using next = std::remove_const_t; using col = std::remove_const_t{})>; using node = sql::row; return context{}; } } // wrapper to parse columns as a projection RA node template static constexpr auto parse_projection() { constexpr auto proj{ recurse_columns() }; constexpr auto next{ parse_from() }; using ranode = typename decltype(proj)::node; using node = ra::projection; return context{}; } // wrapper to parse columns as a rename RA node template static constexpr auto parse_rename() { constexpr auto next = parse_projection(); using ranode = typename decltype(recurse_columns())::node; using node = ra::rename; return context{}; } // attempts to match column rename operation pattern on a column template static constexpr bool has_rename() { if constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2])) { return false; } else if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2])) { return true; } else { constexpr bool comma{ iscomma(tokens_[Pos + 1]) }; static_assert(comma || isfrom(tokens_[Pos + 1]), "Expected ',' or 'FROM' token following column."); if constexpr (comma) { return has_rename(); } else { return has_rename(); } } } // decide RA node to root the expression tree template static constexpr auto parse_root() { static_assert(isselect(tokens_[Pos]), "Expected 'SELECT' token not found."); if constexpr (tokens_[Pos + 1] == "*") { return parse_from(); } else if constexpr (has_rename()) { return parse_rename(); } else { return parse_projection(); } } static constexpr sql::tokens tokens_{ Str }; using expression = typename decltype(parse_root<0>())::node; bool empty_; public: using iterator = query_iterator; using row_type = expression::output_type; query(Schemas const&... tables) { try { expression::seed(tables...); empty_ = false; } catch(ra::data_end const& e) { empty_ = true; } } ~query() { expression::reset(); } inline iterator begin() const { return iterator{ empty_ }; } inline iterator end() const { return iterator{ true }; } }; } // namespace sql ================================================ FILE: tests/data/authored.tsv ================================================ 1984 George Orwell !!!The!!Teddy!Crazy!!Show!!! Harlan Ellison (Learning About) Machine Sex Candas Jane Dorsey ...the World, as we Know 't Howard Waldrop 2001: A Space Odyssey Arthur C. Clarke 2004, or Thereabouts David R. Bunch 20th Century Boys vol.1 Naoki Urasawa 20th Century Boys vol.2 Naoki Urasawa 20th Century Boys vol.3 Naoki Urasawa 20th Century Boys vol.4 Naoki Urasawa 20th Century Boys vol.5 Naoki Urasawa 20th Century Boys vol.6 Naoki Urasawa A Biography of Tadeo Isidoro Cruz (1829-1874) Jorge Luis Borges A Brief History of the Trans-Pacific Tunnel Ken Liu A Canticle for Leibowitz Walter M. Miller, Jr. A Case of Conscience James Blish A Case of Identity Arthur Conan Doyle A Clash of Cymbals James Blish A Clockwork Orange Anthony Burgess A Day at Harmenz Tadeusz Borowski A Deskful of Girls Fritz Leiber A Dialog About A Dialog Jorge Luis Borges A Dialog Between Dead Men Jorge Luis Borges A Farewell to Arms Ernest Hemingway A Feast of Demons William Morrison A Few Things I Know About While Away Joanna Russ A Hundred Ghosts Parade Tonight Xia Jia A is for Automation Kate Wilhelm A Life for the Stars James Blish A Midwinter's Tale Michael Swanwick A Momentary Taste of Being James Tiptree, Jr. A Mouse in the Walls of the Global Village Dean R. Koontz A New Refutation of Time Jorge Luis Borges A Note on (toward) Bernard Shaw Jorge Luis Borges A Path Through the Darkness Harlan Ellison A Prayer for No One's Enemies Harlan Ellison A Problem Jorge Luis Borges A Scandal in Bohemia Arthur Conan Doyle A Scanner Darkly Philip K. Dick A Time of Changes Robert Silverberg A Tour of C++ 2nd Bjarne Stroustrup A Toy for Juliette Robert Bloch A True Story Tadeusz Borowski A Visit Tadeusz Borowski A Way of Thinking Theodore Sturgeon Absalom, Absalom! William Faulkner Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W Harlan Ellison Adrift on the Policy Level Chandler Davis Aesop Clifford D. Simak After the Days of Dead-Eye 'Dee Pat Cadigan Again, Dangerous Visions Harlan Ellison Akira vol.1 Katsuhiro Otomo Akira vol.2 Katsuhiro Otomo Akira vol.3 Katsuhiro Otomo Akira vol.4 Katsuhiro Otomo Akira vol.5 Katsuhiro Otomo Akira vol.6 Katsuhiro Otomo Algorithms 4th Kevin Wayne Algorithms 4th Robert Sedgewick All in Good Time Miram Allen deFord All the Birds Come Home to Roost Harlan Ellison All the Flavors Ken Liu All the Lies Lies That Are My Life Harlan Ellison All The People R. A. Lafferty All the Sound of Fear Harlan Ellison All Tomorrow's Parties William Gibson Along the Scenic Route Harlan Ellison Alpha Ralpha Boulevard Cordwainer Smith Amateur in Chancery George O. Smith America Orson Scott Card An Advanced Readers' Picture Book of Comparative Cognition Ken Liu An Examination of the Work of Herbert Quain Jorge Luis Borges And Chaos Died Joanna Russ And the Angels Sing Kate Wilhelm And the Moon be Still as Bright Ray Bradbury And the Sea Like Mirrors Gregory Benford Andover and the Android Kate Wilhelm Angry Candy Harlan Ellison Animal Farm George Orwell Anybody Else Like Me? Walter M. Miller, Jr. Anywhere But Here, With Anybody But You Harlan Ellison Approaching Oblivion Harlan Ellison April Fools' Day Forever Kate Wilhelm Argumentum Ornithologicum Jorge Luis Borges Army of None Paul Scharre As Simple As That Zenna Henderson At the End of the Orbit Arthur C. Clarke At the Mouse Circus Harlan Ellison Aunt Parnetta's Electric Blisters Diane Glancy Auschwitz, Our Home (A Letter) Tadeusz Borowski Auto-De-Fe Roger Zelazny Avatars of the Tortoise Jorge Luis Borges Averroes' Search Jorge Luis Borges Aye, and Gomorrah... Samuel R. Delany Balanced Ecology James H. Schmitz Basilisk Harlan Ellison Battle for the Mind William Sargant Battle Without Banners Harlan Ellison Battlefield Harlan Ellison Beachhead Clifford D. Simak Beauty's Beast Robert Bloch Bed Sheets are White Evelyn Lief Beowulf Anonymous Bettyann Kris Neville Beyond the Blue Event Horizon Frederik Pohl Bianca's Hands Theodore Sturgeon Bible and Sword Barbara W. Tuchman Big Joe and the Nth Generation Walter M. Miller, Jr. Blabbermouth Theodore Sturgeon Black Bargain Robert Bloch Blame! vol.1 Tsumotu Nihei Blame! vol.2 Tsumotu Nihei Blame! vol.3 Tsumotu Nihei Blame! vol.4 Tsumotu Nihei Blame! vol.5 Tsumotu Nihei Blame! vol.6 Tsumotu Nihei Blank? Harlan Ellison Bleeding Stones Harlan Ellison Blind Bird, Blind Bird, Go Away From Me! Harlan Ellison Blood Bank Walter M. Miller, Jr. Blot Gahan Wilson Blowups Happen Robert A. Heilein Blue Spring Taiyo Matsumoto Borges and I Jorge Luis Borges Bounty T. L. Sherred Brain Wave Poul Anderson Brass and Gold (or Horse and Zeppelin in Beverly Hills) Philip Jose Farmer Brave New World Aldous Huxley Bright Eyes Harlan Ellison Bright Segment Theodore Sturgeon Broken Glass Harlan Ellison Brownshoes Theodore Sturgeon Burning Chrome William Gibson By His Bootstraps Robert A. Heinlein C Primer Plus 5th Stephen Prata C++ Primer 5th Barbara E. Moo C++ Primer 5th Josee Lajoie C++ Primer 5th Stanley B. Lippman Call Girl Tang Fei Camps Jack Dann Capitalism Without Capital Jonathan Haskel Capitalism Without Capital Stian Westlake Captain Harlock: The Classic Collection vol.1 Leiji Matsumoto Captain Harlock: The Classic Collection vol.2 Leiji Matsumoto Captain Harlock: The Classic Collection vol.3 Leiji Matusmoto Carcinoma Angels Norman Spinard Catch That Rabbit Isaac Asimov Catch-22 Joseph Heller Catman Harlan Ellison Caviar Theodore Sturgeon Census Clifford D. Simak Chain Reaction Boyd Ellanby Chained to the Fast Lane in the Red Queen's Race Harlan Ellison Changewar Fritz Leiber Chapterhouse: Dune Frank Herbert Chatting with Anubis Harlan Ellison Childhood's End Arthur C. Clarke Children of Dune Frank Herbert Children of the Sea vol.1 Daisuke Igarashi Children of the Sea vol.2 Daisuke Igarashi Children of the Sea vol.3 Daisuke Igarashi Children of the Sea vol.4 Daisuke Igarashi Children of the Sea vol.5 Daisuke Igarashi Ching Witch! Ross Rocklynne Christ, Old Student in a New School Ray Bradbury Chuck Berry, Won't You Please Come Home Ken McCullough City Clifford D. Simak Cold Friend Harlan Ellison Collecting Team Robert Silverberg Colossus B. Jack Copeland Columbus Was a Dope Robert A. Heinlein Come to the Party F. M. Busby Comes Now the Power Roger Zelazny Commuter's Problem Harlan Ellison Conversations With Jorge Luis Borges Richard Burgin Corpse Harlan Ellison Count the Clock That Tells the Time Harlan Ellison Count Zero William Gibson Covered Mirrors Jorge Luis Borges Crate Theodore Sturgeon Crazy as a Soup Sandwich Harlan Ellison Croatoan Harlan Ellison Crome Yellow Aldous Huxley Crucifixus Etiam Walter M. Miller, Jr. Curse 5.0 Liu Cixin Damnation Morning Fritz Leiber Dandelion Wine Ray Bradbury Dangerous Visions Harlan Ellison Danger-Human! Gordon R. Dickson Daniel White for the Greater Good Harlan Ellison Darkness Upon the Face of the Deep Harlan Ellison Day Million Frederik Pohl Deal From the Bottom Harlan Ellison Death and the Compass Jorge Luis Borges Death and the Penguin Andrey Kurkov Deathbird Stories Harlan Ellison Death's End Liu Cixin Deeper than the Darkness Harlan Ellison Delia Elena San Marco Jorge Luis Borges Delusion for a Dragon Slayer Harlan Ellison Design Patterns Erich Gamma Design Patterns John Vlissides Design Patterns Ralph Johnson Design Patterns Richard Helm Destined for War Graham Allison Deutsches Requiem Jorge Luis Borges Devourer Liu Cixin Dirk Gently's Holistic Detective Agency Douglas Adams Distant Signals Andrew Weiner Distrust That Particular Flavor William Gibson Division by Zero Ted Chiang Django Harlan Ellison Djinn, No Chaser Harlan Ellison Do Androids Dream of Electric Sheep? Philip K. Dick Doctor Zhivago Boris Pasternak Dogfight Michael Swanwick Dogfight William Gibson Do-It-Yourself Harlan Ellison Don Quixote Miguel de Cervantes Saavedra Double Star Robert A. Heinlein Downward to the Earth Robert Silverberg Dr. Bloodmoney Philip K. Dick Dreamtigers Jorge Luis Borges Dumb Waiter Walter M. Miller, Jr. Dune Frank Herbert Dune Messiah Frank Herbert Dying Inside Robert Silverberg Each an Explorer Isaac Asimov Earthman, Come Home James Blish Earthman, Go Home! Harlan Ellison Ecowarewness Harlan Ellison Eidolons Harlan Ellison Elbow Room Marion Zimmer Bradley Elegy Jorge Luis Borges Elouise and the Doctors of the Planet Pergamon Josephine Saxton Emanon vol.1: Memories of Emanon Kenji Tsuruta Emanon vol.2: Emanon Wanderer pt.1 Kenji Tsuruta Emanon vol.3: Emanon Wanderer pt.2 Kenji Tsuruta Emissary from Hamelin Harlan Ellison Emma Zunz Jorge Luis Borges Empire of the Sun Andrew Weiner Empire Star Samuel R. Delany Encounter With A Hick Jonathan Brand Ender's Game Orson Scott Card Endless Frontier G. Pascal Zachary Endymion Dan Simmons Enemy Mine Barry B. Longyear Eniac Scott McCartney Epilogue Clifford D. Simak Epiphany for Aliens David Kerr Ernest and the Machine God Harlan Ellison Erotophobia Harlan Ellison Ersatz Henry Slesar Escape! Isaac Asimov Escapegoat Harlan Ellison Eutopia Poul Anderson Evensong Lester del Rey Everything and Nothing Jorge Luis Borges Evidence Isaac Asimov Exploration Team Murray Leinster Explorers of Space Robert Silverberg Exposures Gregory Benford Eye of the Beholder Burt K. Filer Fahrenheit 451 Ray Bradbury Faith of our Fathers Philip K. Dick Fault-Tolerant Computer System Designs Dhiraj K. Pradhan Fear is a Cold Black Kate Wilhelm Feather Tigers Gene Wolfe Featherbed on Chlyntha Miram Allen deFord Fiasco Stanislaw Lem Ficciones Jorge Luis Borges Final Trophy Harlan Ellison Flies Robert Silverberg Flop Sweat Harlan Ellison Flow My Tears, the Policeman Said Philip K. Dick Flowers for Algernon Daniel Keyes Folding Beijing Hao Jingfang Footsteps Harlan Ellison For the Sake of Grace Suzette Haden Elgin For Value Received Andrew J. Ouffutt For Whom the Bell Tolls Ernest Hemingway Forward the Foundation Isaac Asimov Foundation Isaac Asimov Foundation and Earth Isaac Asimov Foundation and Empire Isaac Asimov Foundation's Edge Isaac Asimov Fragments of a Hologram Rose William Gibson Frank Herbert Nebula Winners Fifteen Frederik Pohl The Expert Dreamers From A to Z, In The Chocolate Alphabet Harlan Ellison From the Government Printing Office Kris Neville Frozen Journey Philip K. Dick Funes the Memorious Jorge Luis Borges G. B. K.-A Many-Flavored Bird Harlan Ellison Gateway Frederik Pohl Gather Blue Roses Pamela Sargent Gathi Miram Allen deFord Getting Along James Blish Ghost in the Shell Shirow Masamune Ghost in the Shell vol.1.5: Human-Error Processor Shirow Masamune Ghost in the Shell vol.2: Man-Machine Interface Shirow Masamune Ghost of a Chance Theodore Sturgeon giANTS Edward Bryant Gift from the Stars Kate Wilhelm Giganto Maxia Kentaro Miura Gnomebody Harlan Ellison Go Toward the Light Harlan Ellison Go, Go, Go, Said the Bird Sonya Dorman God Emperor of Dune Frank Herbert Goldfish Bowl Robert A. Heinlein Gonna Roll the Bones Fritz Leiber Good Hunting Ken Liu Good News from the Vatican Robert Silverberg Gopher in the Gilly Harlan Ellison Grail Harlan Ellison Grave of the Fireflies Cheng Jingbo Gutter Gang Harlan Ellison Hadj Harlan Ellison Half-Life Paul Preuss Hamlet William Shakespeare Harry the Hare James B. Hemesath Hawksbill Station Robert Silverberg Heart of Darkness Joseph Conrad Heavyplanet Lee Gregor Heechee Rendezvous Frederik Pohl Heechee Treasures Frederik Pohl Hell Is the Absence of God Ted Chiang Heretics of Dune Frank Herbert High Weir Samuel R. Delany Hindsight: 480 Seconds Harlan Ellison Hinterlands William Gibson His Vegetable Pat Murphy Hitler Painted Roses Harlan Ellison Hobbies Clifford D. Simak Homecoming Ray Bradbury Homelanding Margaret Atwood Houston, Houston, Do You Read? James Tiptree, Jr. How Beautiful with Banners James Blish How's the Night Life on Cassalda? Harlan Ellison Huddling Place Clifford D. Simak Humpty Dumpty had a Great Fall Frank Belknap Hyperion Dan Simmons I Curse the Lesson and Bless the Knowledge Harlan Ellison I Will Fear No Evil Robert A. Heinlein I, Dreamer Walter M. Miller, Jr. I, Robot Isaac Asimov Ibn-Hakam al-Bokhari, Murdered in His Labyrinth Jorge Luis Borges Ichi-F Kazuto Tatsuta Idoru William Gibson If All Men Were Brothers, Would You Let One Marry Your Sister? Theodore Sturgeon I'm Looking for Kadak Harlan Ellison In Fear of K Harlan Ellison In Lonely Islands Harlan Ellison In Memoriam, J. F. K. Jorge Luis Borges In re Glover Leonard Tushnet In the Barn Piers Anthony In the Core Frederik Pohl In the Fourth Year of the War Harlan Ellison Incident in Moderan David R. Bunch Inferno, I, 32 Jorge Luis Borges Inferno: The World at War, 1939-1945 Max Hastings Interim Ray Bradbury Interlocking Pieces Molly Gloss Into the Wild Jon Krakauer Into Thin Air Jon Krakauer Invaders John Kessel Invasion Footnote Harlan Ellison Invisible Man Ralph Ellison Invisible Planets Hao Jingfang It Theodore Sturgeon It was Nothing-Really Theodore Sturgeon It's You! Theodore Sturgeon J. C. on the Dude Ranch Philip Jose Farmer Jack-in-the-Box Ray Bradbury Jane Doe #112 Harlan Ellison Jeffty is Five Harlan Ellison Jenny with Wings Kate Wilhelm Johnny Mnemonic William Gibson Jorry's Gap Theodore Sturgeon Judas John Brunner Julius Caesar William Shakespeare Jupiter Five Arthur C. Clarke Jurassic Park Michael Crichton Kafka and His Precursors Jorge Luis Borges Invisible Planets Ken Liu Keyboard Harlan Ellison Killdozer! Theodore Sturgeon Killing Bernstein Harlan Ellison King of the Hill Chad Oliver Kirinyaga Mike Resnick Kiss of Fire Harlan Ellison Knights to Move Fritz Leiber Knox Harlan Ellison Kyrie Poul Anderson Labyrinths Jorge Luis Borges Ladies and Gentlemen, This Is Your Crisis Kate Wilhelm Lamia Mutable M. John Harrison Land of the Great Horses R. A. Lafferty Last Train to Kankakee Robin Scott Laugh Track Harlan Ellison Leadership in Turbulent Times Doris Kearns Goodwin Lenny Isaac Asimov Let There Be Light Robert A. Heilein Liar! Isaac Asimov Life in Our Time Robert Bloch Life, the Universe and Everything Douglas Adams Life-Line Robert A. Heilein Liking What You See: A Documentary Ted Chiang Little Lost Robot Isaac Asimov Lollipop and the Tar Baby John Varley Lonley Women Are the Vessels of Time Harlan Ellison Looking for Company Frederik Pohl Lord of Light Roger Zelazny Lord of the Flies William Golding Lord Randy, My Son Joe L. Hensley Love Ain't Nothing but Sex Misspelled Harlan Ellison Lucy Comes To Stay Robert Bloch Madame Curie Eve Curie Making It All the Way into the Future on Gaxton Falls of the Red Planet Barry N. Malzberg Man of Letters Kate Wilhelm Man Plus Frederik Pohl Martin Fierro Jorge Luis Borges Martin the Warrior Brian Jacques Master and Commander Patrick O'Brian Mathoms from the Time Closet Gene Wolfe Mattimeo Brian Jacques Mealtime Harlan Ellison Medusa Theodore Sturgeon Mefisto in Onyx Harlan Ellison Microcosmic God Theodore Sturgeon Midnight in the Sunken Cathedral Harlan Ellison Midnight News Lisa Goldstein Mom Harlan Ellison Mona at Her Windows Harlan Ellison Mona Lisa Overdrive William Gibson Monitored Dreams & Strategic Cremations Bernard Wolfe Mono no Aware Ken Liu Monolog Philip Jose Farmer Monster vol.1 Naoki Urasawa Monster vol.2 Naoki Urasawa Monster vol.3 Naoki Urasawa Monster vol.4 Naoki Urasawa Monster vol.5 Naoki Urasawa Monster vol.6 Naoki Urasawa Monster vol.7 Naoki Urasawa Monster vol.8 Naoki Urasawa Monster vol.9 Naoki Urasawa More Than Human Theodore Sturgeon Moth Race Richard Hill Mountain Liu Cixin Mr. Costello, Hero Theodore Sturgeon Mrs. Bagley Goes to Mars Kate Wilhelm Mutations Jorge Luis Borges Nackles vr.1 Donald E. Westlake Nackles vr.2 Donald E. Westlake Nackles vr.2 Harlan Ellison Nausicaa of the Valley of the Wind vol.1 Hayao Miyazaki Nausicaa of the Valley of the Wind vol.2 Hayao Miyazaki Neither Your Jenny Nor Mine Harlan Ellison Neon Harlan Ellison Neuromancer William Gibson New Rose Hotel William Gibson Night Journey of the Dragon-Horse Xia Jia Night Meeting Ray Bradbury Night of Black Glass Harlan Ellison Nightfall Isaac Asimov Nightfall Robert Silverberg Night-Rise Katherine MacLean Nijigagara Holograph Inio Asano Nine Hundred Grandmothers R. A. Lafferty No Game for Children Harlan Ellison No Great Magic Fritz Leiber No Light in the Windows Kate Wilhelm Nothing for My Noon Meal Harlan Ellison Nova Samuel R. Delany O Ye of Little Faith Harlan Ellison Oddy and Id Alfred Bester Of Ants and Dinosaurs Liu Cixin On Exactitude and Science Jorge Luis Borges On the Downhill Slide Harlan Ellison On the Feasibility of Coal-Driven Power Stations O. R. Frisch On the Slab Harlan Ellison One Day in the Life of Ivan Denisovich Aleksandr Solzhenitsyn One for the Road Kate Wilhelm One Life, Furnished in Early Poverty Harlan Ellison One-Way Journey Miram Allen deFord Operating Systems in Depth Thomas W. Doeppner Operation Cassandra Miram Allen deFord Opium Harlan Ellison Other Worlds Frederik Pohl Out of All Them Bright Stars Nancy Kress Over the River and Through the Woods Clifford D. Simak Overlord Max Hastings Ozymandias Terry Car Paingod Harlan Ellison Paingod and Other Delusions Harlan Ellison Paladin of the Last Hour Harlan Ellison Parable of Cervantes and the Quixote Jorge Luis Borges Parable of the Palace Jorge Luis Borges Paradise Clifford D. Simak Paradiso, XXXI, 108 Jorge Luis Borges Partial Magic in the Quixote Jorge Luis Borges Pattern Recognition William Gibson Paulie Charmed the Sleeping Woman Harlan Ellison Permanent Record Edward Snowden Persona 3: Official Design Works Shigenori Soejima Persona 4 Arena: Official Design Works Shigenori Soejima Persona 4: Official Design Works Shigenori Soejima Philtre Tip Robert Bloch Picnic on Paradise Joanna Russ Pierre Menrad, Author of Don Quixote Jorge Luis Borges Planet Story Kate Wilhelm Planetes vol.1 Makoto Yukimura Planetes vol.2 Makoto Yukimura Player Piano Kurt Vonnegut Precession Edward Bryant Prelude to Foundation Isaac Asimov Presidents of War Michael Beschloss Pretty Maggie Moneyeyes Harlan Ellison Prince Myshkin, and Hold the Relish Harlan Ellison Prodigy Theodore Sturgeon Project Nightmare Robert A. Heinlein Pulling Hard Time Harlan Ellison Punky & The Yale Men Harlan Ellison Queen Emeraldas vol.1 Leiji Matsumoto Queen Emeraldas vol.2 Leiji Matsumoto Quick to Haste Miram Allen deFord Quicktime Harlan Ellison Radio Free Albemuth Philip K. Dick Ragnarok Jorge Luis Borges Rain, Rain, Go Away Harlan Ellison Rat James Patrick Kelly Reason Isaac Asimov Red Star, Winter Orbit Bruce Sterling Red Star, Winter Orbit William Gibson Redwall Brian Jacques Rendezvous with Rama Arthur C. Clarke Repent, Harlequin! Said the Ticktockman Harlan Ellison Requiem Robert A. Heilein Riders of the Purple Wage Philip Jose Farmer Riding the Dark Train Out Harlan Ellison Ringworld Larry Niven Riverworld Philip Jose Farmer Riverworld and Other Stories Philip Jose Farmer Roadside Picnic Arkady Strugatsky Roadside Picnic Boris Strugatsky Robbie Isaac Asimov Rock God Harlan Ellison Rocket Summer Ray Bradbury Runaround Isaac Asimov Sandkings George R. R. Martin Saturn, November 11th Harlan Ellison Scartaris, June 28th Harlan Ellison Schrodinger's Plague Greg Bear Schwarzschild Radius Connie Willis Second Foundation Isaac Asimov Seeing Harlan Ellison Selected Poems T. S. Eliot Selected Stories Theodore Sturgeon Sensible City Harlan Ellison Seraphim: 266613336 Wings Satoshi Kon Seventy-Two Letters Ted Chiang Sex and/or Mr. Morrison Carol Emshwiller Shadow, Shadow on the Wall Theodore Sturgeon Shall the Dust Praise Thee? Damon Knight Shatterday Harlan Ellison Shattered Like a Glass Goblin Harlan Ellison She's a Young Thing and Cannot Leaver Her Mother Harlan Ellison Shin Megami Tensei 4: Official Artworks Masayuki Doi Shoppe Keeper Harlan Ellison Silence Tadeusz Borowski Silent in Gehenna Harlan Ellison Silhouette Gene Wolfe Simulacrum Ken Liu Sir Gawain and the Green Knight J. R. R. Tolkien Skeleton Ray Bradbury Skunk Works Ben R. Rich Skunk Works Leo Janos Sky Lift Robert A. Heinlein Slippage Harlan Ellison Slow Sculpture Theodore Sturgeon Snow John Crowley So Long, and Thanks for All the Fish Douglas Adams Soft Monkey Harlan Ellison Solanin Inio Asano Solaris Stanislaw Lem Some Assembly Required Timothy S. Margush Somehow, I Don't Think We're in Kansas, Toto Harlan Ellison Somerset Dreams Kate Wilhelm Somerset Dreams and Other Fictions Kate Wilhelm Souls Joanna Russ Soundless Evening Lee Hoffman Speech Sound Octavia E. Butler Spook Country William Gibson Stable Strategies for Middle Management Eileen Gunn Stalingrad Antony Beevor Stalking the Nightmare Harlan Ellison Stand Still and Die Harlan Ellison Starship Troopers Robert A. Heinlein State Change Ken Liu State of Grace Kate Wilhelm Still-Life K. M. O'Donnell Stillwell and the American Experience in China 1911-1945 Barbara W. Tuchman Stoned Counsel H. H. Hollis Stories of Your Life and Others Ted Chiang Story of the Warrior and the Captive Maiden Jorge Luis Borges Story of Your Life Ted Chiang Strange Gifts Robert Silverberg Strange Wine Harlan Ellison Stranger in a Strange Land Robert A. Heinlein Stuffing Harlan Ellison Sturgeon is Alive and Well... Theodore Sturgeon Suicide Theodore Sturgeon Sun of China Liu Cixin Symbiosis Kate Wilhelm Take Care of Joey Theodore Sturgeon Taking Care of God Liu Cixin Tandy's Story Theodore Sturgeon Tauf Aleph Physillis Gotlieb Team of Rivals Doris Kearns Goodwin Tekkonkinkreet: Black and White Taiyo Matsumoto Tell Your Fortune Robert Bloch Test to Destruction Keith Laummer That Girl Who Knew What They Meant Theodore Sturgeon The [Widget], the [Wadget], and Boff Theodore Sturgeon The 10:00 Report is Brought to You By... Edward Bryant The 3 Most Important Things in Life Harlan Ellison The Absolutely Perfect Murder Miram Allen deFord The Adventure of Black Peter Arthur Conan Doyle The Adventure of Charles Augustus Milverton Arthur Conan Doyle The Adventure of the Gloria Scott Arthur Conan Doyle The Adventure of the Abbey Grange Arthur Conan Doyle The Adventure of the Beryl Coronet Arthur Conan Doyle The Adventure of the Blue Carbuncle Arthur Conan Doyle The Adventure of the Cardboard Box Arthur Conan Doyle The Adventure of the Copper Beeches Arthur Conan Doyle The Adventure of the Crooked Man Arthur Conan Doyle The Adventure of the Dancing Men Arthur Conan Doyle The Adventure of the Empty House Arthur Conan Doyle The Adventure of the Engineer's Thumb Arthur Conan Doyle The Adventure of the Final Problem Arthur Conan Doyle The Adventure of the Golden Pince-Nez Arthur Conan Doyle The Adventure of the Greek Interpreter Arthur Conan Doyle The Adventure of the Missing Three-Quarter Arthur Conan Doyle The Adventure of the Musgrave Ritual Arthur Conan Doyle The Adventure of the Naval Treaty Arthur Conan Doyle The Adventure of the Noble Bachelor Arthur Conan Doyle The Adventure of the Norwood Builder Arthur Conan Doyle The Adventure of the Priory School Arthur Conan Doyle The Adventure of the Reigate Squires Arthur Conan Doyle The Adventure of the Resident Patient Arthur Conan Doyle The Adventure of the Second Stain Arthur Conan Doyle The Adventure of the Silver Blaze Arthur Conan Doyle The Adventure of the Six Napoleons Arthur Conan Doyle The Adventure of the Solitary Cyclist Arthur Conan Doyle The Adventure of the Speckled Band Arthur Conan Doyle The Adventure of the Stockbroker's Clerk Arthur Conan Doyle The Adventure of the Yellow Face Arthur Conan Doyle The Age of Gold Frederik Pohl The Ajeri Diary Miram Allen deFord The Aleph Jorge Luis Borges The Aleph and Other Stories Jorge Luis Borges The Annals of the Heechee Frederik Pohl The Approach to Al-Mu'tasim Jorge Luis Borges The Argentine Writer and Tradition Jorge Luis Borges The Art of Computer Programming vol.1 Donald E. Knuth The Art of Nausicaa of the Valley of the Wind Hayao Miyazaki The Art of Persona 5 Shigenori Soejima The Art of Space Ron Miller The Avenger of Death Harlan Ellison The Babylon Lottery Jorge Luis Borges The Beast of Barsac Robert Bloch The Belonging Kind John Shirley The Belonging Kind William Gibson The Big Hunger Walter M. Miller, Jr. The Big Space Fuck Kurt Vonnegut, Jr. The Big Time Fritz Leiber The Black Cloud Fred Hoyle The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. Michael Bishop The Book of Skulls Robert Silverberg The Bookmaking Habits of Select Species Ken Liu The Boscombe Valley Mystery Arthur Conan Doyle The Boulevard of Broken Dreams Harlan Ellison The Boy Who Would Live Forever Frederik Pohl The Brains of Rats Michael Blumlein The Byrds Michael G. Coney The Captive Jorge Luis Borges The Cat Who Walks Through Walls Robert A. Heinlein The Catcher in the Rye J. D. Salinger The Cheese Stands Alone Harlan Ellison The Children Miram Allen deFord The Chrysalids John Wyndham The Circle Liu Cixin The Circular Ruins Jorge Luis Borges The Cistern Ray Bradbury The City of Silence Ma Boyong The Classic Horror Stories H. P. Lovecraft The Crackpots Harlan Ellison The Crowd Ray Bradbury The Dark Design Philip Jose Farmer The Dark Forest Liu Cixin The Daughter of the Tree Miram Allen deFord The Day After the Day the Martians Came Frederik Pohl The Day I Died Harlan Ellison The Day of the Triffids John Wyndham The Dead Man Jorge Luis Borges The Death of Schillinger Tadeusz Borowski The Deathbird Harlan Ellison The Demolished Man Alfred Bester The Diagnosis of Dr. Darqueangel Harlan Ellison The Difference Engine Bruce Sterling The Difference Engine William Gibson The Discarded Harlan Ellison The Dispossessed Ursula K. Le Guin The Divine Invasion Philip K. Dick The Doll-House James Cross The Dragon on the Bookshelf Harlan Ellison The Dragon on the Bookshelf Robert Silverberg The Dreaming Jewels Theodore Sturgeon The Dreams a Nightmare Dreams Harlan Ellison The Dune Encyclopedia Dr. Willis E. McNelly The Dwarf Ray Bradbury The Earth Men Ray Bradbury The Electric Kool-Aid Acid Test Tom Wolfe The Emissary Ray Bradbury The Encounter Kate Wilhelm The End Jorge Luis Borges The Evitable Conflict Isaac Asimov The Evolution of Human Science Ted Chiang The Executioner of the Malformed Children Harlan Ellison The Extraordinary Voyages of Amelie Bertrand Joanna Russ The Eyes of Heisenberg Frank Herbert The Face of Helene Bournouw Harlan Ellison The Fall of Hyperion Dan Simmons The Fearful Sphere of Pascal Jorge Luis Borges The Fellowship of the Ring J. R. R. Tolkien The Few, the Proud Harlan Ellison The Fish of Lijiang Chen Qiufan The Five Orange Pips Arthur Conan Doyle The Flower of Shazui Chen Qiufan The Forces that Crush Harlan Ellison The Forever War Joe Haldeman The Form of the Sword Jorge Luis Borges The Fountains of Paradise Arthur C. Clarke The Function of Dream Sleep Harlan Ellison The Funeral Kate Wilhelm The Fusion Bomb Kate Wilhelm The Garden of Forking Paths Jorge Luis Borges The Gateway Asteroid Frederik Pohl The Gateway Trip Frederik Pohl The Gernsback Continum William Gibson The Girl From Mars Robert Bloch The Goddess in the Ice Harlan Ellison The Godmakers Frank Herbert The Gods Lie. Kaori Ozaki The God's Script Jorge Luis Borges The Gods Themselves Isaac Asimov The Golden Helix Theodore Sturgeon The Golden Man Philip K. Dick The Great Gatsby F. Scott Fitzgerald The Green Morning Ray Bradbury The Guns of August Barbara W. Tuchman The Handler Damon Knight The Happy Breed John T. Sladek The Heart of the Other Side George Gamow The Henry Miller Dawn Patrol Philip Jose Farmer The Hitchhiker's Guide to the Galaxy Douglas Adams The Hobbit J. R. R. Tolkien The Home Planet Frederik Pohl The Hounds Kate Wilhelm The Hour That Stretches Harlan Ellison The House of Asterion Jorge Luis Borges The House the Blakeneys Built Avram Davidson The Immortal Jorge Luis Borges The Incredible Voyage Tristan Jones The Indian Spirit Guide Robert Bloch The Infinity Box Kate Wilhelm The Invasion Robert Willey The January Offensive Tadeusz Borowski The Jar Ray Bradbury The Jigsaw Man Larry Niven The Jungle Rot Kid on the Nod Philip Jose Farmer The Korean War Max Hastings The Lake Ray Bradbury The Lake Was Full of Artificial Things Karen Joy Fowler The Last Days of the Captain Kate Wilhelm The Last Generation? Miram Allen deFord The Lathe of Heaven Ursula K. Le Guin The Leaser of Two Evils Philip Jose Farmer The Library of Babel Jorge Luis Borges The Life of Anybody Robert Sheckley The Lingering Scent of Woodsmoke Harlan Ellison The Literomancer Ken Liu The Litigation Master and the Monkey King Ken Liu The Living Demons Robert Bloch The Locusts Ray Bradbury The Long Dark Tea-Time of the Soul Douglas Adams The Long Space Age Alexander MacDonald The Long Years Ray Bradbury The Longest Fall Liu Cixin The Lost World Michael Crichton The Lottery in Babylon Jorge Luis Borges The Lucky Strike Kim Stanley Robinson The Luggage Store Ray Bradbury The Maker Jorge Luis Borges The Malley System Miriam Allen deFord The Man in the High Castle Philip K. Dick The Man on the Threshold Jorge Luis Borges The Man Upstairs Ray Bradbury The Man Who Ended History: A Documentary Ken Liu The Man Who Lost the Sea Theodore Sturgeon The Man Who Rowed Christopher Columbus Ashore Harlan Ellison The Man Who Sold the Moon Robert A. Heinlein The Man Who Was Heavily into Revenge Harlan Ellison The Man Who Went to the Moon-Twice Howard Rodman The Man With English Horace L. Gold The Man with the Package Tadeusz Borowski The Man With the Twisted Lips Arthur Conan Doyle The Man without a Planet Kate Wilhelm The Manhattan Project Al Cimino The March of Folly Barbara W. Tuchman The Mark Gable Foundation Leo Szilard The Martian Ray Bradbury The Martian Chronicles Ray Bradbury The Menace from Earth Robert A. Heinlein The Merchants of Venus Frederik Pohl The Micro-Age Liu Cixin The Mile-Long Spaceship Kate Wilhelm The Milk of Paradise James Tiptree, Jr. The Million-Year Picnic Ray Bradbury The Miracle of the Broom Closet W. Norbert The Mirrors of Enigmas Jorge Luis Borges The Moon is a Harsh Mistress Robert A. Heinlein The Mountains of Sunset, the Mountains of Dawn Vonda N. McIntyre The Mountebank Jorge Luis Borges The Museum on Cyclops Avenue Harlan Ellison The Musicians Ray Bradbury The Naming of Names Ray Bradbury The New Atlantis Robert Silverberg The New Atlantis Ursula K. Le Guin The New York Review of Bird Harlan Ellison The Next in Line Ray Bradbury The Night That All Time Broke Out Brian W. Aldiss The Norton Book of Science Fiction Brian Attebery The Norton Book of Science Fiction Ursula K. Le Guin The October Country Ray Bradbury The Off Season Ray Bradbury The Old Man and the Sea Ernest Hemingway The Old Ones Ray Bradbury The Oldest Soldier Fritz Leiber The Original Hitchhiker Radio Scripts Douglas Adams The Original Illustrated Sherlock Holmes Arthur Conan Doyle The Other Death Jorge Luis Borges The Other Eye of Polyphemus Harlan Ellison The Outcast of Redwall Brian Jacques The Outpost Undiscovered by Tourists Harlan Ellison The Oxford Book of English Verse Christopher Ricks The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 Harlan Ellison The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 Harlan Ellison The Paper Menagerie Ken Liu The Patterns of Drone Theodore Sturgeon The People Who Walked On Tadeusz Borowski The Perfect Match Ken Liu The Peripheral William Gibson The Phantom of the Sewers Philip Jose Farmer The Place with No Name Harlan Ellison The Plot Jorge Luis Borges The Plot Is the Thing Robert Bloch The Private War of Private Jacob Joe Haldeman The Problem of the Sore Bridge-Among Others Philip Jose Farmer The Proud Tower Barbara W. Tuchman The Prowler in the City on the Edge of Forever Harlan Ellison The Recognition J. G. Ballard The Red Canary Kate Wilhelm The Red-Headed League Arthur Conan Doyle The Region Between Harlan Ellison The Regular Ken Liu The Resurgence of Miss Ankle-Strap Wedgie Harlan Ellison The Return of the King J. R. R. Tolkien The Right Stuff Tom Wolfe The Rise of Endymion Dan Simmons The Road Cormac McCarthy The Roads Must Roll Robert A. Heilein The Salmon of Doubt Douglas Adams The Season of Babies Miram Allen deFord The Secret Miracle Jorge Luis Borges The Sect of Phoenix Jorge Luis Borges The Settlers Ray Bradbury The Sex Opposite Theodore Sturgeon The Shape of the Sword Jorge Luis Borges The Shore Ray Bradbury The Silent Towns Ray Bradbury The Silver Corridor Harlan Ellison The Simple Way Clifford D. Simak The Singers W. Grey Walter The Sirens of Titan Kurt Vonnegut The Skills of Xanadu Theodore Sturgeon The Sky is Burning Harlan Ellison The Small Assaassin Ray Bradbury The Smiling Future Miram Allen deFord The Sound and the Fury William Faulkner The South Jorge Luis Borges The Space Merchants C. M. Kornbluth The Space Merchants Frederik Pohl The Stars My Destination Alfred Bester The Starseekers Frederik Pohl The Start of the End of It All Carol Emshwiller The Stochastic Man Robert Silverberg The Summer Night Ray Bradbury The Sun also Rises Ernest Hemingway The Superior Sex Miram Allen deFord The Supper Tadeusz Borowski The Sycthe Ray Bradbury The Taxpayer Ray Bradbury The Tell-Tale Heart and Other Writings Edgar Allan Poe The Tempest William Shakespeare The Test Stand Lee Corey The Test-Tube Creature, Afterward Joan Bernott The Theologians Jorge Luis Borges The Third Ear Curt Siodmak The Third Expedition Ray Bradbury The Three Stigmata of Palmer Eldritch Philip K. Dick The Three-Body Problem Liu Cixin The Tides of the Mind David Gelernter The Time Piece Kate Wilhelm The Transit of Venus Miram Allen deFord The Transmigration of Timothy Archer Philip K. Dick The Tree Lord of Imeten Tom Purdom The Trial Franz Kafka The Two Kings and the Two Labyrinths Jorge Luis Borges The Two Towers J. R. R. Tolkien The Ultimate Hitchhiker's Guide Douglas Adams The Universe of Robert Blake Harlan Ellison The Unspeakable Betrothal Robert Bloch The Very Last Day of a Good Woman Harlan Ellison The View from the Stars Walter M. Miller, Jr. The Village Kate Wilhelm The Visit Frederik Pohl The Voice of the Sonar in My Veriform Appendix Philip Jose Farmer The Volcano Philip Jose Farmer The Wages of Humanity Liu Cixin The Waiting Jorge Luis Borges The Wall and the Books Jorge Luis Borges The Wandering Earth Liu Cixin The War at Home Lewis Shiner The Warlord of Saturn's Moon Eleanor Aranason The Watchers Ray Bradbury The Watchful Poker Chip of H. Matisse Ray Bradbury The Waves Ken Liu The Westing Game Ellen Raskin The Whimper of Whipped Dogs Harlan Ellison The Will Walter M. Miller, Jr. The Wind Ray Bradbury The Wind Beyond the Mountains Harlan Ellison The Windup Girl Paolo Bacigalupi The Wine Has Been Left Open Too Long and the Memory Has Gone Flat Harlan Ellison The Winter Flies Fritz Leiber The Winter Market William Gibson The Witness Jorge Luis Borges The Women Men Don't See James Tiptree, Jr. The Wonderful Death of Dudley Stone Ray Bradbury The Word for World is Forrest Ursula K. Le Guin The World Inside Robert Silverberg The World of Professor Layton Jun Suzuki The World of Stone Tadeusz Borowski The Writing of the God Jorge Luis Borges The Year of the Jackpot Robert A. Heinlein The Year of the Rat Chen Qiufan The Yellow Rose Jorge Luis Borges The Zahir Jorge Luis Borges The Zimmermann Telegram Barbara W. Tuchman Theme of the Traitor and Hero Jorge Luis Borges There Was an Old Woman Ray Bradbury There Will Come Soft Rains Ray Bradbury They Shall Have Stars James Blish Things Lost Thomas M. Disch This Immortal Roger Zelazny This Way for the Gas, Ladies and Gentlemen Tadeusz Borowski Thorns Robert Silverberg Thousand Cranes Yasunari Kawabata Three Versions of Judas Jorge Luis Borges Throwback Miram Allen deFord Thunder and Roses Theodore Sturgeon Time Travel for Pedestrians Ray Nelson Tiny Ally Harlan Ellison Tissue James Sallis Tlon, Uqbar, Orbis Teritus Jorge Luis Borges To Be Continued Robert Silverberg To Explain to Mrs. Thompson Phillip Latham To Here and the Easel Theodore Sturgeon To Kill a Mockingbird Harper Lee To Open the Sky Robert Silverberg Toenails Jorge Luis Borges Tongtong's Summer Xia Jia Totenbuch A. Parra (y Figuerado) Touched With Fire Ray Bradbury Tower of Babylon Ted Chiang Tower of Glass Robert Silverberg Tracking Level Harlan Ellison Transcending Destiny Harlan Ellison Treasure Island Robert Lewis Stevenson Trigun Omnibus Yasuhiro Nightow Triss Brian Jacques Trouble With Ants Clifford D. Simak Try and Change the Past Fritz Leiber Twink Theodore Sturgeon Ubik Philip K. Dick Unaccompanied Sonata Orson Scott Card Uncle Einar Ray Bradbury Uncle Fremmis Theodore Sturgeon Underground Robert Bloch Understand Ted Chiang Unlocking the Air Ursula K. Le Guin Usher II Ray Bradbury Valerie Harlan Ellison Valery as Symbol Jorge Luis Borges VALIS Philip K. Dick Vaster than Empires and More Slow Ursula K. Le Guin Venus Plus X Theodore Sturgeon Vietnam: An Epic Tragedy, 1945-1975 Max Hastings Virtual Light William Gibson Visionary Harlan Ellison Walden; or, Life in the Woods Henry David Thoreau Wandering Island vol.1 Kenji Tsuruta Wandering Island vol.2 Kenji Tsuruta Wanted in Surgery Harlan Ellison Watchmen Alan Moore Water Is for Washing Robert A. Heinlein Watership Down Richard Adams Way in the Middle of the Air Ray Bradbury Way Station Clifford D. Simak We Yevgeny Zamyatin We See Things Differently Bruce Sterling Web of the City Harlan Ellison What Happened to Auguste Clarot? Larry Eisenberg What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 Harlan Ellison What's It Like Out There? Edmond Hamilton When Auld's Acquaintance is Forgot Harlan Ellison When I was a Hired Gun Harlan Ellison When I Was Miss Dow Sonya Dorman When it Changed Joanna Russ When the Bentfin Boomer Boys on Old New Alabama Richard A. Lupoff When the Change-Winds Blow Fritz Leiber Where Have You Been, Billy Boy, Billy Boy? Kate Wilhelm Where I Shall Dwell in the Next World Harlan Ellison Where Late the Sweet Birds Sang Kate Wilhelm With a Finger in My I David Gerrold With Her Eyes Liu Cixin With Virgin Oddum at the East Pole Harlan Ellison Working with the Little People Harlan Ellison Would You Do It for a Penny Harlan Ellison Xenogenesis Miriam Allen deFord Yeager Chuck Yeager Yeager Leo Janos Ylla Ray Bradbury You Triflin' Skunk Walter M. Miller, Jr. Zero Gee Ben Bova Zero History William Gibson ================================================ FILE: tests/data/books.tsv ================================================ 1984 science fiction 1950 328 2001: A Space Odyssey science fiction 1968 221 20th Century Boys vol.1 science fiction 2018 413 20th Century Boys vol.2 science fiction 2018 412 20th Century Boys vol.3 science fiction 2019 410 20th Century Boys vol.4 science fiction 2019 416 20th Century Boys vol.5 science fiction 2019 422 20th Century Boys vol.6 science fiction 2019 456 A Canticle for Leibowitz science fiction 1959 338 A Case of Conscience science fiction 1958 188 A Clash of Cymbals science fiction 1959 199 A Clockwork Orange science fiction 1962 139 A Farewell to Arms american lit 1929 332 A Life for the Stars science fiction 1962 147 A Scanner Darkly science fiction 1977 217 A Time of Changes science fiction 1975 205 A Tour of C++ 2nd textbook 2018 238 Absalom, Absalom! american lit 1936 303 Again, Dangerous Visions science fiction 1972 830 Akira vol.1 science fiction 2010 363 Akira vol.2 science fiction 2010 301 Akira vol.3 science fiction 2010 282 Akira vol.4 science fiction 2010 394 Akira vol.5 science fiction 2011 413 Akira vol.6 science fiction 2011 434 Algorithms 4th textbook 2011 959 All Tomorrow's Parties science fiction 1999 339 And Chaos Died science fiction 1970 189 Angry Candy science fiction 1988 324 Animal Farm british lit 1956 139 Approaching Oblivion science fiction 1974 164 Army of None history 2018 436 Battle for the Mind informative 1954 350 Beowulf fantasy 1994 92 Beyond the Blue Event Horizon science fiction 1980 309 Bible and Sword history 1984 346 Blame! vol.1 science fiction 2016 348 Blame! vol.2 science fiction 2016 374 Blame! vol.3 science fiction 2017 352 Blame! vol.4 science fiction 2017 367 Blame! vol.5 science fiction 2017 334 Blame! vol.6 science fiction 2017 326 Blue Spring fiction 2004 213 Brain Wave science fiction 1954 166 Brave New World science fiction 1932 259 Burning Chrome science fiction 1986 191 C Primer Plus 5th textbook 2005 959 C++ Primer 5th textbook 2013 938 Capitalism Without Capital economics 2018 278 Captain Harlock: The Classic Collection vol.1 science fiction 2018 396 Captain Harlock: The Classic Collection vol.2 science fiction 2018 397 Captain Harlock: The Classic Collection vol.3 science fiction 2019 392 Catch-22 american lit 1955 453 Caviar science fiction 1955 182 Changewar science fiction 1983 198 Chapterhouse: Dune science fiction 1985 436 Childhood's End science fiction 1953 212 Children of Dune science fiction 1976 408 Children of the Sea vol.1 fiction 2013 316 Children of the Sea vol.2 fiction 2013 315 Children of the Sea vol.3 fiction 2013 334 Children of the Sea vol.4 fiction 2013 324 Children of the Sea vol.5 fiction 2013 329 City science fiction 1952 267 Colossus history 2006 462 Conversations With Jorge Luis Borges interviews 1968 144 Count Zero science fiction 1986 246 Crome Yellow british lit 1921 174 Dandelion Wine american lit 1957 239 Dangerous Visions science fiction 1967 598 Death and the Penguin mystery 1996 228 Deathbird Stories science fiction 1975 347 Death's End science fiction 2016 604 Destined for War history 2017 364 Dirk Gently's Holistic Detective Agency science fiction 1987 306 Distrust That Particular Flavor essays 2012 255 Do Androids Dream of Electric Sheep? science fiction 1968 244 Doctor Zhivago east euro lit 1957 456 Don Quixote adventure 1950 940 Double Star science fiction 1956 243 Downward to the Earth science fiction 1970 181 Dr. Bloodmoney science fiction 1965 298 Dune science fiction 1965 883 Dune Messiah science fiction 1969 279 Dying Inside science fiction 1972 200 Earthman, Come Home science fiction 1955 256 Earthman, Go Home! science fiction 1962 191 Emanon vol.1: Memories of Emanon science fiction 2019 190 Emanon vol.2: Emanon Wanderer pt.1 science fiction 2019 213 Emanon vol.3: Emanon Wanderer pt.2 science fiction 2019 233 Empire Star science fiction 1966 102 Ender's Game science fiction 1977 324 Endless Frontier history 1997 527 Endymion science fiction 1995 563 Eniac history 1999 262 Explorers of Space science fiction 1975 253 Fahrenheit 451 science fiction 1953 190 Fault-Tolerant Computer System Designs textbook 1996 550 Fiasco science fiction 1987 322 Ficciones fiction 1956 174 Flow My Tears, the Policeman Said science fiction 1974 231 Flowers for Algernon science fiction 1966 216 For Whom the Bell Tolls american lit 1940 507 Forward the Foundation science fiction 1993 435 Foundation science fiction 1951 296 Foundation and Earth science fiction 1986 494 Foundation and Empire science fiction 1952 282 Foundation's Edge science fiction 1982 426 Gateway science fiction 1977 313 Ghost in the Shell science fiction 2009 348 Ghost in the Shell vol.2: Man-Machine Interface science fiction 2010 306 Ghost in the Shell vol.1.5: Human-Error Processor science fiction 2007 176 Giganto Maxia fantasy 2016 232 God Emperor of Dune science fiction 1981 423 Hamlet tragedy 1599 287 Hawksbill Station science fiction 1968 185 Heart of Darkness east euro lit 1899 166 Heechee Rendezvous science fiction 1984 331 Heretics of Dune science fiction 1984 480 Houston, Houston, Do You Read? science fiction 1976 92 Hyperion science fiction 1989 482 I Will Fear No Evil science fiction 1970 512 I, Robot science fiction 1950 192 Ichi-F nonfiction 2017 550 Idoru science fiction 1996 383 Inferno: The World at War, 1939-1945 informative 2012 729 Into the Wild nonfiction 1996 207 Into Thin Air nonfiction 1997 404 Invisible Man american lit 1952 581 Invisible Planets science fiction 2016 393 Julius Caesar tragedy 1599 209 Jurassic Park science fiction 1990 399 Labyrinths fiction 2007 256 Leadership in Turbulent Times history 2018 473 Life, the Universe and Everything science fiction 1982 162 Lord of Light science fiction 1967 296 Lord of the Flies british lit 1954 208 Love Ain't Nothing but Sex Misspelled science fiction 1968 380 Madame Curie history 1939 390 Man Plus science fiction 1976 277 Martin the Warrior fantasy 1994 376 Master and Commander adventure 1970 408 Mattimeo fantasy 1990 432 Mona Lisa Overdrive science fiction 1988 308 Monster vol.1 thriller 2014 422 Monster vol.2 thriller 2014 398 Monster vol.3 thriller 2015 430 Monster vol.4 thriller 2015 412 Monster vol.5 thriller 2015 404 Monster vol.6 thriller 2015 400 Monster vol.7 thriller 2016 410 Monster vol.8 thriller 2016 424 Monster vol.9 thriller 2016 470 More Than Human science fiction 1953 188 Nausicaa of the Valley of the Wind vol.1 fantasy 2012 548 Nausicaa of the Valley of the Wind vol.2 fantasy 2012 533 Nebula Winners Fifteen science fiction 1981 223 Neuromancer science fiction 1984 271 Nightfall science fiction 1990 339 Nijigagara Holograph fiction 2015 200 Nova science fiction 1968 215 One Day in the Life of Ivan Denisovich east euro lit 1962 210 Operating Systems in Depth textbook 2011 444 Overlord history 1984 462 Paingod and Other Delusions science fiction 1965 157 Pattern Recognition science fiction 2003 356 Permanent Record history 2019 340 Persona 3: Official Design Works art 2006 141 Persona 4 Arena: Official Design Works art 2012 176 Persona 4: Official Design Works art 2008 191 Picnic on Paradise science fiction 1968 157 Planetes vol.1 science fiction 2015 524 Planetes vol.2 science fiction 2016 524 Player Piano science fiction 1952 320 Prelude to Foundation science fiction 1988 434 Presidents of War history 2018 740 Queen Emeraldas vol.1 science fiction 2016 415 Queen Emeraldas vol.2 science fiction 2017 423 Radio Free Albemuth science fiction 1985 214 Redwall fantasy 1986 333 Rendezvous with Rama science fiction 1973 243 Riders of the Purple Wage science fiction 1992 216 Ringworld science fiction 1970 288 Riverworld and Other Stories science fiction 1979 264 Roadside Picnic science fiction 1972 209 Second Foundation science fiction 1953 279 Selected Poems american lit 1954 114 Selected Stories science fiction 2000 439 Seraphim: 266613336 Wings science fiction 2015 268 Shatterday science fiction 1980 332 Shin Megami Tensei 4: Official Artworks art 2013 208 Sir Gawain and the Green Knight fantasy 1975 212 Skunk Works history 1994 372 Slippage science fiction 1997 359 So Long, and Thanks for All the Fish science fiction 1984 214 Solanin fiction 2008 432 Solaris science fiction 1961 223 Some Assembly Required informative 2012 611 Somerset Dreams and Other Fictions science fiction 1979 174 Souls fantasy 1982 84 Spook Country science fiction 2007 480 Stalingrad history 1998 493 Stalking the Nightmare science fiction 1982 301 Starship Troopers science fiction 1959 335 Stillwell and the American Experience in China 1911-1945 history 1971 794 Stories of Your Life and Others science fiction 2002 281 Strange Gifts science fiction 1975 191 Strange Wine science fiction 1979 316 Stranger in a Strange Land science fiction 1961 438 Sturgeon is Alive and Well... science fiction 1971 207 Team of Rivals history 2005 757 Tekkonkinkreet: Black and White fiction 2007 614 The Aleph and Other Stories fiction 1998 210 The Annals of the Heechee science fiction 1987 341 The Art of Computer Programming vol.1 textbook 1997 652 The Art of Nausicaa of the Valley of the Wind art 2007 207 The Art of Persona 5 art 2017 447 The Art of Space art 2014 224 The Big Time science fiction 1958 184 The Book of Skulls science fiction 1972 222 The Boy Who Would Live Forever science fiction 2004 452 The Cat Who Walks Through Walls science fiction 1985 388 The Catcher in the Rye american lit 1945 214 The Chrysalids science fiction 1955 200 The Classic Horror Stories horror 2013 487 The Dark Forest science fiction 2015 512 The Day of the Triffids science fiction 1951 191 The Demolished Man science fiction 1954 175 The Difference Engine science fiction 1991 429 The Dispossessed science fiction 1974 311 The Divine Invasion science fiction 1981 260 The Dreaming Jewels science fiction 1950 174 The Dune Encyclopedia encyclopedia 1985 526 The Electric Kool-Aid Acid Test informative 1968 416 The Expert Dreamers science fiction 1962 248 The Eyes of Heisenberg science fiction 1966 158 The Fall of Hyperion science fiction 1990 518 The Fellowship of the Ring fantasy 1954 458 The Forever War science fiction 1974 254 The Fountains of Paradise science fiction 1980 305 The Gateway Trip science fiction 1990 245 The Godmakers science fiction 1972 221 The Gods Lie. fiction 2016 216 The Gods Themselves science fiction 1972 288 The Great Gatsby american lit 1952 180 The Guns of August history 1962 606 The Hitchhiker's Guide to the Galaxy science fiction 1979 215 The Hobbit fantasy 1937 305 The Incredible Voyage nonfiction 1977 390 The Infinity Box science fiction 1975 272 The Korean War history 1987 389 The Lathe of Heaven science fiction 1971 175 The Living Demons horror 1967 156 The Long Dark Tea-Time of the Soul science fiction 1988 307 The Long Space Age history 2017 258 The Lost World science fiction 1995 430 The Man in the High Castle science fiction 1962 259 The Man Who Sold the Moon science fiction 1951 267 The Manhattan Project history 2016 187 The March of Folly history 1984 447 The Martian Chronicles science fiction 1950 181 The Menace from Earth science fiction 1962 189 The Mile-Long Spaceship science fiction 1963 160 The Moon is a Harsh Mistress science fiction 1966 382 The New Atlantis science fiction 1975 182 The Norton Book of Science Fiction science fiction 1993 861 The October Country science fiction 1956 306 The Old Man and the Sea american lit 1952 127 The Original Hitchhiker Radio Scripts science fiction 1985 248 The Original Illustrated Sherlock Holmes mystery 1976 636 The Outcast of Redwall fantasy 1995 367 The Oxford Book of English Verse british lit 1999 668 The Paper Menagerie science fiction 2016 450 The Peripheral science fiction 2014 486 The Proud Tower history 1966 615 The Return of the King fantasy 1955 466 The Right Stuff nonfiction 1970 352 The Rise of Endymion science fiction 1997 709 The Road thriller 2006 287 The Salmon of Doubt fiction 2002 299 The Sirens of Titan science fiction 1959 224 The Sound and the Fury american lit 1929 326 The Space Merchants science fiction 1953 216 The Stars My Destination science fiction 1956 234 The Stochastic Man science fiction 1976 240 The Sun also Rises american lit 1926 251 The Tell-Tale Heart and Other Writings horror 1982 419 The Tempest tragedy 1599 177 The Third Ear science fiction 1971 254 The Three Stigmata of Palmer Eldritch science fiction 1964 230 The Three-Body Problem science fiction 2014 399 The Tides of the Mind nonfiction 2016 267 The Transmigration of Timothy Archer science fiction 1991 255 The Tree Lord of Imeten science fiction 1966 152 The Trial east euro lit 1925 271 The Two Towers fantasy 1954 398 The Ultimate Hitchhiker's Guide science fiction 2005 815 The View from the Stars science fiction 1965 192 The Wandering Earth science fiction 2013 478 The Westing Game mystery 1978 182 The Windup Girl science fiction 2015 466 The World Inside science fiction 1970 167 The World of Professor Layton art 2015 191 The Zimmermann Telegram history 1966 225 They Shall Have Stars science fiction 1956 181 This Immortal science fiction 1966 184 This Way for the Gas, Ladies and Gentlemen east euro lit 1959 180 Thorns science fiction 1967 222 Thousand Cranes asian lit 1965 144 To Kill a Mockingbird american lit 1960 376 To Open the Sky science fiction 1967 222 Tower of Glass science fiction 1971 184 Treasure Island adventure 1882 202 Trigun Omnibus science fiction 2013 691 Triss fantasy 2002 389 Ubik science fiction 1969 216 VALIS science fiction 1991 241 Venus Plus X science fiction 1960 160 Vietnam: An Epic Tragedy, 1945-1975 history 2018 857 Virtual Light science fiction 1993 352 Walden; or, Life in the Woods essays 1854 216 Wandering Island vol.1 fiction 2016 198 Wandering Island vol.2 fiction 2018 190 Watchmen science fiction 1986 414 Watership Down fantasy 1973 478 Way Station science fiction 1963 190 We science fiction 1924 226 Web of the City thriller 1958 284 What's It Like Out There? science fiction 1974 320 Where Late the Sweet Birds Sang science fiction 1976 207 Xenogenesis science fiction 1969 231 Yeager history 1985 331 Zero History science fiction 2010 529 ================================================ FILE: tests/data/collected.tsv ================================================ !!!The!!Teddy!Crazy!!Show!!! Stalking the Nightmare 14 (Learning About) Machine Sex The Norton Book of Science Fiction 16 ...the World, as we Know 't The Norton Book of Science Fiction 16 2004, or Thereabouts The Norton Book of Science Fiction 5 A Biography of Tadeo Isidoro Cruz (1829-1874) The Aleph and Other Stories 4 A Brief History of the Trans-Pacific Tunnel The Paper Menagerie and Other Stories 19 A Case of Identity The Original Illustrated Sherlock Holmes 12 A Day at Harmenz This Way for the Gas, Ladies and Gentlemen 32 A Deskful of Girls Changewar 44 A Dialog About A Dialog The Aleph and Other Stories 1 A Dialog Between Dead Men The Aleph and Other Stories 3 A Feast of Demons The Expert Dreamers 26 A Few Things I Know About While Away The Norton Book of Science Fiction 13 A Hundred Ghosts Parade Tonight Invisible Planets 20 A is for Automation The Mile-Long Spaceship 17 A Midwinter's Tale The Norton Book of Science Fiction 13 A Momentary Taste of Being The New Atlantis 174 A Mouse in the Walls of the Global Village Again, Dangerous Visions 15 A New Refutation of Time Labyrinths 20 A Note on (toward) Bernard Shaw Labyrinths 4 A Path Through the Darkness Love Ain't Nothing but Sex Misspelled 14 A Prayer for No One's Enemies Love Ain't Nothing but Sex Misspelled 21 A Problem Labyrinths 2 A Problem The Aleph and Other Stories 2 A Scandal in Bohemia The Original Illustrated Sherlock Holmes 15 A Toy for Juliette Dangerous Visions 15 A True Story This Way for the Gas, Ladies and Gentlemen 4 A Visit This Way for the Gas, Ladies and Gentlemen 3 A Way of Thinking Selected Stories 29 Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W Deathbird Stories 40 Adrift on the Policy Level The Expert Dreamers 24 Aesop City 42 After the Days of Dead-Eye 'Dee The Norton Book of Science Fiction 11 All in Good Time Xenogensis 10 All the Birds Come Home to Roost Shatterday 18 All the Flavors The Paper Menagerie and Other Stories 89 All the Lies Lies That Are My Life Shatterday 58 All The People Strange Gifts 12 All the Sound of Fear Earthman, Go Home! 12 Along the Scenic Route Deathbird Stories 14 Alpha Ralpha Boulevard The Norton Book of Science Fiction 25 Amateur in Chancery The Expert Dreamers 18 America The Norton Book of Science Fiction 24 An Advanced Readers' Picture Book of Comparative Cognition The Paper Menagerie and Other Stories 15 An Examination of the Work of Herbert Quain Ficciones 6 And the Angels Sing The Norton Book of Science Fiction 17 And the Sea Like Mirrors Again, Dangerous Visions 20 Andover and the Android The Mile-Long Spaceship 13 Anybody Else Like Me? The View from the Stars 17 Anywhere But Here, With Anybody But You Slippage 8 April Fools' Day Forever The Infinity Box 58 Argumentum Ornithologicum The Aleph and Other Stories 1 As Simple As That The Norton Book of Science Fiction 11 At the End of the Orbit The Expert Dreamers 20 At the Mouse Circus Deathbird Stories 10 Aunt Parnetta's Electric Blisters The Norton Book of Science Fiction 5 Auschwitz, Our Home (A Letter) This Way for the Gas, Ladies and Gentlemen 45 Auto-De-Fe Dangerous Visions 10 Avatars of the Tortoise Labyrinths 7 Averroes' Search Labyrinths 8 Averroes' Search The Aleph and Other Stories 10 Aye, and Gomorrah... Dangerous Visions 14 Balanced Ecology The Norton Book of Science Fiction 17 Basilisk Deathbird Stories 22 Battle Without Banners Love Ain't Nothing but Sex Misspelled 14 Battlefield Earthman, Go Home! 12 Beachhead Explorers of Space 25 Beauty's Beast The Living Demons 17 Bed Sheets are White Again, Dangerous Visions 8 Bettyann Strange Gifts 44 Bianca's Hands Selected Stories 9 Big Joe and the Nth Generation The View from the Stars 19 Blabbermouth Caviar 28 Black Bargain The Living Demons 16 Blank? Stalking the Nightmare 8 Bleeding Stones Deathbird Stories 8 Blind Bird, Blind Bird, Go Away From Me! Love Ain't Nothing but Sex Misspelled 22 Blood Bank The View from the Stars 46 Blot Again, Dangerous Visions 15 Blowups Happen The Man Who Sold the Moon 54 Borges and I Labyrinths 2 Borges and I The Aleph and Other Stories 2 Bounty Again, Dangerous Visions 7 Brass and Gold (or Horse and Zeppelin in Beverly Hills) Riverworld and Other Stories 18 Bright Eyes Paingod and Other Delusions 12 Bright Segment Caviar 28 Bright Segment Selected Stories 25 Broken Glass Angry Candy 12 Brownshoes Sturgeon is Alive and Well... 12 Burning Chrome Burning Chrome 23 By His Bootstraps The Menace from Earth 49 Call Girl Invisible Planets 12 Camps Nebula Winners Fifteen 29 Carcinoma Angels Dangerous Visions 15 Catch That Rabbit I, Robot 15 Catman Approaching Oblivion 34 Census City 35 Chain Reaction The Expert Dreamers 16 Chained to the Fast Lane in the Red Queen's Race Angry Candy 16 Chatting with Anubis Slippage 8 Ching Witch! Again, Dangerous Visions 24 Christ, Old Student in a New School Again, Dangerous Visions 9 Chuck Berry, Won't You Please Come Home Again, Dangerous Visions 12 City City 34 Cold Friend Approaching Oblivion 11 Collecting Team Explorers of Space 18 Columbus Was a Dope The Menace from Earth 4 Come to the Party The Collected Stories of Frank Herbert 21 Comes Now the Power The Norton Book of Science Fiction 5 Commuter's Problem Earthman, Go Home! 22 Corpse Deathbird Stories 12 Count the Clock That Tells the Time Shatterday 22 Covered Mirrors The Aleph and Other Stories 2 Crate Sturgeon is Alive and Well... 14 Crazy as a Soup Sandwich Slippage 48 Croatoan Strange Wine 18 Crucifixus Etiam The View from the Stars 18 Curse 5.0 The Wandering Earth 23 Damnation Morning Changewar 19 Danger-Human! Strange Gifts 21 Daniel White for the Greater Good Love Ain't Nothing but Sex Misspelled 13 Darkness Upon the Face of the Deep Slippage 16 Day Million The Norton Book of Science Fiction 5 Deal From the Bottom Earthman, Go Home! 7 Death and the Compass Ficciones 14 Death and the Compass Labyrinths 12 Deeper than the Darkness Paingod and Other Delusions 20 Delia Elena San Marco The Aleph and Other Stories 1 Delusion for a Dragon Slayer Deathbird Stories 18 Deutsches Requiem Labyrinths 7 Deutsches Requiem The Aleph and Other Stories 7 Devourer The Wandering Earth 46 Distant Signals The Norton Book of Science Fiction 13 Division by Zero Stories of Your Life and Others 20 Django Shatterday 12 Djinn, No Chaser Stalking the Nightmare 22 Dogfight Burning Chrome 24 Do-It-Yourself Earthman, Go Home! 14 Dreamtigers The Aleph and Other Stories 1 Dumb Waiter The View from the Stars 34 Each an Explorer Explorers of Space 18 Ecowarewness Approaching Oblivion 2 Eidolons Angry Candy 18 Elbow Room The Norton Book of Science Fiction 15 Elegy Labyrinths 2 Elouise and the Doctors of the Planet Pergamon Again, Dangerous Visions 19 Emissary from Hamelin Strange Wine 13 Emma Zunz Labyrinths 6 Emma Zunz The Aleph and Other Stories 7 Empire of the Sun Again, Dangerous Visions 8 Encounter With A Hick Dangerous Visions 7 Enemy Mine Nebula Winners Fifteen 64 Epilogue City 13 Epiphany for Aliens Again, Dangerous Visions 11 Ernest and the Machine God Deathbird Stories 20 Erotophobia Approaching Oblivion 7 Ersatz Dangerous Visions 9 Escape! I, Robot 21 Escapegoat Angry Candy 4 Eutopia Dangerous Visions 23 Evensong Dangerous Visions 10 Everything and Nothing Labyrinths 3 Everything and Nothing The Aleph and Other Stories 3 Evidence I, Robot 23 Exploration Team Explorers of Space 58 Exposures The Norton Book of Science Fiction 12 Eye of the Beholder Again, Dangerous Visions 15 Faith of our Fathers Dangerous Visions 38 Fear is a Cold Black The Mile-Long Spaceship 25 Feather Tigers The Norton Book of Science Fiction 7 Featherbed on Chlyntha Xenogensis 17 Final Trophy Stalking the Nightmare 12 Flies Dangerous Visions 13 Flop Sweat Shatterday 18 Folding Beijing Invisible Planets 44 Footsteps Angry Candy 14 For the Sake of Grace The Norton Book of Science Fiction 20 For Value Received Again, Dangerous Visions 18 Fragments of a Hologram Rose Burning Chrome 7 From A to Z, In The Chocolate Alphabet Strange Wine 24 From the Government Printing Office Dangerous Visions 9 Frozen Journey The Norton Book of Science Fiction 16 Funes the Memorious Labyrinths 8 Funes the Memorious Ficciones 10 G. B. K.-A Many-Flavored Bird Love Ain't Nothing but Sex Misspelled 11 Gather Blue Roses The Norton Book of Science Fiction 5 Gathi Xenogensis 7 Getting Along Again, Dangerous Visions 32 Ghost of a Chance Caviar 20 giANTS Nebula Winners Fifteen 20 Gift from the Stars The Mile-Long Spaceship 17 Gnomebody Earthman, Go Home! 7 Go Toward the Light Slippage 10 Go, Go, Go, Said the Bird Dangerous Visions 9 Goldfish Bowl The Menace from Earth 29 Gonna Roll the Bones Dangerous Visions 26 Good Hunting The Paper Menagerie and Other Stories 23 Good News from the Vatican The Norton Book of Science Fiction 8 Gopher in the Gilly Stalking the Nightmare 6 Grail Stalking the Nightmare 28 Grave of the Fireflies Invisible Planets 18 Gutter Gang Web of the City 25 Hadj Earthman, Go Home! 5 Half-Life The Norton Book of Science Fiction 14 Harry the Hare Again, Dangerous Visions 5 Heavyplanet The Expert Dreamers 13 Heechee Treasures The Gateway Trip 19 Hell Is the Absence of God Stories of Your Life and Others 32 High Weir The Norton Book of Science Fiction 18 Hindsight: 480 Seconds Approaching Oblivion 6 Hinterlands Burning Chrome 22 His Vegetable The Norton Book of Science Fiction 5 Hitler Painted Roses Strange Wine 18 Hobbies City 28 Homecoming The October Country 17 Homelanding The Norton Book of Science Fiction 3 How Beautiful with Banners The Norton Book of Science Fiction 9 How's the Night Life on Cassalda? Shatterday 18 Huddling Place City 23 Humpty Dumpty had a Great Fall Strange Gifts 27 I Curse the Lesson and Bless the Knowledge Love Ain't Nothing but Sex Misspelled 14 I, Dreamer The View from the Stars 12 Ibn-Hakam al-Bokhari, Murdered in His Labyrinth The Aleph and Other Stories 10 If All Men Were Brothers, Would You Let One Marry Your Sister? Dangerous Visions 49 I'm Looking for Kadak Approaching Oblivion 27 In Fear of K Strange Wine 16 In Lonely Islands Earthman, Go Home! 5 In Memoriam, J. F. K. The Aleph and Other Stories 1 In re Glover Again, Dangerous Visions 13 In the Barn Again, Dangerous Visions 37 In the Core The Gateway Trip 9 In the Fourth Year of the War Shatterday 14 Incident in Moderan Dangerous Visions 6 Inferno, I, 32 Labyrinths 1 Inferno, I, 32 The Aleph and Other Stories 1 Interim The Martian Chronicles 1 Interlocking Pieces The Norton Book of Science Fiction 6 Invaders The Norton Book of Science Fiction 20 Invasion Footnote Stalking the Nightmare 8 Invisible Planets Invisible Planets 20 It Selected Stories 25 It was Nothing-Really Sturgeon is Alive and Well... 15 It's You! Sturgeon is Alive and Well... 10 J. C. on the Dude Ranch Riverworld and Other Stories 16 Jack-in-the-Box The October Country 20 Jane Doe #112 Slippage 12 Jeffty is Five Shatterday 28 Jenny with Wings The Mile-Long Spaceship 13 Johnny Mnemonic Burning Chrome 22 Jorry's Gap Sturgeon is Alive and Well... 12 Judas Dangerous Visions 12 Jupiter Five Explorers of Space 38 Kafka and His Precursors Labyrinths 3 Keyboard Slippage 7 Killdozer! Selected Stories 70 Killing Bernstein Strange Wine 18 King of the Hill Again, Dangerous Visions 20 Kirinyaga The Norton Book of Science Fiction 17 Kiss of Fire Approaching Oblivion 11 Knights to Move Changewar 13 Knox Approaching Oblivion 15 Kyrie Explorers of Space 15 Kyrie The Norton Book of Science Fiction 10 Ladies and Gentlemen, This Is Your Crisis Somerset Dreams and Other Fictions 16 Lamia Mutable Again, Dangerous Visions 10 Land of the Great Horses Dangerous Visions 12 Last Train to Kankakee Again, Dangerous Visions 11 Laugh Track Angry Candy 22 Lenny The Expert Dreamers 18 Let There Be Light The Man Who Sold the Moon 19 Liar! I, Robot 16 Life in Our Time The Living Demons 9 Life-Line The Man Who Sold the Moon 22 Liking What You See: A Documentary Stories of Your Life and Others 38 Little Lost Robot I, Robot 26 Lollipop and the Tar Baby The Norton Book of Science Fiction 19 Lonley Women Are the Vessels of Time Strange Wine 8 Looking for Company The Gateway Trip 13 Lord Randy, My Son Dangerous Visions 18 Lucy Comes To Stay The Living Demons 6 Making It All the Way into the Future on Gaxton Falls of the Red Planet The Norton Book of Science Fiction 4 Man of Letters The Infinity Box 19 Martin Fierro The Aleph and Other Stories 2 Mathoms from the Time Closet Again, Dangerous Visions 12 Mealtime Earthman, Go Home! 11 Medusa Caviar 26 Mefisto in Onyx Slippage 46 Microcosmic God Caviar 34 Midnight in the Sunken Cathedral Slippage 10 Midnight News The Norton Book of Science Fiction 11 Mom Strange Wine 22 Mona at Her Windows Love Ain't Nothing but Sex Misspelled 5 Monitored Dreams & Strategic Cremations Again, Dangerous Visions 67 Mono no Aware The Paper Menagerie and Other Stories 21 Monolog Riverworld and Other Stories 8 Moth Race Again, Dangerous Visions 13 Mountain The Wandering Earth 48 Mr. Costello, Hero Selected Stories 26 Mrs. Bagley Goes to Mars Somerset Dreams and Other Fictions 10 Mutations The Aleph and Other Stories 1 Nackles vr.1 Slippage 8 Nackles vr.2 Slippage 31 Neither Your Jenny Nor Mine Love Ain't Nothing but Sex Misspelled 44 Neon Deathbird Stories 12 New Rose Hotel Burning Chrome 14 Night Journey of the Dragon-Horse Invisible Planets 20 Night Meeting The Martian Chronicles 9 Night of Black Glass Stalking the Nightmare 16 Night-Rise The Norton Book of Science Fiction 10 Nine Hundred Grandmothers The Norton Book of Science Fiction 9 No Game for Children Web of the City 51 No Great Magic Changewar 68 No Light in the Windows The Mile-Long Spaceship 11 Nothing for My Noon Meal Earthman, Go Home! 15 O Ye of Little Faith Deathbird Stories 10 Oddy and Id Strange Gifts 17 Of Ants and Dinosaurs The Wandering Earth 57 On Exactitude and Science The Aleph and Other Stories 1 On the Downhill Slide Deathbird Stories 18 On the Feasibility of Coal-Driven Power Stations The Expert Dreamers 4 On the Slab Angry Candy 12 One for the Road The Mile-Long Spaceship 16 One Life, Furnished in Early Poverty Approaching Oblivion 14 One-Way Journey Xenogensis 11 Operation Cassandra Xenogensis 27 Opium Shatterday 8 Other Worlds The Gateway Trip 19 Out of All Them Bright Stars The Norton Book of Science Fiction 7 Over the River and Through the Woods The Norton Book of Science Fiction 8 Ozymandias Again, Dangerous Visions 21 Paingod Deathbird Stories 12 Paingod Paingod and Other Delusions 12 Paladin of the Last Hour Angry Candy 26 Parable of Cervantes and the Quixote Labyrinths 1 Parable of the Palace The Aleph and Other Stories 2 Paradise City 16 Paradiso, XXXI, 108 Labyrinths 2 Paradiso, XXXI, 108 The Aleph and Other Stories 2 Partial Magic in the Quixote Labyrinths 4 Paulie Charmed the Sleeping Woman Approaching Oblivion 4 Philtre Tip The Living Demons 5 Pierre Menrad, Author of Don Quixote Ficciones 12 Pierre Menrad, Author of Don Quixote Labyrinths 9 Planet Story Somerset Dreams and Other Fictions 16 Precession The Norton Book of Science Fiction 10 Pretty Maggie Moneyeyes Deathbird Stories 24 Prince Myshkin, and Hold the Relish Angry Candy 10 Prodigy Caviar 14 Project Nightmare The Menace from Earth 21 Pulling Hard Time Slippage 6 Punky & The Yale Men Love Ain't Nothing but Sex Misspelled 30 Quick to Haste Xenogensis 12 Quicktime Angry Candy 10 Ragnarok Labyrinths 2 Ragnarok The Aleph and Other Stories 2 Rain, Rain, Go Away Earthman, Go Home! 9 Rat The Norton Book of Science Fiction 11 Reason I, Robot 18 Red Star, Winter Orbit Burning Chrome 23 Repent, Harlequin! Said the Ticktockman Paingod and Other Delusions 14 Requiem The Man Who Sold the Moon 20 Riders of the Purple Wage Dangerous Visions 80 Riding the Dark Train Out Love Ain't Nothing but Sex Misspelled 10 Riverworld Riverworld and Other Stories 86 Robbie I, Robot 19 Rock God Deathbird Stories 14 Rocket Summer The Martian Chronicles 1 Runaround I, Robot 17 Sandkings Nebula Winners Fifteen 43 Saturn, November 11th Stalking the Nightmare 16 Scartaris, June 28th Slippage 22 Schrodinger's Plague The Norton Book of Science Fiction 8 Schwarzschild Radius The Norton Book of Science Fiction 16 Seeing Strange Wine 34 Sensible City Slippage 10 Seventy-Two Letters Stories of Your Life and Others 54 Sex and/or Mr. Morrison Dangerous Visions 14 Shadow, Shadow on the Wall Caviar 12 Shall the Dust Praise Thee? Dangerous Visions 7 Shatterday Shatterday 17 Shattered Like a Glass Goblin Deathbird Stories 14 She's a Young Thing and Cannot Leaver Her Mother Slippage 16 Shoppe Keeper Shatterday 24 Silence This Way for the Gas, Ladies and Gentlemen 3 Silent in Gehenna Approaching Oblivion 16 Silhouette The New Atlantis 56 Simulacrum The Paper Menagerie and Other Stories 11 Skeleton The October Country 20 Sky Lift The Menace from Earth 14 Slow Sculpture Selected Stories 20 Slow Sculpture Sturgeon is Alive and Well... 22 Snow The Norton Book of Science Fiction 14 Soft Monkey Angry Candy 16 Somehow, I Don't Think We're in Kansas, Toto Stalking the Nightmare 10 Somerset Dreams Somerset Dreams and Other Fictions 46 Soundless Evening Again, Dangerous Visions 8 Speech Sound The Norton Book of Science Fiction 12 Stable Strategies for Middle Management The Norton Book of Science Fiction 11 Stand Still and Die Web of the City 203 State Change The Paper Menagerie and Other Stories 16 State of Grace Somerset Dreams and Other Fictions 9 Still-Life Again, Dangerous Visions 15 Stoned Counsel Again, Dangerous Visions 16 Story of the Warrior and the Captive Maiden Labyrinths 5 Story of the Warrior and the Captive Maiden The Aleph and Other Stories 5 Story of Your Life Stories of Your Life and Others 56 Strange Wine Strange Wine 12 Strange Wine The Norton Book of Science Fiction 7 Stuffing Angry Candy 8 Suicide Sturgeon is Alive and Well... 8 Sun of China The Wandering Earth 49 Symbiosis Somerset Dreams and Other Fictions 20 Take Care of Joey Sturgeon is Alive and Well... 12 Taking Care of God Invisible Planets 40 Taking Care of God The Wandering Earth 41 Tandy's Story The Norton Book of Science Fiction 19 Tauf Aleph The Norton Book of Science Fiction 18 Tell Your Fortune The Living Demons 25 Test to Destruction Dangerous Visions 29 That Girl Who Knew What They Meant Sturgeon is Alive and Well... 10 The [Widget], the [Wadget], and Boff Selected Stories 84 The 10:00 Report is Brought to You By... Again, Dangerous Visions 16 The 3 Most Important Things in Life Stalking the Nightmare 20 The Absolutely Perfect Murder Xenogensis 11 The Adventure of Black Peter The Original Illustrated Sherlock Holmes 13 The Adventure of Charles Augustus Milverton The Original Illustrated Sherlock Holmes 12 The Adventure of the Gloria Scott The Original Illustrated Sherlock Holmes 12 The Adventure of the Abbey Grange The Original Illustrated Sherlock Holmes 15 The Adventure of the Beryl Coronet The Original Illustrated Sherlock Holmes 15 The Adventure of the Blue Carbuncle The Original Illustrated Sherlock Holmes 13 The Adventure of the Cardboard Box The Original Illustrated Sherlock Holmes 13 The Adventure of the Copper Beeches The Original Illustrated Sherlock Holmes 17 The Adventure of the Crooked Man The Original Illustrated Sherlock Holmes 11 The Adventure of the Dancing Men The Original Illustrated Sherlock Holmes 16 The Adventure of the Empty House The Original Illustrated Sherlock Holmes 15 The Adventure of the Engineer's Thumb The Original Illustrated Sherlock Holmes 13 The Adventure of the Final Problem The Original Illustrated Sherlock Holmes 14 The Adventure of the Golden Pince-Nez The Original Illustrated Sherlock Holmes 15 The Adventure of the Greek Interpreter The Original Illustrated Sherlock Holmes 12 The Adventure of the Missing Three-Quarter The Original Illustrated Sherlock Holmes 14 The Adventure of the Musgrave Ritual The Original Illustrated Sherlock Holmes 11 The Adventure of the Naval Treaty The Original Illustrated Sherlock Holmes 22 The Adventure of the Noble Bachelor The Original Illustrated Sherlock Holmes 14 The Adventure of the Norwood Builder The Original Illustrated Sherlock Holmes 15 The Adventure of the Priory School The Original Illustrated Sherlock Holmes 19 The Adventure of the Reigate Squires The Original Illustrated Sherlock Holmes 12 The Adventure of the Resident Patient The Original Illustrated Sherlock Holmes 11 The Adventure of the Second Stain The Original Illustrated Sherlock Holmes 14 The Adventure of the Silver Blaze The Original Illustrated Sherlock Holmes 16 The Adventure of the Six Napoleons The Original Illustrated Sherlock Holmes 14 The Adventure of the Solitary Cyclist The Original Illustrated Sherlock Holmes 13 The Adventure of the Speckled Band The Original Illustrated Sherlock Holmes 16 The Adventure of the Stockbroker's Clerk The Original Illustrated Sherlock Holmes 11 The Adventure of the Yellow Face The Original Illustrated Sherlock Holmes 11 The Age of Gold The Gateway Trip 16 The Ajeri Diary Xenogensis 20 The Aleph The Aleph and Other Stories 16 The Approach to Al-Mu'tasim Ficciones 8 The Argentine Writer and Tradition Labyrinths 9 The Avenger of Death Angry Candy 14 The Babylon Lottery Ficciones 8 The Beast of Barsac The Living Demons 19 The Belonging Kind Burning Chrome 15 The Big Hunger The View from the Stars 14 The Big Space Fuck Again, Dangerous Visions 11 The Black Cloud The Expert Dreamers 18 The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. The Norton Book of Science Fiction 12 The Bookmaking Habits of Select Species The Paper Menagerie and Other Stories 9 The Boscombe Valley Mystery The Original Illustrated Sherlock Holmes 16 The Boulevard of Broken Dreams Strange Wine 6 The Brains of Rats The Norton Book of Science Fiction 14 The Byrds The Norton Book of Science Fiction 12 The Captive The Aleph and Other Stories 2 The Cheese Stands Alone Stalking the Nightmare 14 The Children Xenogensis 29 The Circle Invisible Planets 22 The Circular Ruins Ficciones 8 The Circular Ruins Labyrinths 6 The Cistern The October Country 10 The City of Silence Invisible Planets 44 The Crackpots Paingod and Other Delusions 40 The Crowd The October Country 12 The Daughter of the Tree Xenogensis 12 The Day After the Day the Martians Came Dangerous Visions 10 The Day I Died Stalking the Nightmare 10 The Dead Man The Aleph and Other Stories 6 The Death of Schillinger This Way for the Gas, Ladies and Gentlemen 4 The Deathbird Deathbird Stories 32 The Diagnosis of Dr. Darqueangel Strange Wine 17 The Discarded Paingod and Other Delusions 14 The Doll-House Dangerous Visions 24 The Dragon on the Bookshelf Slippage 12 The Dreams a Nightmare Dreams Slippage 4 The Dwarf The October Country 15 The Earth Men The Martian Chronicles 15 The Emissary The October Country 10 The Encounter Somerset Dreams and Other Fictions 28 The End Ficciones 4 The Evitable Conflict I, Robot 22 The Evolution of Human Science Stories of Your Life and Others 4 The Executioner of the Malformed Children Shatterday 16 The Extraordinary Voyages of Amelie Bertrand Nebula Winners Fifteen 15 The Face of Helene Bournouw Deathbird Stories 12 The Fearful Sphere of Pascal Labyrinths 4 The Few, the Proud Slippage 10 The Fish of Lijiang Invisible Planets 18 The Five Orange Pips The Original Illustrated Sherlock Holmes 11 The Flower of Shazui Invisible Planets 20 The Forces that Crush Earthman, Go Home! 15 The Form of the Sword Ficciones 6 The Function of Dream Sleep Angry Candy 23 The Funeral Again, Dangerous Visions 28 The Funeral The Infinity Box 27 The Fusion Bomb The Infinity Box 39 The Garden of Forking Paths Ficciones 14 The Garden of Forking Paths Labyrinths 11 The Gateway Asteroid The Gateway Trip 9 The Gernsback Continuum The Norton Book of Science Fiction 9 The Gernsback Continuum Burning Chrome 13 The Girl From Mars The Living Demons 7 The Goddess in the Ice Stalking the Nightmare 6 The God's Script Labyrinths 8 The Golden Helix Selected Stories 56 The Golden Man Strange Gifts 33 The Green Morning The Martian Chronicles 5 The Handler The Norton Book of Science Fiction 4 The Happy Breed Dangerous Visions 22 The Heart of the Other Side The Expert Dreamers 11 The Henry Miller Dawn Patrol Riverworld and Other Stories 16 The Home Planet The Gateway Trip 9 The Hounds Somerset Dreams and Other Fictions 28 The Hour That Stretches Stalking the Nightmare 22 The House of Asterion Labyrinths 3 The House of Asterion The Aleph and Other Stories 3 The House the Blakeneys Built The Norton Book of Science Fiction 10 The Immortal Labyrinths 14 The Immortal The Aleph and Other Stories 17 The Indian Spirit Guide The Living Demons 16 The Infinity Box The Infinity Box 65 The Invasion The Expert Dreamers 18 The January Offensive This Way for the Gas, Ladies and Gentlemen 10 The Jar The October Country 17 The Jigsaw Man Dangerous Visions 17 The Jungle Rot Kid on the Nod Riverworld and Other Stories 12 The Lake The October Country 7 The Lake Was Full of Artificial Things The Norton Book of Science Fiction 11 The Last Days of the Captain The Mile-Long Spaceship 15 The Last Generation? Xenogensis 12 The Leaser of Two Evils Riverworld and Other Stories 16 The Library of Babel Ficciones 10 The Library of Babel Labyrinths 8 The Life of Anybody The Norton Book of Science Fiction 2 The Lingering Scent of Woodsmoke Slippage 4 The Literomancer The Paper Menagerie and Other Stories 38 The Litigation Master and the Monkey King The Paper Menagerie and Other Stories 26 The Locusts The Martian Chronicles 1 The Long Years The Martian Chronicles 11 The Longest Fall The Wandering Earth 56 The Lottery in Babylon Labyrinths 6 The Lucky Strike The Norton Book of Science Fiction 31 The Luggage Store The Martian Chronicles 1 The Maker The Aleph and Other Stories 3 The Malley System Dangerous Visions 11 The Man on the Threshold The Aleph and Other Stories 6 The Man Upstairs The October Country 16 The Man Who Ended History: A Documentary The Paper Menagerie and Other Stories 61 The Man Who Lost the Sea Selected Stories 12 The Man Who Rowed Christopher Columbus Ashore Slippage 18 The Man Who Sold the Moon The Man Who Sold the Moon 106 The Man Who Was Heavily into Revenge Shatterday 8 The Man Who Went to the Moon-Twice Dangerous Visions 13 The Man With English Strange Gifts 10 The Man with the Package This Way for the Gas, Ladies and Gentlemen 5 The Man With the Twisted Lips The Original Illustrated Sherlock Holmes 15 The Man without a Planet The Mile-Long Spaceship 7 The Mark Gable Foundation The Expert Dreamers 13 The Martian The Martian Chronicles 12 The Menace from Earth The Menace from Earth 13 The Merchants of Venus The Gateway Trip 122 The Micro-Age The Wandering Earth 33 The Mile-Long Spaceship The Mile-Long Spaceship 10 The Milk of Paradise Again, Dangerous Visions 13 The Million-Year Picnic The Martian Chronicles 9 The Miracle of the Broom Closet The Expert Dreamers 7 The Mirrors of Enigmas Labyrinths 4 The Mountains of Sunset, the Mountains of Dawn The Norton Book of Science Fiction 13 The Mountebank The Aleph and Other Stories 2 The Museum on Cyclops Avenue Slippage 12 The Musicians The Martian Chronicles 1 The Naming of Names The Martian Chronicles 1 The New Atlantis The New Atlantis 30 The New Atlantis The Norton Book of Science Fiction 20 The New York Review of Bird Strange Wine 44 The Next in Line The October Country 41 The Night That All Time Broke Out Dangerous Visions 16 The Off Season The Martian Chronicles 12 The Old Ones The Martian Chronicles 1 The Oldest Soldier Changewar 27 The Other Death The Aleph and Other Stories 8 The Other Eye of Polyphemus Shatterday 14 The Outpost Undiscovered by Tourists Stalking the Nightmare 8 The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 Slippage 6 The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 Slippage 8 The Paper Menagerie The Paper Menagerie and Other Stories 15 The Patterns of Drone Sturgeon is Alive and Well... 16 The People Who Walked On This Way for the Gas, Ladies and Gentlemen 16 The Perfect Match The Paper Menagerie and Other Stories 25 The Phantom of the Sewers Riverworld and Other Stories 25 The Place with No Name Deathbird Stories 16 The Plot The Aleph and Other Stories 1 The Plot Is the Thing The Living Demons 7 The Private War of Private Jacob The Norton Book of Science Fiction 5 The Problem of the Sore Bridge-Among Others Riverworld and Other Stories 32 The Prowler in the City on the Edge of Forever Dangerous Visions 20 The Recognition Dangerous Visions 14 The Red Canary The Infinity Box 18 The Red-Headed League The Original Illustrated Sherlock Holmes 15 The Region Between Angry Candy 86 The Regular The Paper Menagerie and Other Stories 25 The Resurgence of Miss Ankle-Strap Wedgie Love Ain't Nothing but Sex Misspelled 91 The Roads Must Roll The Man Who Sold the Moon 45 The Season of Babies Xenogensis 14 The Secret Miracle Ficciones 8 The Secret Miracle Labyrinths 7 The Sect of Phoenix Ficciones 4 The Sect of Phoenix Labyrinths 4 The Settlers The Martian Chronicles 1 The Sex Opposite Selected Stories 28 The Shape of the Sword Labyrinths 5 The Shore The Martian Chronicles 1 The Silent Towns The Martian Chronicles 10 The Silver Corridor Earthman, Go Home! 20 The Simple Way City 25 The Singers The Expert Dreamers 4 The Skills of Xanadu Selected Stories 28 The Sky is Burning Earthman, Go Home! 9 The Small Assaassin The October Country 21 The Smiling Future Xenogensis 13 The South Ficciones 7 The Starseekers The Gateway Trip 19 The Start of the End of It All The Norton Book of Science Fiction 11 The Summer Night The Martian Chronicles 2 The Superior Sex Xenogensis 11 The Supper This Way for the Gas, Ladies and Gentlemen 5 The Sycthe The October Country 8 The Taxpayer The Martian Chronicles 1 The Test Stand The Expert Dreamers 14 The Test-Tube Creature, Afterward Again, Dangerous Visions 5 The Theologians Labyrinths 8 The Theologians The Aleph and Other Stories 9 The Third Expedition The Martian Chronicles 16 The Time Piece The Infinity Box 22 The Transit of Venus Xenogensis 11 The Two Kings and the Two Labyrinths The Aleph and Other Stories 2 The Universe of Robert Blake Love Ain't Nothing but Sex Misspelled 5 The Unspeakable Betrothal The Living Demons 14 The Very Last Day of a Good Woman Earthman, Go Home! 9 The Village The Infinity Box 10 The Visit The Gateway Trip 9 The Voice of the Sonar in My Veriform Appendix Riverworld and Other Stories 14 The Volcano Riverworld and Other Stories 20 The Wages of Humanity The Wandering Earth 44 The Waiting Labyrinths 4 The Wall and the Books Labyrinths 3 The Wandering Earth The Wandering Earth 46 The War at Home The Norton Book of Science Fiction 3 The Warlord of Saturn's Moon The Norton Book of Science Fiction 8 The Watchers The Martian Chronicles 1 The Watchful Poker Chip of H. Matisse The October Country 12 The Waves The Paper Menagerie and Other Stories 26 The Whimper of Whipped Dogs Deathbird Stories 22 The Will The View from the Stars 14 The Wind The October Country 12 The Wind Beyond the Mountains Earthman, Go Home! 10 The Wine Has Been Left Open Too Long and the Memory Has Gone Flat Strange Wine 16 The Winter Flies The Norton Book of Science Fiction 12 The Winter Market Burning Chrome 25 The Witness Labyrinths 1 The Witness The Aleph and Other Stories 1 The Women Men Don't See The Norton Book of Science Fiction 25 The Wonderful Death of Dudley Stone The October Country 13 The Word for World is Forrest Again, Dangerous Visions 96 The World of Stone This Way for the Gas, Ladies and Gentlemen 3 The Writing of the God The Aleph and Other Stories 6 The Year of the Jackpot The Menace from Earth 32 The Year of the Rat Invisible Planets 30 The Yellow Rose The Aleph and Other Stories 1 The Zahir Labyrinths 5 The Zahir The Aleph and Other Stories 10 Theme of the Traitor and Hero Ficciones 6 Theme of the Traitor and Hero Labyrinths 4 There Was an Old Woman The October Country 16 There Will Come Soft Rains The Martian Chronicles 6 Things Lost Again, Dangerous Visions 30 This Way for the Gas, Ladies and Gentlemen This Way for the Gas, Ladies and Gentlemen 21 Three Versions of Judas Ficciones 8 Three Versions of Judas Labyrinths 6 Throwback Xenogensis 13 Thunder and Roses Selected Stories 24 Time Travel for Pedestrians Again, Dangerous Visions 31 Tiny Ally Stalking the Nightmare 6 Tissue Again, Dangerous Visions 16 Tlon, Uqbar, Orbis Teritus Ficciones 20 Tlon, Uqbar, Orbis Teritus Labyrinths 16 To Be Continued Strange Gifts 14 To Explain to Mrs. Thompson The Expert Dreamers 23 To Here and the Easel Sturgeon is Alive and Well... 56 Toenails The Aleph and Other Stories 1 Tongtong's Summer Invisible Planets 20 Totenbuch Again, Dangerous Visions 10 Touched With Fire The October Country 15 Tower of Babylon Stories of Your Life and Others 28 Tracking Level Stalking the Nightmare 12 Transcending Destiny Stalking the Nightmare 26 Trouble With Ants City 38 Try and Change the Past Changewar 11 Twink Caviar 19 Unaccompanied Sonata Nebula Winners Fifteen 20 Uncle Einar The October Country 10 Uncle Fremmis Sturgeon is Alive and Well... 18 Underground The Living Demons 6 Understand Stories of Your Life and Others 42 Unlocking the Air The Unreal and the Real 26 Usher II The Martian Chronicles 15 Valerie Love Ain't Nothing but Sex Misspelled 16 Valery as Symbol Labyrinths 2 Vaster than Empires and More Slow Explorers of Space 57 Visionary Stalking the Nightmare 14 Wanted in Surgery Paingod and Other Delusions 30 Water Is for Washing The Menace from Earth 10 Way in the Middle of the Air The Martian Chronicles 3 We See Things Differently The Norton Book of Science Fiction 18 What Happened to Auguste Clarot? Dangerous Visions 8 What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 Love Ain't Nothing but Sex Misspelled 19 What's It Like Out There? Explorers of Space 27 When Auld's Acquaintance is Forgot Angry Candy 10 When I was a Hired Gun Love Ain't Nothing but Sex Misspelled 12 When I Was Miss Dow The Norton Book of Science Fiction 10 When it Changed Again, Dangerous Visions 16 When the Bentfin Boomer Boys on Old New Alabama Again, Dangerous Visions 107 When the Change-Winds Blow Changewar 15 Where Have You Been, Billy Boy, Billy Boy? The Infinity Box 13 Where I Shall Dwell in the Next World Slippage 12 With a Finger in My I Again, Dangerous Visions 15 With Her Eyes The Wandering Earth 19 With Virgin Oddum at the East Pole Angry Candy 20 Working with the Little People Strange Wine 18 Would You Do It for a Penny Shatterday 22 Ylla The Martian Chronicles 12 You Triflin' Skunk The View from the Stars 11 Zero Gee Again, Dangerous Visions 31 And the Moon be Still as Bright The Martian Chronicles 24 ================================================ FILE: tests/data/stories.tsv ================================================ !!!The!!Teddy!Crazy!!Show!!! science fiction 1968 (Learning About) Machine Sex science fiction 1988 ...the World, as we Know 't science fiction 1982 2004, or Thereabouts science fiction 1964 A Biography of Tadeo Isidoro Cruz (1829-1874) fiction 1944 A Brief History of the Trans-Pacific Tunnel science fiction 2013 A Case of Identity mystery 1891 A Day at Harmenz east euro lit 1959 A Deskful of Girls science fiction 1958 A Dialog About A Dialog fiction 1936 A Dialog Between Dead Men fiction 1957 A Feast of Demons science fiction 1958 A Few Things I Know About While Away science fiction 1975 A Hundred Ghosts Parade Tonight science fiction 2010 A is for Automation science fiction 1959 A Midwinter's Tale science fiction 1988 A Momentary Taste of Being science fiction 1975 A Mouse in the Walls of the Global Village science fiction 1972 A New Refutation of Time essay 1947 A Note on (toward) Bernard Shaw essay 1962 A Path Through the Darkness science fiction 1963 A Prayer for No One's Enemies science fiction 1966 A Problem fiction 1957 A Scandal in Bohemia mystery 1891 A Toy for Juliette science fiction 1967 A True Story east euro lit 1959 A Visit east euro lit 1959 A Way of Thinking science fiction 1953 Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W science fiction 1974 Adrift on the Policy Level science fiction 1959 Aesop science fiction 1947 After the Days of Dead-Eye 'Dee science fiction 1985 All in Good Time science fiction 1960 All the Birds Come Home to Roost science fiction 1978 All the Flavors science fiction 2012 All the Lies Lies That Are My Life science fiction 1980 All The People science fiction 1961 All the Sound of Fear science fiction 1962 Along the Scenic Route science fiction 1969 Alpha Ralpha Boulevard science fiction 1961 Amateur in Chancery science fiction 1961 America science fiction 1987 An Advanced Readers' Picture Book of Comparative Cognition science fiction 2016 An Examination of the Work of Herbert Quain fiction 1941 And the Angels Sing science fiction 1990 And the Sea Like Mirrors science fiction 1972 Andover and the Android science fiction 1963 Anybody Else Like Me? science fiction 1952 Anywhere But Here, With Anybody But You science fiction 1996 April Fools' Day Forever science fiction 1970 Argumentum Ornithologicum fiction 1952 As Simple As That science fiction 1971 At the End of the Orbit science fiction 1961 At the Mouse Circus science fiction 1971 Aunt Parnetta's Electric Blisters science fiction 1990 Auschwitz, Our Home (A Letter) east euro lit 1959 Auto-De-Fe science fiction 1967 Avatars of the Tortoise essay 1939 Averroes' Search fiction 1947 Aye, and Gomorrah... science fiction 1967 Balanced Ecology science fiction 1965 Basilisk science fiction 1972 Battle Without Banners science fiction 1964 Battlefield science fiction 1958 Beachhead science fiction 1951 Beauty's Beast science fiction 1941 Bed Sheets are White science fiction 1972 Bettyann science fiction 1951 Bianca's Hands science fiction 1947 Big Joe and the Nth Generation science fiction 1952 Blabbermouth science fiction 1945 Black Bargain science fiction 1942 Blank? science fiction 1957 Bleeding Stones science fiction 1973 Blind Bird, Blind Bird, Go Away From Me! science fiction 1963 Blood Bank science fiction 1952 Blot science fiction 1972 Blowups Happen science fiction 1940 Borges and I fiction 1957 Bounty science fiction 1972 Brass and Gold (or Horse and Zeppelin in Beverly Hills) science fiction 1971 Bright Eyes science fiction 1965 Bright Segment science fiction 1955 Broken Glass science fiction 1981 Brownshoes science fiction 1969 Burning Chrome science fiction 1982 By His Bootstraps science fiction 1941 Call Girl science fiction 2014 Camps science fiction 1979 Carcinoma Angels science fiction 1967 Catch That Rabbit science fiction 1944 Catman science fiction 1974 Census science fiction 1944 Chain Reaction science fiction 1956 Chained to the Fast Lane in the Red Queen's Race science fiction 1983 Chatting with Anubis science fiction 1995 Ching Witch! science fiction 1972 Christ, Old Student in a New School science fiction 1972 Chuck Berry, Won't You Please Come Home science fiction 1972 City science fiction 1944 Cold Friend science fiction 1973 Collecting Team science fiction 1956 Columbus Was a Dope science fiction 1947 Come to the Party science fiction 1978 Comes Now the Power science fiction 1966 Commuter's Problem science fiction 1957 Corpse science fiction 1972 Count the Clock That Tells the Time science fiction 1978 Covered Mirrors fiction 1936 Crate science fiction 1970 Crazy as a Soup Sandwich science fiction 1989 Croatoan science fiction 1975 Crucifixus Etiam science fiction 1953 Curse 5.0 science fiction 2013 Damnation Morning science fiction 1959 Danger-Human! science fiction 1957 Daniel White for the Greater Good science fiction 1961 Darkness Upon the Face of the Deep science fiction 1991 Day Million science fiction 1966 Deal From the Bottom science fiction 1960 Death and the Compass fiction 1942 Deeper than the Darkness science fiction 1957 Delia Elena San Marco fiction 1957 Delusion for a Dragon Slayer science fiction 1966 Deutsches Requiem fiction 1946 Devourer science fiction 2013 Distant Signals science fiction 1984 Division by Zero science fiction 1991 Django science fiction 1978 Djinn, No Chaser science fiction 1982 Dogfight science fiction 1985 Do-It-Yourself science fiction 1961 Dreamtigers fiction 1936 Dumb Waiter science fiction 1952 Each an Explorer science fiction 1956 Ecowarewness science fiction 1974 Eidolons science fiction 1986 Elbow Room science fiction 1980 Elegy poem 1962 Elouise and the Doctors of the Planet Pergamon science fiction 1972 Emissary from Hamelin science fiction 1977 Emma Zunz fiction 1948 Empire of the Sun science fiction 1972 Encounter With A Hick science fiction 1967 Enemy Mine science fiction 1979 Epilogue science fiction 1952 Epiphany for Aliens science fiction 1972 Ernest and the Machine God science fiction 1968 Erotophobia science fiction 1971 Ersatz science fiction 1967 Escape! science fiction 1945 Escapegoat science fiction 1983 Eutopia science fiction 1967 Evensong science fiction 1967 Everything and Nothing fiction 1958 Evidence science fiction 1946 Exploration Team science fiction 1956 Exposures science fiction 1981 Eye of the Beholder science fiction 1972 Faith of our Fathers science fiction 1967 Fear is a Cold Black science fiction 1963 Feather Tigers science fiction 1973 Featherbed on Chlyntha science fiction 1957 Final Trophy science fiction 1957 Flies science fiction 1967 Flop Sweat science fiction 1977 Folding Beijing science fiction 2014 Footsteps science fiction 1980 For the Sake of Grace science fiction 1969 For Value Received science fiction 1972 Fragments of a Hologram Rose science fiction 1977 From A to Z, In The Chocolate Alphabet science fiction 1979 From the Government Printing Office science fiction 1967 Frozen Journey science fiction 1980 Funes the Memorious fiction 1942 G. B. K.-A Many-Flavored Bird science fiction 1962 Gather Blue Roses science fiction 1972 Gathi science fiction 1958 Getting Along science fiction 1972 Ghost of a Chance science fiction 1943 giANTS science fiction 1979 Gift from the Stars science fiction 1958 Gnomebody science fiction 1956 Go Toward the Light science fiction 1996 Go, Go, Go, Said the Bird science fiction 1967 Goldfish Bowl science fiction 1942 Gonna Roll the Bones science fiction 1967 Good Hunting science fiction 2012 Good News from the Vatican science fiction 1971 Gopher in the Gilly science fiction 1982 Grail science fiction 1981 Grave of the Fireflies science fiction 2005 Gutter Gang thriller 1957 Hadj science fiction 1956 Half-Life science fiction 1989 Harry the Hare science fiction 1972 Heavyplanet science fiction 1958 Heechee Treasures science fiction 1990 Hell Is the Absence of God science fiction 2001 High Weir science fiction 1968 Hindsight: 480 Seconds science fiction 1973 Hinterlands science fiction 1981 His Vegetable science fiction 1986 Hitler Painted Roses science fiction 1977 Hobbies science fiction 1946 Homecoming science fiction 1946 Homelanding science fiction 1990 How Beautiful with Banners science fiction 1966 How's the Night Life on Cassalda? science fiction 1977 Huddling Place science fiction 1944 Humpty Dumpty had a Great Fall science fiction 1948 I Curse the Lesson and Bless the Knowledge science fiction 1976 I, Dreamer science fiction 1953 Ibn-Hakam al-Bokhari, Murdered in His Labyrinth fiction 1951 If All Men Were Brothers, Would You Let One Marry Your Sister? science fiction 1967 I'm Looking for Kadak science fiction 1974 In Fear of K science fiction 1975 In Lonely Islands science fiction 1956 In Memoriam, J. F. K. fiction 1967 In re Glover science fiction 1972 In the Barn science fiction 1972 In the Core science fiction 1990 In the Fourth Year of the War science fiction 1979 Incident in Moderan science fiction 1967 Inferno, I, 32 fiction 1955 Interim science fiction 1950 Interlocking Pieces science fiction 1984 Invaders science fiction 1990 Invasion Footnote science fiction 1957 Invisible Planets science fiction 2010 It science fiction 1940 It was Nothing-Really science fiction 1969 It's You! science fiction 1969 J. C. on the Dude Ranch science fiction 1979 Jack-in-the-Box science fiction 1947 Jane Doe #112 science fiction 1990 Jeffty is Five science fiction 1977 Jenny with Wings science fiction 1963 Johnny Mnemonic science fiction 1981 Jorry's Gap science fiction 1969 Judas science fiction 1967 Jupiter Five science fiction 1953 Kafka and His Precursors essay 1951 Keyboard science fiction 1995 Killdozer! science fiction 1944 Killing Bernstein science fiction 1976 King of the Hill science fiction 1972 Kirinyaga science fiction 1988 Kiss of Fire science fiction 1972 Knights to Move science fiction 1965 Knox science fiction 1974 Kyrie science fiction 1968 Ladies and Gentlemen, This Is Your Crisis science fiction 1976 Lamia Mutable science fiction 1972 Land of the Great Horses science fiction 1967 Last Train to Kankakee science fiction 1972 Laugh Track science fiction 1984 Lenny science fiction 1957 Let There Be Light science fiction 1940 Liar! science fiction 1941 Life in Our Time science fiction 1966 Life-Line science fiction 1939 Liking What You See: A Documentary science fiction 2002 Little Lost Robot science fiction 1947 Lollipop and the Tar Baby science fiction 1977 Lonley Women Are the Vessels of Time science fiction 1976 Looking for Company science fiction 1990 Lord Randy, My Son science fiction 1967 Lucy Comes To Stay science fiction 1952 Making It All the Way into the Future on Gaxton Falls of the Red Planet science fiction 1974 Man of Letters science fiction 1975 Martin Fierro fiction 1957 Mathoms from the Time Closet science fiction 1972 Mealtime science fiction 1958 Medusa science fiction 1942 Mefisto in Onyx science fiction 1993 Microcosmic God science fiction 1941 Midnight in the Sunken Cathedral science fiction 1995 Midnight News science fiction 1990 Mom science fiction 1976 Mona at Her Windows science fiction 1962 Monitored Dreams & Strategic Cremations science fiction 1972 Mono no Aware science fiction 2012 Monolog science fiction 1973 Moth Race science fiction 1972 Mountain science fiction 2013 Mr. Costello, Hero science fiction 1953 Mrs. Bagley Goes to Mars science fiction 1975 Mutations fiction 1960 Nackles vr.1 science fiction 1963 Nackles vr.2 science fiction 1987 Neither Your Jenny Nor Mine science fiction 1964 Neon science fiction 1973 New Rose Hotel science fiction 1984 Night Journey of the Dragon-Horse science fiction 2016 Night Meeting science fiction 1950 Night of Black Glass science fiction 1981 Night-Rise science fiction 1978 Nine Hundred Grandmothers science fiction 1966 No Game for Children thriller 1959 No Great Magic science fiction 1960 No Light in the Windows science fiction 1963 Nothing for My Noon Meal science fiction 1958 O Ye of Little Faith science fiction 1968 Oddy and Id science fiction 1950 Of Ants and Dinosaurs science fiction 2013 On Exactitude and Science fiction 1946 On the Downhill Slide science fiction 1972 On the Feasibility of Coal-Driven Power Stations science fiction 1956 On the Slab science fiction 1981 One for the Road science fiction 1959 One Life, Furnished in Early Poverty science fiction 1970 One-Way Journey science fiction 1955 Operation Cassandra science fiction 1958 Opium science fiction 1977 Other Worlds science fiction 1990 Out of All Them Bright Stars science fiction 1986 Over the River and Through the Woods science fiction 1965 Ozymandias science fiction 1972 Paingod science fiction 1964 Paladin of the Last Hour science fiction 1985 Parable of Cervantes and the Quixote poem 1955 Parable of the Palace fiction 1956 Paradise science fiction 1946 Paradiso, XXXI, 108 fiction 1954 Partial Magic in the Quixote essay 1949 Paulie Charmed the Sleeping Woman science fiction 1962 Philtre Tip science fiction 1961 Pierre Menrad, Author of Don Quixote fiction 1939 Planet Story science fiction 1975 Precession science fiction 1980 Pretty Maggie Moneyeyes science fiction 1967 Prince Myshkin, and Hold the Relish science fiction 1982 Prodigy science fiction 1949 Project Nightmare science fiction 1953 Pulling Hard Time science fiction 1995 Punky & The Yale Men science fiction 1966 Quick to Haste science fiction 1969 Quicktime science fiction 1985 Ragnarok fiction 1959 Rain, Rain, Go Away science fiction 1956 Rat science fiction 1986 Reason science fiction 1941 Red Star, Winter Orbit science fiction 1983 Repent, Harlequin! Said the Ticktockman science fiction 1965 Requiem science fiction 1940 Riders of the Purple Wage science fiction 1967 Riding the Dark Train Out science fiction 1961 Riverworld science fiction 1966 Robbie science fiction 1940 Rock God science fiction 1969 Rocket Summer science fiction 1950 Runaround science fiction 1942 Sandkings science fiction 1979 Saturn, November 11th science fiction 1981 Scartaris, June 28th science fiction 1990 Schrodinger's Plague science fiction 1982 Schwarzschild Radius science fiction 1987 Seeing science fiction 1976 Sensible City science fiction 1994 Seventy-Two Letters science fiction 2000 Sex and/or Mr. Morrison science fiction 1967 Shadow, Shadow on the Wall science fiction 1951 Shall the Dust Praise Thee? science fiction 1967 Shatterday science fiction 1975 Shattered Like a Glass Goblin science fiction 1968 She's a Young Thing and Cannot Leaver Her Mother science fiction 1988 Shoppe Keeper science fiction 1977 Silence east euro lit 1959 Silent in Gehenna science fiction 1971 Silhouette science fiction 1975 Simulacrum science fiction 2011 Skeleton science fiction 1977 Sky Lift science fiction 1953 Slow Sculpture science fiction 1970 Snow science fiction 1985 Soft Monkey science fiction 1987 Somehow, I Don't Think We're in Kansas, Toto science fiction 1974 Somerset Dreams science fiction 1969 Soundless Evening science fiction 1972 Speech Sound science fiction 1983 Stable Strategies for Middle Management science fiction 1988 Stand Still and Die thriller 1956 State Change science fiction 2004 State of Grace science fiction 1977 Still-Life science fiction 1972 Stoned Counsel science fiction 1972 Story of the Warrior and the Captive Maiden fiction 1949 Story of Your Life science fiction 1998 Strange Wine science fiction 1976 Stuffing science fiction 1982 Suicide science fiction 1970 Sun of China science fiction 2013 Symbiosis science fiction 1972 Take Care of Joey science fiction 1970 Taking Care of God science fiction 2005 Tandy's Story science fiction 1961 Tauf Aleph science fiction 1981 Tell Your Fortune science fiction 1967 Test to Destruction science fiction 1967 That Girl Who Knew What They Meant science fiction 1970 The [Widget], the [Wadget], and Boff science fiction 1955 The 10:00 Report is Brought to You By... science fiction 1972 The 3 Most Important Things in Life science fiction 1978 The Absolutely Perfect Murder science fiction 1965 The Adventure of Black Peter mystery 1904 The Adventure of Charles Augustus Milverton mystery 1904 The Adventure of the Gloria Scott mystery 1893 The Adventure of the Abbey Grange mystery 1904 The Adventure of the Beryl Coronet mystery 1892 The Adventure of the Blue Carbuncle mystery 1892 The Adventure of the Cardboard Box mystery 1893 The Adventure of the Copper Beeches mystery 1892 The Adventure of the Crooked Man mystery 1893 The Adventure of the Dancing Men mystery 1903 The Adventure of the Empty House mystery 1903 The Adventure of the Engineer's Thumb mystery 1892 The Adventure of the Final Problem mystery 1893 The Adventure of the Golden Pince-Nez mystery 1904 The Adventure of the Greek Interpreter mystery 1893 The Adventure of the Missing Three-Quarter mystery 1904 The Adventure of the Musgrave Ritual mystery 1893 The Adventure of the Naval Treaty mystery 1893 The Adventure of the Noble Bachelor mystery 1892 The Adventure of the Norwood Builder mystery 1903 The Adventure of the Priory School mystery 1904 The Adventure of the Reigate Squires mystery 1893 The Adventure of the Resident Patient mystery 1893 The Adventure of the Second Stain mystery 1904 The Adventure of the Silver Blaze mystery 1892 The Adventure of the Six Napoleons mystery 1904 The Adventure of the Solitary Cyclist mystery 1903 The Adventure of the Speckled Band mystery 1892 The Adventure of the Stockbroker's Clerk mystery 1893 The Adventure of the Yellow Face mystery 1893 The Age of Gold science fiction 1990 The Ajeri Diary science fiction 1968 The Aleph fiction 1949 The Approach to Al-Mu'tasim fiction 1936 The Argentine Writer and Tradition essay 1951 The Avenger of Death science fiction 1988 The Babylon Lottery fiction 1941 The Beast of Barsac science fiction 1944 The Belonging Kind science fiction 1981 The Big Hunger science fiction 1952 The Big Space Fuck science fiction 1972 The Black Cloud science fiction 1957 The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. science fiction 1985 The Bookmaking Habits of Select Species science fiction 2012 The Boscombe Valley Mystery mystery 1891 The Boulevard of Broken Dreams science fiction 1975 The Brains of Rats science fiction 1986 The Byrds science fiction 1982 The Captive fiction 1957 The Cheese Stands Alone science fiction 1981 The Children science fiction 1952 The Circle science fiction 2014 The Circular Ruins fiction 1940 The Cistern science fiction 1947 The City of Silence science fiction 2005 The Crackpots science fiction 1956 The Crowd science fiction 1943 The Daughter of the Tree science fiction 1951 The Day After the Day the Martians Came science fiction 1967 The Day I Died science fiction 1973 The Dead Man fiction 1946 The Death of Schillinger east euro lit 1959 The Deathbird science fiction 1973 The Diagnosis of Dr. Darqueangel science fiction 1977 The Discarded science fiction 1959 The Doll-House science fiction 1967 The Dragon on the Bookshelf science fiction 1995 The Dreams a Nightmare Dreams science fiction 1997 The Dwarf science fiction 1954 The Earth Men science fiction 1948 The Emissary science fiction 1947 The Encounter science fiction 1970 The End fiction 1953 The Evitable Conflict science fiction 1950 The Evolution of Human Science science fiction 2000 The Executioner of the Malformed Children science fiction 1978 The Extraordinary Voyages of Amelie Bertrand science fiction 1979 The Face of Helene Bournouw science fiction 1960 The Fearful Sphere of Pascal essay 1947 The Few, the Proud science fiction 1987 The Fish of Lijiang science fiction 2006 The Five Orange Pips mystery 1891 The Flower of Shazui science fiction 2012 The Forces that Crush science fiction 1958 The Form of the Sword fiction 1942 The Funeral science fiction 1972 The Fusion Bomb science fiction 1972 The Garden of Forking Paths fiction 1941 The Gateway Asteroid science fiction 1990 The Gernsback Continuum science fiction 1981 The Girl From Mars science fiction 1950 The Goddess in the Ice science fiction 1967 The God's Script fiction 1949 The Golden Helix science fiction 1979 The Golden Man science fiction 1954 The Green Morning science fiction 1950 The Handler science fiction 1960 The Happy Breed science fiction 1967 The Heart of the Other Side science fiction 1962 The Henry Miller Dawn Patrol science fiction 1977 The Home Planet science fiction 1990 The Hounds science fiction 1974 The Hour That Stretches science fiction 1982 The House of Asterion fiction 1947 The House the Blakeneys Built science fiction 1965 The Immortal fiction 1947 The Indian Spirit Guide science fiction 1948 The Infinity Box science fiction 1971 The Invasion science fiction 1940 The January Offensive east euro lit 1959 The Jar science fiction 1944 The Jigsaw Man science fiction 1967 The Jungle Rot Kid on the Nod science fiction 1968 The Lake science fiction 1944 The Lake Was Full of Artificial Things science fiction 1985 The Last Days of the Captain science fiction 1962 The Last Generation? science fiction 1946 The Leaser of Two Evils science fiction 1979 The Library of Babel fiction 1941 The Life of Anybody science fiction 1984 The Lingering Scent of Woodsmoke science fiction 1996 The Literomancer science fiction 2010 The Litigation Master and the Monkey King science fiction 2013 The Locusts science fiction 1950 The Long Years science fiction 1948 The Longest Fall science fiction 2013 The Lottery in Babylon fiction 1941 The Lucky Strike science fiction 1984 The Luggage Store science fiction 1950 The Maker fiction 1958 The Malley System science fiction 1967 The Man on the Threshold fiction 1952 The Man Upstairs science fiction 1947 The Man Who Ended History: A Documentary science fiction 2011 The Man Who Lost the Sea science fiction 1959 The Man Who Rowed Christopher Columbus Ashore science fiction 1991 The Man Who Sold the Moon science fiction 1950 The Man Who Was Heavily into Revenge science fiction 1978 The Man Who Went to the Moon-Twice science fiction 1967 The Man With English science fiction 1953 The Man with the Package east euro lit 1959 The Man With the Twisted Lips mystery 1891 The Man without a Planet science fiction 1962 The Mark Gable Foundation science fiction 1961 The Martian science fiction 1949 The Menace from Earth science fiction 1957 The Merchants of Venus science fiction 1972 The Micro-Age science fiction 2013 The Mile-Long Spaceship science fiction 1956 The Milk of Paradise science fiction 1972 The Million-Year Picnic science fiction 1946 The Miracle of the Broom Closet science fiction 1952 The Mirrors of Enigmas essay 1940 The Mountains of Sunset, the Mountains of Dawn science fiction 1974 The Mountebank fiction 1957 The Museum on Cyclops Avenue science fiction 1995 The Musicians science fiction 1950 The Naming of Names science fiction 1950 The New Atlantis science fiction 1975 The New York Review of Bird science fiction 1975 The Next in Line science fiction 1947 The Night That All Time Broke Out science fiction 1967 The Off Season science fiction 1948 The Old Ones science fiction 1950 The Oldest Soldier science fiction 1960 The Other Death fiction 1949 The Other Eye of Polyphemus science fiction 1977 The Outpost Undiscovered by Tourists science fiction 1982 The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 science fiction 1994 The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 science fiction 1994 The Paper Menagerie science fiction 2011 The Patterns of Drone science fiction 1970 The People Who Walked On east euro lit 1959 The Perfect Match science fiction 2012 The Phantom of the Sewers science fiction 1978 The Place with No Name science fiction 1969 The Plot fiction 1957 The Plot Is the Thing science fiction 1966 The Private War of Private Jacob science fiction 1973 The Problem of the Sore Bridge-Among Others science fiction 1975 The Prowler in the City on the Edge of Forever science fiction 1967 The Recognition science fiction 1967 The Red Canary science fiction 1973 The Red-Headed League mystery 1891 The Region Between science fiction 1970 The Regular science fiction 2014 The Resurgence of Miss Ankle-Strap Wedgie science fiction 1968 The Roads Must Roll science fiction 1940 The Season of Babies science fiction 1959 The Secret Miracle fiction 1943 The Sect of Phoenix fiction 1952 The Settlers science fiction 1950 The Sex Opposite science fiction 1952 The Shape of the Sword fiction 1942 The Shore science fiction 1950 The Silent Towns science fiction 1949 The Silver Corridor science fiction 1956 The Simple Way science fiction 1951 The Singers science fiction 1956 The Skills of Xanadu science fiction 1956 The Sky is Burning science fiction 1958 The Small Assaassin science fiction 1962 The Smiling Future science fiction 1965 The South fiction 1953 The Starseekers science fiction 1990 The Start of the End of It All science fiction 1981 The Summer Night science fiction 1949 The Superior Sex science fiction 1968 The Supper east euro lit 1959 The Sycthe science fiction 1943 The Taxpayer science fiction 1950 The Test Stand science fiction 1955 The Test-Tube Creature, Afterward science fiction 1972 The Theologians fiction 1947 The Third Expedition science fiction 1948 The Time Piece science fiction 1975 The Transit of Venus science fiction 1962 The Two Kings and the Two Labyrinths fiction 1946 The Universe of Robert Blake science fiction 1962 The Unspeakable Betrothal science fiction 1949 The Very Last Day of a Good Woman science fiction 1958 The Village science fiction 1973 The Visit science fiction 1990 The Voice of the Sonar in My Veriform Appendix science fiction 1971 The Volcano science fiction 1976 The Wages of Humanity science fiction 2013 The Waiting fiction 1950 The Wall and the Books essay 1950 The Wandering Earth science fiction 2013 The War at Home science fiction 1985 The Warlord of Saturn's Moon science fiction 1974 The Watchers science fiction 1950 The Watchful Poker Chip of H. Matisse science fiction 1954 The Waves science fiction 2012 The Whimper of Whipped Dogs science fiction 1973 The Will science fiction 1953 The Wind science fiction 1943 The Wind Beyond the Mountains science fiction 1957 The Wine Has Been Left Open Too Long and the Memory Has Gone Flat science fiction 1976 The Winter Flies science fiction 1967 The Winter Market science fiction 1985 The Witness fiction 1957 The Women Men Don't See science fiction 1973 The Wonderful Death of Dudley Stone science fiction 1954 The Word for World is Forrest science fiction 1972 The World of Stone east euro lit 1959 The Writing of the God fiction 1949 The Year of the Jackpot science fiction 1952 The Year of the Rat science fiction 2009 The Yellow Rose fiction 1960 The Zahir fiction 1947 Theme of the Traitor and Hero fiction 1944 There Was an Old Woman science fiction 1944 There Will Come Soft Rains science fiction 1950 Things Lost science fiction 1972 This Way for the Gas, Ladies and Gentlemen east euro lit 1959 Three Versions of Judas fiction 1944 Throwback science fiction 1952 Thunder and Roses science fiction 1957 Time Travel for Pedestrians science fiction 1972 Tiny Ally science fiction 1957 Tissue science fiction 1972 Tlon, Uqbar, Orbis Teritus fiction 1940 To Be Continued science fiction 1956 To Explain to Mrs. Thompson science fiction 1951 To Here and the Easel science fiction 1954 Toenails fiction 1936 Tongtong's Summer science fiction 2014 Totenbuch science fiction 1972 Touched With Fire science fiction 1954 Tower of Babylon science fiction 1990 Tracking Level science fiction 1956 Transcending Destiny science fiction 1957 Trouble With Ants science fiction 1951 Try and Change the Past science fiction 1958 Twink science fiction 1955 Unaccompanied Sonata science fiction 1979 Uncle Einar science fiction 1947 Uncle Fremmis science fiction 1970 Underground science fiction 1967 Understand science fiction 1991 Unlocking the Air science fiction 1990 Usher II science fiction 1950 Valerie science fiction 1972 Valery as Symbol essay 1962 Vaster than Empires and More Slow science fiction 1971 Visionary science fiction 1959 Wanted in Surgery science fiction 1957 Water Is for Washing science fiction 1947 Way in the Middle of the Air science fiction 1950 We See Things Differently science fiction 1989 What Happened to Auguste Clarot? science fiction 1967 What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 science fiction 1964 What's It Like Out There? science fiction 1952 When Auld's Acquaintance is Forgot science fiction 1982 When I was a Hired Gun science fiction 1973 When I Was Miss Dow science fiction 1966 When it Changed science fiction 1972 When the Bentfin Boomer Boys on Old New Alabama science fiction 1972 When the Change-Winds Blow science fiction 1964 Where Have You Been, Billy Boy, Billy Boy? science fiction 1971 Where I Shall Dwell in the Next World science fiction 1992 With a Finger in My I science fiction 1972 With Her Eyes science fiction 2013 With Virgin Oddum at the East Pole science fiction 1985 Working with the Little People science fiction 1979 Would You Do It for a Penny science fiction 1967 Ylla science fiction 1950 You Triflin' Skunk science fiction 1954 Zero Gee science fiction 1972 And the Moon be Still as Bright science fiction 1948 ================================================ FILE: tests/data.hpp ================================================ #pragma once #include #include #include "sql.hpp" using books = sql::schema< "books", sql::index<>, #ifdef CROSS sql::column<"book", std::string>, #else sql::column<"title", std::string>, #endif sql::column<"genre", std::string>, sql::column<"year", unsigned>, sql::column<"pages", unsigned> >; using stories = sql::schema< "stories", sql::index<>, #ifdef CROSS sql::column<"story", std::string>, #else sql::column<"title", std::string>, #endif sql::column<"genre", std::string>, sql::column<"year", unsigned> >; using authored = sql::schema< "authored", sql::index<>, sql::column<"title", std::string>, sql::column<"name", std::string> >; using collected = sql::schema< "collected", sql::index<>, sql::column<"title", std::string>, sql::column<"collection", std::string>, sql::column<"pages", unsigned> >; const std::string data_folder{ "./data/" }; const std::string perf_folder{ "../data/" }; const std::string books_data{ "books.tsv" }; const std::string stories_data{ "stories.tsv" }; const std::string authored_data{ "authored.tsv" }; const std::string collected_data{ "collected.tsv" }; using books_row = std::tuple; using books_type = std::vector; using stories_row = std::tuple; using stories_type = std::vector; using authored_row = std::tuple; using authored_type = std::vector; using collected_row = std::tuple; using collected_type = std::vector; constexpr std::size_t iters{ 65536 }; constexpr std::size_t offset{ 512 }; template books_type books_load() { auto file{ std::fstream(perf_folder + books_data) }; books_type table{}; while (file) { books_row row{}; std::getline(file, std::get<0>(row), Delim); std::getline(file, std::get<1>(row), Delim); file >> std::get<2>(row); file >> std::get<3>(row); table.push_back(std::move(row)); if (file.get() != '\n') { file.unget(); } } return table; } template stories_type stories_load() { auto file{ std::fstream(perf_folder + stories_data) }; stories_type table{}; while (file) { stories_row row{}; std::getline(file, std::get<0>(row), Delim); std::getline(file, std::get<1>(row), Delim); file >> std::get<2>(row); table.push_back(std::move(row)); if (file.get() != '\n') { file.unget(); } } return table; } template authored_type authored_load() { auto file{ std::fstream(perf_folder + authored_data) }; authored_type table{}; while (file) { authored_row row{}; std::getline(file, std::get<0>(row), Delim); std::getline(file, std::get<1>(row), Delim); table.push_back(std::move(row)); if (file.get() != '\n') { file.unget(); } } return table; } template collected_type collected_load() { auto file{ std::fstream(perf_folder + collected_data) }; collected_type table{}; while (file) { collected_row row{}; std::getline(file, std::get<0>(row), Delim); std::getline(file, std::get<1>(row), Delim); file >> std::get<2>(row); table.push_back(std::move(row)); if (file.get() != '\n') { file.unget(); } } return table; } ================================================ FILE: tests/perf/data/lib-query0 ================================================ 6.81 user ================================================ FILE: tests/perf/data/lib-query1 ================================================ 4.73 user ================================================ FILE: tests/perf/data/lib-query2 ================================================ 3.70 user ================================================ FILE: tests/perf/data/lib-query3 ================================================ 11.81 user ================================================ FILE: tests/perf/data/lib-query4 ================================================ 1.54 user ================================================ FILE: tests/perf/data/lib-query5 ================================================ 38.04 user ================================================ FILE: tests/perf/data/query0 ================================================ 6.39 user ================================================ FILE: tests/perf/data/query1 ================================================ 4.18 user ================================================ FILE: tests/perf/data/query2 ================================================ 11.17 user ================================================ FILE: tests/perf/data/query3 ================================================ 12.39 user ================================================ FILE: tests/perf/data/query4 ================================================ 3.45 user ================================================ FILE: tests/perf/data/query5 ================================================ 44.35 user ================================================ FILE: tests/perf/queries/lib-query0.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT title, genre AS type, year AS published " "FROM stories " "WHERE NOT genre <> \"science fiction\" AND NOT year <= 1970", stories >; int main() { stories s{ sql::load(perf_folder + stories_data, '\t') }; for (std::size_t i{}; i < iters; ++i) { for (query q{ s }; auto const& [t, g, y] : q) { std::cout << t << '\t' << g << '\t' << y << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/lib-query1.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT title, genre AS type, year AS published, pages " "FROM books " "WHERE NOT genre <> \"science fiction\" AND NOT year >= 1970 OR pages < 300", books >; int main() { books b{ sql::load(perf_folder + books_data), '\t' }; for (std::size_t i{}; i < iters; ++i) { for (query q{ b }; auto const& [t, g, y, p] : q) { std::cout << t << '\t' << g << '\t' << y << '\t' << p << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/lib-query2.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT genre AS type, name " "FROM books NATURAL JOIN authored " "WHERE NOT genre = \"science fiction\" AND name != \"Harlan Ellison\"", books, authored >; int main() { books b{ sql::load(perf_folder + books_data, '\t') }; authored a{ sql::load(perf_folder + authored_data, '\t') }; for (std::size_t i{}; i < iters; ++i) { for (query q{ b, a }; auto const& [g, n] : q) { std::cout << g << '\t' << n << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/lib-query3.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT genre AS type, year AS published, title, name " "FROM stories NATURAL JOIN authored " "WHERE genre = \"science fiction\" AND year > 1970 AND name != \"Harlan Elison\"", stories, authored >; int main() { stories s{ sql::load(perf_folder + stories_data, '\t') }; authored a{ sql::load(perf_folder + authored_data, '\t') }; for (std::size_t i{}; i < iters; ++i) { for (query q{ s, a }; auto const& [g, y, t, n] : q) { std::cout << g << '\t' << y << '\t' << t << '\t' << n << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/lib-query4.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT book, genre AS type, year As published " "FROM books CROSS JOIN authored " "WHERE NOT genre != \"science fiction\" AND year > 1970", books, authored >; int main() { books b{ sql::load(perf_folder + books_data '\t') }; authored a{ sql::load(perf_folder + authored_data, '\t') }; for (std::size_t i{}; i < iters / offset; ++i) { for (query q{ b, a }; auto const& [b, g, y] : q) { std::cout << b << '\t' << g << '\t' << y << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/lib-query5.cpp ================================================ #include #include "../../data.hpp" using query = sql::query< "SELECT story, genre AS type, year AS published, title, collection, pages " "FROM stories CROSS join collected " "WHERE genre != \"science fiction\" OR year >= 1970 OR NOT pages < 300", stories, collected >; int main() { stories s{ sql::load(perf_folder + stories_data, '\t') }; collected c{ sql::load(perf_folder + collected_data, '\t') }; for (std::size_t i{}; i < iters / offset; ++i) { for (query q{ s, c }; auto const& [s, g, y, t, c, p] : q) { std::cout << s << '\t' << g << '\t' << y << '\t' << t << '\t' << c << '\t' << p << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query0.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" stories_type query(stories_type const& s) { using std::get; stories_type output{}; for (auto const& row : s) { if (!(get<1>(row) != "science fiction") && !(get<2>(row) <= 1970)) { output.push_back(row); } } return output; } int main() { stories_type s{ stories_load<'\t'>() }; for (std::size_t i{}; i < iters; ++i) { for (auto data{ query(s) }; auto const& [t, g, y] : data) { std::cout << t << '\t' << g << '\t' << y << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query1.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" books_type query(books_type const& b) { using std::get; books_type output{}; for (auto const& row : b) { if (!(get<1>(row) != "science fiction") && !(get<2>(row) >= 1970) || get<3>(row) < 300) { output.push_back(row); } } return output; } int main() { books_type b{ books_load<'\t'>() }; for (std::size_t i{}; i < iters; ++i) { for (auto data{ query(b) }; auto const& [t, g, y, p] : data) { std::cout << t << '\t' << g << '\t' << y << '\t' << p << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query2.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" authored_type query(books_type const& b, authored_type const& a) { using std::get; authored_type output{}; std::unordered_map cache{}; for (auto const& row : a) { cache[get<0>(row)] = row; } for (auto const& b_row : b) { auto it{ cache.find(get<0>(b_row)) }; if (it != cache.end()) { auto const& a_row{ get<1>(*it) }; if (!(get<1>(b_row) == "science fiction") && get<1>(a_row) != "Harlan Ellison") { output.emplace_back(get<1>(b_row), get<1>(a_row)); } } } return output; } int main() { books_type b{ books_load<'\t'>() }; authored_type a{ authored_load<'\t'>() }; for (std::size_t i{}; i < iters; ++i) { for (auto data{ query(b, a) }; auto const& [g, n] : data) { std::cout << g << '\t' << n << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query3.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" using output_type = std::vector>; output_type query(stories_type const& s, authored_type const& a) { using std::get; output_type output{}; std::unordered_map cache{}; for (auto const& row : a) { cache[get<0>(row)] = row; } for (auto const& s_row : s) { auto it{ cache.find(get<0>(s_row)) }; if (it != cache.end()) { auto const& a_row{ get<1>(*it) }; if (get<1>(s_row) == "science fiction" && get<2>(s_row) > 1970 && get<1>(a_row) != "Harlan Ellison") { output.emplace_back(get<1>(s_row), get<2>(s_row), get<0>(a_row), get<1>(a_row)); } } } return output; } int main() { stories_type s{ stories_load<'\t'>() }; authored_type a{ authored_load<'\t'>() }; for (std::size_t i{}; i < iters; ++i) { for (auto data{ query(s, a) }; auto const& [g, y, t, n] : data) { std::cout << g << '\t' << y << '\t' << t << '\t' << n << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query4.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" using output_type = std::vector>; output_type query(books_type const& b, authored_type const& a) { using std::get; output_type output{}; for (auto const& a_row : a) { for (auto const& b_row : b) { if (!(get<1>(b_row) != "science fiction") && get<2>(b_row) > 1970) { output.emplace_back(get<0>(b_row), get<1>(b_row), get<2>(b_row)); } } } return output; } int main() { books_type b{ books_load<'\t'>() }; authored_type a{ authored_load<'\t'>() }; for (std::size_t i{}; i < iters / offset; ++i) { for (auto data{ query(b, a) }; auto const& [b, g, y] : data) { std::cout << b << '\t' << g << '\t' << y << '\n'; } } return 0; } ================================================ FILE: tests/perf/queries/query5.cpp ================================================ #include #include #include #include #include #include #include "../../data.hpp" using output_type = std::vector>; output_type query(stories_type const& s, collected_type const& c) { using std::get; output_type output{}; for (auto const& c_row : c) { for (auto const& s_row : s) { if (!(get<1>(s_row) != "science fiction") || get<2>(s_row) >= 1970 || !(get<2>(c_row) < 300)) { output.emplace_back(get<0>(s_row), get<1>(s_row), get<2>(s_row), get<0>(c_row), get<1>(c_row), get<2>(c_row)); } } } return output; } int main() { stories_type s{ stories_load<'\t'>() }; collected_type c{ collected_load<'\t'>() }; for (std::size_t i{}; i < iters / offset; ++i) { for (auto data{ query(s, c) }; auto const& [st, g, y, t, co, p] : data) { std::cout << st << '\t' << g << '\t' << y << '\t' << t << '\t' << co << '\t' << p << '\n'; } } return 0; } ================================================ FILE: tests/perf/runner.sh ================================================ python3 scripts/runner.py ================================================ FILE: tests/perf/scripts/runner.py ================================================ import os QUERIES = 6 def exe(file, q): if int(q) >= 4: os.system("g++ -std=c++2a -DCROSS -O3 -I../../single-header -o test queries/" + file) else: os.system("g++ -std=c++2a -O3 -I../../single-header -o test queries/" + file) os.system("/usr/bin/time -f \"%U user\" -o data/" + file[:-4] + " ./test > /dev/null") os.remove("test") def main(): print("Benchmark Test Begin") for q in range(QUERIES): q = str(q) print("\tTest Query " + q) exe("lib-query" + q + ".cpp", q) exe("query" + q + ".cpp", q) print("Benchmark Test End") if __name__ == "__main__": main() ================================================ FILE: tests/runner.sh ================================================ mkdir queries python3 scripts/generate.py python3 scripts/runner.py ================================================ FILE: tests/scripts/compose.py ================================================ # Composes a test file begin = """#include #include "data.hpp" using query = sql::query< """ middle = """ >; int main() { """ end = """ return 0; } """ def data(tokens): f = False cs = 1 ts = [] for tk in tokens: tk = tk.lower() if tk[-1] == ",": cs += 1 if tk == "where": break if tk == "from": f = True elif f and tk != "cross" and tk != "natural" and tk != "join": ts += [tk] return cs, ts def templ(query, ts): templ_spec = "\t\t\"" + query + "\"" for t in ts: templ_spec += ",\n\t\t" + t return templ_spec def func(ts, cs): body = "" args = "" out = "\tstd::cout << " count = 0 for t in ts: body += "\t" + t + " t" + str(count) + "{ sql::load<" + t + ">(data_folder + " + t + "_data, '\\t') };\n" args += "t" + str(count) + ", " count += 1 body += "\n\tfor (query q{ " + args[:-2] + " }; auto const& [" for c in range(cs): body += "c" + str(c) + ", " out += "c" + str(c) + " << \'|\' << " body = body[:-2] + "] : q)\n\t{\n\t" + out[:-11] + " << \'\\n\';\n\t}\n" return body def main(): infile = open("queries/query", "r") query = infile.readline().strip() infile.close() tokens = query.split() cs, ts = data(tokens[1:]) spec = templ(query, ts) body = func(ts, cs) outfile = open("test.cpp", "w") outfile.write(begin + spec + middle + body + end) outfile.close() if __name__ == "__main__": main() ================================================ FILE: tests/scripts/generate.py ================================================ # SQL query generator for test queries # Generates over 1.4 million unique queries import itertools import random tables = ["books", "stories", "authored", "collected"] columns = { "books": ["book", "genre", "year", "pages"], "stories": ["story", "genre", "year"], "authored": ["title", "name"], "collected": ["title", "collection", "pages"] } joinable = { "books": ["authored"], "stories": ["authored", "collected"], "authored": [], "collected": [] } joins = ["cross"] renames = { "genre": "type", "year": "published" } integral = ["year", "pages"] all_comp = ["=", "!=", "<>"] integral_comp = [">", "<", ">=", "<="] bool_op = ["or", "and"] negate_op = ["", "not "] where_data = { "name": ["Harlan Ellison"], "year": [1970], "pages": [300], "genre": ["science fiction"] } outfiles = { "joinless": open("queries/joinless-queries.txt", "w"), "cross": open("queries/cross-queries.txt", "w") } def col_list(cs): cl = [] re = False cols = "" for c in cs: cols += c if c in renames.keys(): cols += " as " + renames[c] re = True cols += ", " cl += [cols[:-2]] if re: cols = "" for c in cs: cols += c cols += ", " cl += [cols[:-2]] return cl def froms(ts): f = [] output = outfiles["joinless"] if len(ts) == 1: f = [ts[0]] else: for j in joins: output = outfiles[j] if random.random() < 0.3333: j = j.upper() f += [ts[0] + " " + j + " join " + ts[1]] return f, output def compose(ts, cs, pred): if pred != "": pred = " where " + pred cols = col_list(cs) sel, output = froms(ts) for s in sel: for c in cols: output.write("select " + c + " from " + s + pred + "\n") def next(cs, ci): if ci >= len(cs): return -1 else: while not cs[ci] in where_data.keys(): ci += 1 if ci >= len(cs): return -1 return ci def predicate(ts, cs, ci, pred): ci = next(cs, ci) if ci == -1: compose(ts, cs, pred) else: for op in bool_op: if random.random() < 0.3333: op = op.upper() p = pred + " " + op + " " operation(ts, cs, ci, p) def operation(ts, cs, ci, pred): c = cs[ci] ops = [] ops += all_comp if c in integral: ops += integral_comp for nop in negate_op: for op in ops: for data in where_data[c]: if random.random() < 0.3333: nop = nop.upper() p = pred p += nop + c + " " + op + " " if type(data) is str: p += "\\\"" + data + "\\\"" else: p += str(data) predicate(ts, cs, ci + 1, p) def select(ts): cols = [] for t in ts: cols += columns[t] for i in range(len(cols)): comb = list(itertools.combinations(cols, i + 1)) for cs in comb: ci = next(cs, 0) if ci == -1: compose(ts, cs, "") else: pred = operation(ts, cs, ci, "") def root_query(left): select([left]) for right in joinable[left]: select([left, right]) def main(): print("Test Generator") for table in tables: print("\tGenerating queries for \"" + table + "\" schema") root_query(table) if __name__ == "__main__": main() for file in outfiles.keys(): outfiles[file].close() joins = ["natural"] outfiles = { "joinless": open("queries/joinless-queries.txt", "w"), "natural": open("queries/natural-queries.txt", "w") } columns = { "books": ["title", "genre", "year", "pages"], "stories": ["title", "genre", "year"], "authored": ["title", "name"], "collected": ["title", "collection", "pages"] } main() for file in outfiles.keys(): outfiles[file].close() ================================================ FILE: tests/scripts/runner.py ================================================ import os def main(): print("Test Runner") os.system("python3 scripts/select.py") print("\tTest queries selected") num = 1 token = "" db = "library.db" with open("queries/test-queries.txt", "r") as queries: for query in queries: query = query.strip() if query[0] != "s": token = query if query == "CROSS": db = "library-cross.db" continue q = open("queries/query", "w") q.write(query + "\n") q.close() os.system("python3 scripts/compose.py") os.system("g++ -std=c++2a " + "-D" + token + " -O3 -I../single-header -o test test.cpp") os.system("./test | sort > cpp-results.txt") os.system("sqlite3 data/" + db + " \"" + query + ";\" | sort > sql-results.txt") stream = os.popen("diff cpp-results.txt sql-results.txt") res = "Passed" for line in stream: res = "Failed" break print("\tTest " + str(num) + ":\t" + res + "\n\t\t" + query) if res == "Failed": exit() num += 1 os.remove("cpp-results.txt") os.remove("sql-results.txt") os.remove("queries/test-queries.txt") os.remove("queries/query") if __name__ == "__main__": main() ================================================ FILE: tests/scripts/select.py ================================================ # Randomly selects ~500 queries to test from the 1.4mil query set import random def main(): outfile = open("queries/test-queries.txt", "w") #h = 100 / 23000 #h = 0 h = 1.0 outfile.write("JOINLESS\n") with open("queries/joinless-queries.txt", "r") as infile: for line in infile: if random.random() < h: outfile.write(line) #h = 500 / 700000 outfile.write("NATURAL\n") with open("queries/natural-queries.txt", "r") as infile: for line in infile: if random.random() < h: outfile.write(line) outfile.write("CROSS\n") with open("queries/cross-queries.txt", "r") as infile: for line in infile: if random.random() < h: outfile.write(line) outfile.close() if __name__ == "__main__": main()