├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── COPYING ├── README.md ├── cmake_modules └── Findlibunwind.cmake ├── libsqltoast ├── CMakeLists.txt ├── include │ └── sqltoast │ │ ├── column_definition.h │ │ ├── column_reference.h │ │ ├── constraint.h │ │ ├── data_type.h │ │ ├── debug.h │ │ ├── identifier.h │ │ ├── lexeme.h │ │ ├── predicate.h │ │ ├── print.h │ │ ├── query.h │ │ ├── sqltoast.h.in │ │ ├── statement.h │ │ ├── table_reference.h │ │ ├── value.h │ │ └── value_expression.h └── src │ ├── parser │ ├── column_definition.cc │ ├── comment.cc │ ├── comment.h │ ├── compare.h │ ├── constraint.cc │ ├── context.cc │ ├── context.h │ ├── data_type_descriptor.cc │ ├── error.cc │ ├── error.h │ ├── identifier.cc │ ├── identifier.h │ ├── keyword.cc │ ├── keyword.h │ ├── lexer.cc │ ├── lexer.h │ ├── literal.cc │ ├── literal.h │ ├── parse.cc │ ├── parse.h │ ├── predicate.cc │ ├── query.cc │ ├── sequence.cc │ ├── sequence.h │ ├── special.h │ ├── statement.cc │ ├── statements │ │ ├── alter_table.cc │ │ ├── commit.cc │ │ ├── create_schema.cc │ │ ├── create_table.cc │ │ ├── create_view.cc │ │ ├── delete.cc │ │ ├── drop_schema.cc │ │ ├── drop_table.cc │ │ ├── drop_view.cc │ │ ├── grant.cc │ │ ├── insert.cc │ │ ├── rollback.cc │ │ ├── select.cc │ │ └── update.cc │ ├── symbol.cc │ ├── symbol.h │ ├── table_reference.cc │ ├── token.cc │ ├── token.h │ ├── value.cc │ └── value_expression.cc │ └── print │ ├── column_definition.cc │ ├── column_reference.cc │ ├── constraint.cc │ ├── data_type.cc │ ├── identifier.cc │ ├── predicate.cc │ ├── query.cc │ ├── statement.cc │ ├── table_reference.cc │ ├── value.cc │ └── value_expression.cc ├── sqltoaster ├── CMakeLists.txt ├── fill.h ├── main.cc ├── measure.h ├── node.cc ├── node.h ├── node │ └── statement.cc ├── printer.cc └── printer.h └── tests └── grammar ├── ansi-92 ├── alter-table.test ├── case-expressions.test ├── column-definitions.test ├── create-schema.test ├── create-table.test ├── create-view.test ├── datetime-expressions.test ├── delete.test ├── drop-schema.test ├── drop-table.test ├── drop-view.test ├── grant.test ├── identifiers.test ├── insert-select.test ├── insert-values.test ├── interval-expressions.test ├── joins.test ├── numeric-expressions.test ├── predicates.test ├── row-value-constructors.test ├── string-expressions.test ├── table-references.test └── update.test └── runner.py /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | _install 3 | # We generate this file... 4 | libsqltoast/include/sqltoast/sqltoast.h 5 | *.~ 6 | *.swp 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: gcc 3 | matrix: 4 | include: 5 | # works on Precise and Trusty 6 | - os: linux 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - g++-4.9 13 | env: 14 | - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" 15 | # works on Precise and Trusty 16 | - os: linux 17 | addons: 18 | apt: 19 | sources: 20 | - ubuntu-toolchain-r-test 21 | packages: 22 | - g++-5 23 | env: 24 | - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" 25 | # works on Precise and Trusty 26 | - os: linux 27 | addons: 28 | apt: 29 | sources: 30 | - ubuntu-toolchain-r-test 31 | packages: 32 | - g++-6 33 | env: 34 | - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" 35 | # works on Precise and Trusty 36 | - os: linux 37 | addons: 38 | apt: 39 | sources: 40 | - ubuntu-toolchain-r-test 41 | packages: 42 | - g++-7 43 | env: 44 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" 45 | 46 | before_install: 47 | - eval "${MATRIX_EVAL}" 48 | script: 49 | - mkdir -p _build 50 | - cd _build 51 | - cmake .. -DCMAKE_BUILD_TYPE=fast 52 | - make 53 | - cd ../tests/grammar 54 | - python runner.py run 55 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.4) 2 | PROJECT(sqltoast) 3 | 4 | # String comparisons in cmake are case-sensitive and unfortunately, CamelCase 5 | # is used for many examples/tutorials, so people do things like cmake .. 6 | # -DCMAKE_BUILD_TYPE=Debug. We want to only have to compare lower-cased build 7 | # types, so we have a variable here that lower-cases the build type and stores 8 | # it in a cache variable for use by the other cmakes. 9 | STRING(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER) 10 | 11 | SET( 12 | CMAKE_MODULE_PATH 13 | ${CMAKE_MODULE_PATH} 14 | "${CMAKE_SOURCE_DIR}/cmake_modules" 15 | ) 16 | 17 | # Must use GNUInstallDirs to install libraries into correct 18 | # locations on all platforms. 19 | INCLUDE(GNUInstallDirs) 20 | 21 | ADD_SUBDIRECTORY(libsqltoast) 22 | ADD_SUBDIRECTORY(sqltoaster) 23 | -------------------------------------------------------------------------------- /cmake_modules/Findlibunwind.cmake: -------------------------------------------------------------------------------- 1 | # Yanked and slightly modified from here: 2 | # https://github.com/cmccabe/lksmith/tree/\ 3 | # f1a85b2d08348b47892c0957840b525045433e72/cmake_modules 4 | # 5 | # Find the libunwind library 6 | # 7 | # LIBUNWIND_FOUND - True if libunwind was found. 8 | # LIBUNWIND_LIBRARIES - The libraries needed to use libunwind 9 | # LIBUNWIND_INCLUDE_DIR - Location of unwind.h and libunwind.h 10 | 11 | FIND_PATH(LIBUNWIND_INCLUDE_DIR libunwind.h) 12 | if(NOT LIBUNWIND_INCLUDE_DIR) 13 | message(FATAL_ERROR "Failed to find libunwind.h. 14 | Please install libunwind when building the debug libsqltoast binaries. On Debian/Ubuntu systems, this package is called libunwind-dev. 15 | ") 16 | elif(NOT EXISTS "${LIBUNWIND_INCLUDE_DIR}/unwind.h") 17 | message(FATAL_ERROR "libunwind.h was found, but unwind.h was not found in that directory.") 18 | SET(LIBUNWIND_INCLUDE_DIR "") 19 | endif() 20 | 21 | FIND_LIBRARY(LIBUNWIND_GENERIC_LIBRARY "unwind") 22 | if (NOT LIBUNWIND_GENERIC_LIBRARY) 23 | MESSAGE(FATAL_ERROR "Failed to find unwind generic library") 24 | endif () 25 | SET(LIBUNWIND_LIBRARIES ${LIBUNWIND_GENERIC_LIBRARY}) 26 | 27 | # For some reason, we have to link to two libunwind shared object files: 28 | # one arch-specific and one not. 29 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") 30 | SET(LIBUNWIND_ARCH "arm") 31 | elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") 32 | SET(LIBUNWIND_ARCH "x86_64") 33 | elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") 34 | SET(LIBUNWIND_ARCH "x86") 35 | endif() 36 | 37 | if (LIBUNWIND_ARCH) 38 | FIND_LIBRARY(LIBUNWIND_SPECIFIC_LIBRARY "unwind-${LIBUNWIND_ARCH}") 39 | if (NOT LIBUNWIND_SPECIFIC_LIBRARY) 40 | MESSAGE(FATAL_ERROR "Failed to find unwind-${LIBUNWIND_ARCH}") 41 | endif () 42 | SET(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ${LIBUNWIND_SPECIFIC_LIBRARY}) 43 | endif(LIBUNWIND_ARCH) 44 | 45 | MARK_AS_ADVANCED(LIBUNWIND_LIBRARIES LIBUNWIND_INCLUDE_DIR) 46 | -------------------------------------------------------------------------------- /libsqltoast/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(libsqltoast VERSION 0.1 LANGUAGES CXX) 2 | 3 | SET(PROJECT_DESCRIPTION "A recursive descent parser for SQL") 4 | SET(SQLTOAST_VERSION_MAJOR 0) 5 | SET(SQLTOAST_VERSION_MINOR 1) 6 | SET(LIBSQLTOAST_SOURCES 7 | src/parser/column_definition.cc 8 | src/parser/data_type_descriptor.cc 9 | src/parser/comment.cc 10 | src/parser/constraint.cc 11 | src/parser/context.cc 12 | src/parser/error.cc 13 | src/parser/keyword.cc 14 | src/parser/identifier.cc 15 | src/parser/lexer.cc 16 | src/parser/literal.cc 17 | src/parser/parse.cc 18 | src/parser/predicate.cc 19 | src/parser/query.cc 20 | src/parser/sequence.cc 21 | src/parser/statement.cc 22 | src/parser/statements/alter_table.cc 23 | src/parser/statements/create_schema.cc 24 | src/parser/statements/create_table.cc 25 | src/parser/statements/create_view.cc 26 | src/parser/statements/delete.cc 27 | src/parser/statements/drop_schema.cc 28 | src/parser/statements/drop_table.cc 29 | src/parser/statements/drop_view.cc 30 | src/parser/statements/grant.cc 31 | src/parser/statements/insert.cc 32 | src/parser/statements/rollback.cc 33 | src/parser/statements/select.cc 34 | src/parser/statements/commit.cc 35 | src/parser/statements/update.cc 36 | src/parser/symbol.cc 37 | src/parser/table_reference.cc 38 | src/parser/token.cc 39 | src/parser/value.cc 40 | src/parser/value_expression.cc 41 | src/print/column_definition.cc 42 | src/print/column_reference.cc 43 | src/print/constraint.cc 44 | src/print/data_type.cc 45 | src/print/identifier.cc 46 | src/print/predicate.cc 47 | src/print/query.cc 48 | src/print/statement.cc 49 | src/print/table_reference.cc 50 | src/print/value.cc 51 | src/print/value_expression.cc 52 | ) 53 | 54 | ADD_LIBRARY(sqltoast STATIC ${LIBSQLTOAST_SOURCES}) 55 | SET_TARGET_PROPERTIES(sqltoast PROPERTIES 56 | CXX_STANDARD 14 57 | CXX_STANDARD_REQUIRED YES 58 | CXX_EXTENSIONS NO 59 | ) 60 | SET(LIBSQLTOAST_BUILD_OPTS, "-Wall --no-rtti") 61 | TARGET_COMPILE_OPTIONS(sqltoast 62 | PUBLIC ${LIBSQLTOAST_BUILD_OPTS} 63 | ) 64 | 65 | # To build with debugging symbols and some extra tracing functionality, do: 66 | # 67 | # $ROOT_DIR/build $> cmake -DCMAKE_BUILD_TYPE=debug .. 68 | SET(LIBSQLTOAST_BUILD_DEBUG_OPTS, "-Werror -DSQLTOAST_DEBUG") 69 | TARGET_COMPILE_OPTIONS(sqltoast 70 | PRIVATE "$<$:${LIBSQLTOAST_BUILD_DEBUG_OPTS}>" 71 | ) 72 | 73 | # To build a speed-optimized binary, do: 74 | # 75 | # $ROOT_DIR/build $> cmake -DCMAKE_BUILD_TYPE=release .. 76 | SET(LIBSQLTOAST_BUILD_RELEASE_OPTS, "-O2 -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1") 77 | TARGET_COMPILE_OPTIONS(sqltoast 78 | PRIVATE "$<$:${LIBSQLTOAST_BUILD_RELEASE_OPTS}>" 79 | ) 80 | 81 | # Header file for configuration templated variables 82 | CONFIGURE_FILE( 83 | "${PROJECT_SOURCE_DIR}/include/sqltoast/sqltoast.h.in" 84 | "${PROJECT_SOURCE_DIR}/include/sqltoast/sqltoast.h" 85 | ) 86 | 87 | # Header files in src/ are private and not exported for public sqltoast 88 | # interfaces 89 | TARGET_INCLUDE_DIRECTORIES(sqltoast 90 | PUBLIC 91 | $ 92 | $ 93 | PRIVATE 94 | src) 95 | 96 | # Include libunwind when we're in debug mode 97 | if (${BUILD_TYPE_LOWER} STREQUAL "debug") 98 | FIND_PACKAGE(libunwind REQUIRED) 99 | TARGET_LINK_LIBRARIES(sqltoast ${LIBUNWIND_LIBRARIES}) 100 | endif () 101 | 102 | # 'make install' to the correct locations (provided by GNUInstallDirs). 103 | INSTALL(TARGETS sqltoast EXPORT sqltoast_config 104 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 105 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 106 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # This is for Windows 107 | 108 | # This makes the project importable from the install directory 109 | # Put config file in per-project dir (name MUST match), can also 110 | # just go into 'cmake'. 111 | INSTALL(EXPORT sqltoast_config DESTINATION share/sqltoast/cmake) 112 | 113 | # This makes the project importable from the build directory 114 | EXPORT(TARGETS sqltoast FILE sqltoast_config.cmake) 115 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/column_definition.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_COLUMN_DEFINITION_H 8 | #define SQLTOAST_COLUMN_DEFINITION_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef enum default_type { 13 | DEFAULT_TYPE_LITERAL, 14 | DEFAULT_TYPE_USER, 15 | DEFAULT_TYPE_CURRENT_USER, 16 | DEFAULT_TYPE_SESSION_USER, 17 | DEFAULT_TYPE_SYSTEM_USER, 18 | DEFAULT_TYPE_CURRENT_DATE, 19 | DEFAULT_TYPE_CURRENT_TIME, 20 | DEFAULT_TYPE_CURRENT_TIMESTAMP, 21 | DEFAULT_TYPE_NULL 22 | } default_type_t; 23 | 24 | typedef struct default_descriptor { 25 | default_type_t type; 26 | lexeme_t lexeme; 27 | size_t precision; 28 | default_descriptor(default_type_t type, lexeme_t lexeme, size_t prec) : 29 | type(type), 30 | lexeme(lexeme), 31 | precision(prec) 32 | {} 33 | } default_descriptor_t; 34 | 35 | typedef struct column_definition { 36 | lexeme_t name; 37 | std::unique_ptr data_type; 38 | std::unique_ptr default_descriptor; 39 | std::vector> constraints; 40 | lexeme_t collate; 41 | column_definition( 42 | lexeme_t& name, 43 | std::unique_ptr& data_type, 44 | std::unique_ptr& default_descriptor, 45 | std::vector>& constraints) : 46 | name(name), 47 | data_type(std::move(data_type)), 48 | default_descriptor(std::move(default_descriptor)), 49 | constraints(std::move(constraints)) 50 | {} 51 | } column_definition_t; 52 | 53 | } // namespace sqltoast 54 | 55 | #endif /* SQLTOAST_COLUMN_DEFINITION_H */ 56 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/column_reference.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_COLUMN_REFERENCE_H 8 | #define SQLTOAST_COLUMN_REFERENCE_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef struct derived_column { 13 | lexeme_t alias; 14 | std::unique_ptr value; 15 | // Specialized constructor for the "asterisk" projection 16 | derived_column() 17 | {} 18 | derived_column(std::unique_ptr& ve) : 19 | value(std::move(ve)) 20 | {} 21 | inline bool has_alias() const { 22 | return alias.start != parse_position_t(0); 23 | } 24 | } derived_column_t; 25 | 26 | typedef struct grouping_column_reference { 27 | lexeme_t column; 28 | lexeme_t collation; 29 | grouping_column_reference(lexeme_t& column) : 30 | column(column) 31 | {} 32 | inline bool has_collation() const { 33 | return collation.start != parse_position_t(0); 34 | } 35 | } grouping_column_reference_t; 36 | 37 | } // namespace sqltoast 38 | 39 | #endif /* SQLTOAST_COLUMN_REFERENCE_H */ 40 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/constraint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_CONSTRAINT_H 8 | #define SQLTOAST_CONSTRAINT_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef enum constraint_type { 13 | CONSTRAINT_TYPE_UNKNOWN, 14 | CONSTRAINT_TYPE_NOT_NULL, 15 | CONSTRAINT_TYPE_UNIQUE, 16 | CONSTRAINT_TYPE_PRIMARY_KEY, 17 | CONSTRAINT_TYPE_FOREIGN_KEY, 18 | CONSTRAINT_TYPE_CHECK 19 | } constraint_type_t; 20 | 21 | typedef struct constraint { 22 | constraint_type_t type; 23 | lexeme_t name; 24 | std::vector columns; 25 | constraint(constraint_type_t type) : 26 | type(type) 27 | {} 28 | } constraint_t; 29 | 30 | typedef struct not_null_constraint : constraint_t { 31 | not_null_constraint() : 32 | constraint_t(CONSTRAINT_TYPE_NOT_NULL) 33 | {} 34 | } not_null_constraint_t; 35 | 36 | typedef struct unique_constraint : constraint_t { 37 | unique_constraint(bool is_primary) : 38 | constraint_t(is_primary ? CONSTRAINT_TYPE_PRIMARY_KEY : CONSTRAINT_TYPE_UNIQUE) 39 | {} 40 | } unique_constraint_t; 41 | 42 | typedef enum match_type { 43 | MATCH_TYPE_NONE, 44 | MATCH_TYPE_FULL, 45 | MATCH_TYPE_PARTIAL 46 | } match_type_t; 47 | 48 | typedef enum referential_action { 49 | REFERENTIAL_ACTION_NONE, 50 | REFERENTIAL_ACTION_CASCADE, 51 | REFERENTIAL_ACTION_SET_NULL, 52 | REFERENTIAL_ACTION_SET_DEFAULT 53 | } referential_action_t; 54 | 55 | typedef struct foreign_key_constraint : constraint_t { 56 | lexeme_t referenced_table; 57 | std::vector referenced_columns; 58 | match_type_t match_type; 59 | referential_action_t on_update; 60 | referential_action_t on_delete; 61 | foreign_key_constraint( 62 | lexeme_t& ref_table, 63 | std::vector& referenced_cols, 64 | match_type_t match_type, 65 | referential_action_t on_update, 66 | referential_action_t on_delete) : 67 | constraint(CONSTRAINT_TYPE_FOREIGN_KEY), 68 | referenced_table(ref_table), 69 | referenced_columns(std::move(referenced_cols)), 70 | match_type(match_type), 71 | on_update(on_update), 72 | on_delete(on_delete) 73 | {} 74 | } foreign_key_constraint_t; 75 | 76 | } // namespace sqltoast 77 | 78 | #endif /* SQLTOAST_CONSTRAINT_H */ 79 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/data_type.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_DATA_TYPE_H 8 | #define SQLTOAST_DATA_TYPE_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef enum data_type { 13 | DATA_TYPE_CHAR, 14 | DATA_TYPE_VARCHAR, 15 | DATA_TYPE_NCHAR, 16 | DATA_TYPE_NVARCHAR, 17 | DATA_TYPE_BIT, 18 | DATA_TYPE_VARBIT, 19 | DATA_TYPE_NUMERIC, 20 | DATA_TYPE_INT, 21 | DATA_TYPE_SMALLINT, 22 | DATA_TYPE_FLOAT, 23 | DATA_TYPE_DOUBLE, 24 | DATA_TYPE_DATE, 25 | DATA_TYPE_TIME, 26 | DATA_TYPE_TIMESTAMP, 27 | DATA_TYPE_INTERVAL 28 | } data_type_t; 29 | 30 | typedef struct data_type_descriptor { 31 | data_type_t type; 32 | data_type_descriptor(data_type_t type) : type(type) 33 | {} 34 | } data_type_descriptor_t; 35 | 36 | typedef struct char_string : data_type_descriptor_t { 37 | size_t size; 38 | lexeme_t charset; 39 | char_string(data_type_t type, size_t size) : 40 | data_type_descriptor_t(type), 41 | size(size) 42 | {} 43 | char_string(data_type_t type, size_t size, lexeme_t charset) : 44 | data_type_descriptor_t(type), 45 | size(size), 46 | charset(charset) 47 | {} 48 | } char_string_t; 49 | 50 | typedef struct bit_string : data_type_descriptor_t { 51 | size_t size; 52 | bit_string(data_type_t type, size_t size) : 53 | data_type_descriptor_t(type), 54 | size(size) 55 | {} 56 | } bit_string_t; 57 | 58 | typedef struct exact_numeric : data_type_descriptor_t { 59 | size_t precision; 60 | size_t scale; 61 | exact_numeric(data_type_t type, size_t prec, size_t scale) : 62 | data_type_descriptor_t(type), 63 | precision(prec), 64 | scale(scale) 65 | {} 66 | } exact_numeric_t; 67 | 68 | typedef struct approximate_numeric : data_type_descriptor_t { 69 | size_t precision; 70 | approximate_numeric(data_type_t type, size_t prec) : 71 | data_type_descriptor_t(type), 72 | precision(prec) 73 | {} 74 | } approximate_numeric_t; 75 | 76 | typedef struct datetime : data_type_descriptor_t { 77 | size_t precision; 78 | bool with_tz; 79 | datetime(data_type_t type, size_t prec, bool with_tz) : 80 | data_type_descriptor_t(type), 81 | precision(prec), 82 | with_tz(with_tz) 83 | {} 84 | } datetime_t; 85 | 86 | // TOOD(jaypipes): Move datetime and interval stuff to a separate temporal.h 87 | // file 88 | typedef enum interval_unit { 89 | INTERVAL_UNIT_YEAR, 90 | INTERVAL_UNIT_MONTH, 91 | INTERVAL_UNIT_DAY, 92 | INTERVAL_UNIT_HOUR, 93 | INTERVAL_UNIT_MINUTE, 94 | INTERVAL_UNIT_SECOND 95 | } interval_unit_t; 96 | 97 | typedef struct interval : data_type_descriptor_t { 98 | interval_unit_t unit; 99 | size_t precision; 100 | interval(interval_unit_t unit, size_t prec) : 101 | data_type_descriptor_t(DATA_TYPE_INTERVAL), 102 | unit(unit), 103 | precision(prec) 104 | {} 105 | } interval_t; 106 | 107 | } // namespace sqltoast 108 | 109 | #endif /* SQLTOAST_DATA_TYPE_H */ 110 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_DEBUG_H 8 | #define SQLTOAST_DEBUG_H 9 | 10 | #if defined(SQLTOAST_DEBUG) 11 | 12 | #include 13 | 14 | #include 15 | 16 | namespace sqltoast { 17 | 18 | // The following code was yanked from 19 | // https://blog.galowicz.de/2016/02/20/short_file_macro/ 20 | using cstr = const char* const; 21 | 22 | static constexpr cstr past_last_slash(cstr str, cstr last_slash) 23 | { 24 | return *str == '\0' ? last_slash : 25 | *str == '/' ? past_last_slash(str + 1, str + 1) : 26 | past_last_slash(str + 1, last_slash); 27 | } 28 | 29 | static constexpr cstr past_last_slash(cstr str) 30 | { 31 | return past_last_slash(str, str); 32 | } 33 | 34 | #define __SHORT_FILE__ ({constexpr cstr sf__ {past_last_slash(__FILE__)}; sf__;}) 35 | 36 | template 37 | void debug_print(const T& v) { 38 | std::cerr << v << std::endl; 39 | } 40 | template 41 | void debug_print(const T& v, Args... rest) { 42 | std::cerr << v; 43 | debug_print(rest...); 44 | } 45 | template 46 | void debug_print(const char *file, int line_no, const char *fn, Args... args) { 47 | std::cerr << file << '[' << line_no << "] " << fn << "(): "; 48 | debug_print(args...); 49 | } 50 | 51 | } // namespace sqltoast 52 | 53 | #define ST_DBG(...) sqltoast::debug_print(__SHORT_FILE__, __LINE__, __func__, __VA_ARGS__) 54 | 55 | #else // defined(SQLTOAST_DEBUG) 56 | 57 | #define ST_DBG(fmt, ...) 58 | 59 | #endif // defined(SQLTOAST_DEBUG) 60 | 61 | #endif /* SQLTOAST_DEBUG_H */ 62 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/identifier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_IDENTIFIER_H 8 | #define SQLTOAST_IDENTIFIER_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef struct identifier { 13 | const std::string name; 14 | identifier(lexeme_t& lexeme) : name(lexeme.start, lexeme.end) 15 | {} 16 | } identifier_t; 17 | 18 | } // namespace sqltoast 19 | 20 | #endif /* SQLTOAST_IDENTIFIER_H */ 21 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/lexeme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_LEXEME_H 8 | #define SQLTOAST_LEXEME_H 9 | 10 | namespace sqltoast { 11 | 12 | typedef std::vector parse_input_t; 13 | 14 | typedef parse_input_t::const_iterator parse_position_t; 15 | 16 | // A lexeme_t demarcates some word or phrase within the tokenized input stream 17 | typedef struct lexeme { 18 | parse_position_t start; 19 | parse_position_t end; 20 | lexeme() :start(0), end(0) 21 | {} 22 | lexeme( 23 | parse_position_t start, 24 | parse_position_t end) : 25 | start(start), end(end) 26 | {} 27 | inline size_t size() const { 28 | return end - start; 29 | } 30 | inline operator bool() const { 31 | return start != parse_position_t(0); 32 | } 33 | } lexeme_t; 34 | 35 | inline std::ostream& operator<< (std::ostream& out, const lexeme_t& word) { 36 | out << std::string(word.start, word.end); 37 | return out; 38 | } 39 | 40 | } // namespace sqltoast 41 | 42 | #endif /* SQLTOAST_STATEMENT_H */ 43 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/query.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_QUERY_H 8 | #define SQLTOAST_QUERY_H 9 | 10 | namespace sqltoast { 11 | 12 | // A table expression describes the tables involved in a query expression along 13 | // with filtering, grouping and aggregate expressions on those tables 14 | 15 | typedef struct table_expression { 16 | std::vector> referenced_tables; 17 | std::unique_ptr where_condition; 18 | std::vector group_by_columns; 19 | std::unique_ptr having_condition; 20 | table_expression( 21 | std::vector>& ref_tables, 22 | std::unique_ptr& where_cond, 23 | std::vector& group_by_cols, 24 | std::unique_ptr& having_cond) : 25 | referenced_tables(std::move(ref_tables)), 26 | where_condition(std::move(where_cond)), 27 | group_by_columns(std::move(group_by_cols)), 28 | having_condition(std::move(having_cond)) 29 | {} 30 | } table_expression_t; 31 | 32 | typedef struct query_specification { 33 | bool distinct; 34 | std::vector selected_columns; 35 | std::unique_ptr table_expression; 36 | query_specification( 37 | bool distinct, 38 | std::vector& selected_cols, 39 | std::unique_ptr& table_expression) : 40 | distinct(distinct), 41 | selected_columns(std::move(selected_cols)), 42 | table_expression(std::move(table_expression)) 43 | {} 44 | } query_specification_t; 45 | 46 | typedef enum query_expression_type_t { 47 | QUERY_EXPRESSION_TYPE_NON_JOIN_QUERY_EXPRESSION, 48 | QUERY_EXPRESSION_TYPE_JOINED_TABLE 49 | } query_expression_type_t; 50 | 51 | // A query expression produces a table-like selection of rows. 52 | 53 | typedef struct query_expression { 54 | query_expression_type_t query_expression_type; 55 | query_expression(query_expression_type_t qe_type) : 56 | query_expression_type(qe_type) 57 | {} 58 | } query_expression_t; 59 | 60 | typedef enum non_join_query_primary_type { 61 | NON_JOIN_QUERY_PRIMARY_TYPE_QUERY_SPECIFICATION, 62 | NON_JOIN_QUERY_PRIMARY_TYPE_TABLE_VALUE_CONSTRUCTOR, 63 | NON_JOIN_QUERY_PRIMARY_TYPE_EXPLICIT_TABLE, 64 | NON_JOIN_QUERY_PRIMARY_TYPE_SUBEXPRESSION 65 | } non_join_query_primary_type_t; 66 | 67 | typedef struct non_join_query_primary { 68 | non_join_query_primary_type primary_type; 69 | non_join_query_primary( 70 | non_join_query_primary_type_t primary_type) : 71 | primary_type(primary_type) 72 | {} 73 | } non_join_query_primary_t; 74 | 75 | typedef struct query_specification_non_join_query_primary : non_join_query_primary_t { 76 | std::unique_ptr query_spec; 77 | query_specification_non_join_query_primary( 78 | std::unique_ptr& query_spec) : 79 | non_join_query_primary_t(NON_JOIN_QUERY_PRIMARY_TYPE_QUERY_SPECIFICATION), 80 | query_spec(std::move(query_spec)) 81 | {} 82 | } query_specification_non_join_query_primary_t; 83 | 84 | typedef struct table_value_constructor { 85 | std::vector> values; 86 | table_value_constructor( 87 | std::vector>& values) : 88 | values(std::move(values)) 89 | {} 90 | } table_value_constructor_t; 91 | 92 | typedef struct table_value_constructor_non_join_query_primary : non_join_query_primary_t { 93 | std::unique_ptr table_value; 94 | table_value_constructor_non_join_query_primary( 95 | std::unique_ptr& table_value) : 96 | non_join_query_primary_t(NON_JOIN_QUERY_PRIMARY_TYPE_TABLE_VALUE_CONSTRUCTOR), 97 | table_value(std::move(table_value)) 98 | {} 99 | } table_value_constructor_non_join_query_primary_t; 100 | 101 | typedef struct non_join_query_term { 102 | std::unique_ptr primary; 103 | non_join_query_term( 104 | std::unique_ptr& primary) : 105 | primary(std::move(primary)) 106 | {} 107 | } non_join_query_term_t; 108 | 109 | typedef struct non_join_query_expression : query_expression_t { 110 | std::unique_ptr term; 111 | non_join_query_expression( 112 | std::unique_ptr& term) : 113 | query_expression_t(QUERY_EXPRESSION_TYPE_NON_JOIN_QUERY_EXPRESSION), 114 | term(std::move(term)) 115 | {} 116 | } non_join_query_expression_t; 117 | 118 | typedef struct joined_table_query_expression : query_expression_t { 119 | std::unique_ptr joined_table; 120 | joined_table_query_expression( 121 | std::unique_ptr& joined_table) : 122 | query_expression_t(QUERY_EXPRESSION_TYPE_JOINED_TABLE), 123 | joined_table(std::move(joined_table)) 124 | {} 125 | } joined_table_query_expression_t; 126 | 127 | } // namespace sqltoast 128 | 129 | #endif /* SQLTOAST_QUERY_H */ 130 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/sqltoast.h.in: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. Only edit the lnclude/sqltoast.h.in file, since sqltoast.h is 2 | // generated during build. 3 | #ifndef SQLTOAST_H 4 | #define SQLTOAST_H 5 | 6 | #define SQLTOAST_VERSION_MAJOR @SQLTOAST_VERSION_MAJOR@ 7 | #define SQLTOAST_VERSION_MINOR @SQLTOAST_VERSION_MINOR@ 8 | 9 | #if defined(__GNUC__) || defined(__clang__) 10 | #define SQLTOAST_UNREACHABLE() __builtin_unreachable() 11 | #else 12 | #define SQLTOAST_UNREACHABLE() assert(!"code should not be reachable") 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "lexeme.h" 21 | #include "identifier.h" 22 | #include "data_type.h" 23 | #include "constraint.h" 24 | #include "column_definition.h" 25 | #include "value.h" 26 | #include "value_expression.h" 27 | #include "column_reference.h" 28 | #include "predicate.h" 29 | #include "table_reference.h" 30 | #include "query.h" 31 | #include "statement.h" 32 | 33 | #include "debug.h" 34 | 35 | namespace sqltoast { 36 | 37 | // Dialects of SQL that can be parsed by sqltoast 38 | typedef enum sql_dialect { 39 | SQL_DIALECT_ANSI_1992, 40 | SQL_DIALECT_ANSI_1999, 41 | SQL_DIALECT_ANSI_2003 42 | } sql_dialect_t; 43 | 44 | // Possible return codes from parsing 45 | enum parse_result_code { 46 | PARSE_OK, 47 | PARSE_INPUT_ERROR, 48 | PARSE_SYNTAX_ERROR 49 | }; 50 | 51 | typedef enum error { 52 | ERR_NONE, 53 | ERR_NO_CLOSING_DELIMITER 54 | } error_t; 55 | 56 | typedef struct parse_options { 57 | // The dialect of SQL to parse the input with 58 | sql_dialect_t dialect; 59 | // If true, sqltoast::parse() will not attempt to create 60 | // sqltoast::statement objects during parsing. If all the caller is 61 | // interested in is determining whether a particular input is valid SQL and 62 | // parses to one or more SQL statements, this can reduce both the CPU time 63 | // taken as well as the memory usage of the parser. 64 | bool disable_statement_construction; 65 | } parse_options_t; 66 | 67 | typedef struct parse_result { 68 | parse_result_code code; 69 | std::string error; 70 | // As each SQL statement in an input stream is successfully parsed, a 71 | // sqltoast::statement derived object will be dynamically allocated and 72 | // pushed onto this vector 73 | std::vector> statements; 74 | } parse_result_t; 75 | 76 | parse_result_t parse(parse_input_t& subject); 77 | parse_result_t parse(parse_input_t& subject, parse_options_t &opts); 78 | 79 | } // namespace sqltoast 80 | 81 | #endif /* SQLTOAST_H */ 82 | -------------------------------------------------------------------------------- /libsqltoast/include/sqltoast/table_reference.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_TABLE_REFERENCE_H 8 | #define SQLTOAST_TABLE_REFERENCE_H 9 | 10 | namespace sqltoast { 11 | 12 | // A correlation specification is the parse element that indicates a table 13 | // reference's alias (technically called a "correlation name") and the optional 14 | // list of correlated column names. 15 | typedef struct correlation_spec { 16 | lexeme_t alias; 17 | std::vector columns; 18 | correlation_spec(lexeme_t& alias) : 19 | alias(alias) 20 | {} 21 | correlation_spec( 22 | lexeme_t& alias, 23 | std::vector& columns) : 24 | alias(alias), 25 | columns(std::move(columns)) 26 | {} 27 | } correlation_spec_t; 28 | 29 | typedef enum join_type { 30 | JOIN_TYPE_NONE, 31 | JOIN_TYPE_CROSS, 32 | JOIN_TYPE_INNER, 33 | JOIN_TYPE_LEFT, 34 | JOIN_TYPE_RIGHT, 35 | JOIN_TYPE_FULL, 36 | JOIN_TYPE_NATURAL, 37 | JOIN_TYPE_UNION 38 | } join_type_t; 39 | 40 | typedef struct join_specification { 41 | std::unique_ptr condition; 42 | std::vector named_columns; 43 | join_specification() 44 | {} 45 | join_specification(std::unique_ptr& join_cond) : 46 | condition(std::move(join_cond)) 47 | {} 48 | join_specification(std::vector& named_columns) : 49 | named_columns(std::move(named_columns)) 50 | {} 51 | } join_specification_t; 52 | 53 | typedef struct join_target { 54 | join_type_t join_type; 55 | std::unique_ptr table_ref; 56 | std::unique_ptr join_spec; 57 | join_target( 58 | join_type_t join_type, 59 | std::unique_ptr& table_ref, 60 | std::unique_ptr& join_spec) : 61 | join_type(join_type), 62 | table_ref(std::move(table_ref)), 63 | join_spec(std::move(join_spec)) 64 | {} 65 | join_target( 66 | join_type_t join_type, 67 | std::unique_ptr& table_ref) : 68 | join_type(join_type), 69 | table_ref(std::move(table_ref)) 70 | {} 71 | } join_target_t; 72 | 73 | // A table reference is an object whose columns are referenced in the 18 | // 19 | // ::= DISTINCT | ALL 20 | // 21 | // [ { ::= | 26 | // 27 | // ::= [ ] 28 | // 29 | // ::= [ AS ] 30 | // 31 | //
::= 32 | // 33 | // [ ] 34 | // [ ] 35 | // [ ] 36 | bool parse_select( 37 | parse_context_t& ctx, 38 | token_t& cur_tok, 39 | std::unique_ptr& out) { 40 | symbol_t cur_sym = cur_tok.symbol; 41 | std::unique_ptr query; 42 | 43 | if (! parse_query_specification(ctx, cur_tok, query)) 44 | return false; 45 | goto statement_ending; 46 | statement_ending: 47 | // We get here if we have already successfully processed the SELECT 48 | // statement and are expecting EOS or SEMICOLON as the next non-comment 49 | // token. Alternately, we can find an RPAREN, which would indicate we may 50 | // be at the end of a valid subquery, which is also fine. We rely on the 51 | // caller to check for the validity of an RPAREN in the current lexical 52 | // context. Finally, a SELECT, not enclosed by parens, is expected for the 53 | // CREATE VIEW statement, and the SELECT may be followed by a WITH 54 | // CHECK OPTION clause. So, we need to terminate with a WITH symbol as 55 | // well... 56 | cur_sym = cur_tok.symbol; 57 | if (cur_sym == SYMBOL_SEMICOLON || 58 | cur_sym == SYMBOL_EOS || 59 | cur_sym == SYMBOL_RPAREN || 60 | cur_sym == SYMBOL_WITH) 61 | goto push_statement; 62 | expect_any_error(ctx, {SYMBOL_EOS, SYMBOL_SEMICOLON, SYMBOL_RPAREN}); 63 | return false; 64 | push_statement: 65 | if (ctx.opts.disable_statement_construction) 66 | return true; 67 | out = std::make_unique(query); 68 | return true; 69 | } 70 | 71 | } // namespace sqltoast 72 | -------------------------------------------------------------------------------- /libsqltoast/src/parser/statements/update.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include 8 | 9 | #include "sqltoast/sqltoast.h" 10 | 11 | #include "parser/error.h" 12 | #include "parser/parse.h" 13 | 14 | namespace sqltoast { 15 | 16 | // ::= 17 | // UPDATE
SET [ WHERE ] 18 | // 19 | // ::= [ { } ... ] 20 | // 21 | // ::= 22 | // 23 | // ::= 24 | // 25 | // ::= | | DEFAULT 26 | bool parse_update( 27 | parse_context_t& ctx, 28 | token_t& cur_tok, 29 | std::unique_ptr& out) { 30 | lexer_t& lex = ctx.lexer; 31 | parse_position_t start = ctx.lexer.cursor; 32 | lexeme_t table_name; 33 | lexeme_t column_name; 34 | symbol_t cur_sym; 35 | std::unique_ptr value; 36 | std::vector set_columns; 37 | std::unique_ptr where_cond; 38 | 39 | cur_sym = cur_tok.symbol; 40 | if (cur_sym != SYMBOL_UPDATE) { 41 | ctx.lexer.cursor = start; 42 | return false; 43 | } 44 | cur_tok = lex.next(); 45 | goto expect_identifier; 46 | expect_identifier: 47 | // We get here after successfully finding UPDATE. We now need to find the 48 | // table identifier 49 | cur_sym = cur_tok.symbol; 50 | if (cur_sym != SYMBOL_IDENTIFIER) 51 | goto err_expect_identifier; 52 | table_name = cur_tok.lexeme; 53 | cur_tok = lex.next(); 54 | goto expect_set; 55 | err_expect_identifier: 56 | expect_error(ctx, SYMBOL_IDENTIFIER); 57 | return false; 58 | expect_set: 59 | // We get here after successfully finding UPDATE
. We now 60 | // expect to find the SET symbol followed by the set columns list. 61 | cur_sym = cur_tok.symbol; 62 | if (cur_sym != SYMBOL_SET) 63 | goto err_expect_set; 64 | cur_tok = lex.next(); 65 | goto process_set_column; 66 | err_expect_set: 67 | expect_error(ctx, SYMBOL_SET); 68 | return false; 69 | process_set_column: 70 | // Each set column is a column name followed by an equals sign and then the 71 | // NULL symbol, the DEFAULT symbol or a value expreession. 72 | cur_sym = cur_tok.symbol; 73 | if (cur_sym != SYMBOL_IDENTIFIER) 74 | goto err_expect_identifier; 75 | column_name = cur_tok.lexeme; 76 | cur_tok = lex.next(); 77 | cur_sym = cur_tok.symbol; 78 | if (cur_sym != SYMBOL_EQUAL) 79 | goto err_expect_equal; 80 | cur_tok = lex.next(); 81 | cur_sym = cur_tok.symbol; 82 | if (cur_sym == SYMBOL_NULL) { 83 | cur_tok = lex.next(); 84 | set_columns.emplace_back(set_column_t(SET_COLUMN_TYPE_NULL, column_name)); 85 | } else if (cur_sym == SYMBOL_DEFAULT) { 86 | cur_tok = lex.next(); 87 | set_columns.emplace_back(set_column_t(SET_COLUMN_TYPE_DEFAULT, column_name)); 88 | } else { 89 | if (! parse_value_expression(ctx, cur_tok, value)) 90 | goto err_expect_value_null_or_default; 91 | set_columns.emplace_back(set_column_t(column_name, value)); 92 | } 93 | cur_sym = cur_tok.symbol; 94 | if (cur_sym == SYMBOL_COMMA) { 95 | cur_tok = lex.next(); 96 | goto process_set_column; 97 | } 98 | goto optional_where; 99 | err_expect_equal: 100 | expect_error(ctx, SYMBOL_EQUAL); 101 | return false; 102 | err_expect_value_null_or_default: 103 | if (ctx.result.code == PARSE_SYNTAX_ERROR) 104 | return false; 105 | { 106 | std::stringstream estr; 107 | estr << "Expected to find NULL, DEFAULT or a << value expression >> for " 108 | "WHERE clause." << std::endl; 109 | create_syntax_error_marker(ctx, estr); 110 | return false; 111 | } 112 | optional_where: 113 | cur_sym = cur_tok.symbol; 114 | if (cur_sym == SYMBOL_WHERE) { 115 | cur_tok = lex.next(); 116 | if (! parse_search_condition(ctx, cur_tok, where_cond)) 117 | return false; 118 | } 119 | goto statement_ending; 120 | statement_ending: 121 | // We get here after successfully parsing the statement and now expect 122 | // either the end of parse content or a semicolon to indicate end of 123 | // statement. 124 | cur_sym = cur_tok.symbol; 125 | if (cur_sym == SYMBOL_SEMICOLON || cur_sym == SYMBOL_EOS) 126 | goto push_statement; 127 | expect_any_error(ctx, {SYMBOL_EOS, SYMBOL_SEMICOLON}); 128 | return false; 129 | push_statement: 130 | if (ctx.opts.disable_statement_construction) 131 | return true; 132 | if (where_cond) 133 | out = std::make_unique( 134 | table_name, set_columns, where_cond); 135 | else 136 | out = std::make_unique(table_name, set_columns); 137 | return true; 138 | } 139 | 140 | } // namespace sqltoast 141 | -------------------------------------------------------------------------------- /libsqltoast/src/parser/symbol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_PARSER_SYMBOL_H 8 | #define SQLTOAST_PARSER_SYMBOL_H 9 | 10 | #include 11 | #include 12 | 13 | namespace sqltoast { 14 | 15 | // A symbol is similar to a token type but represents the specific meaning of 16 | // the underlying lexeme. A token type represents the category of lexeme that 17 | // is tokenized. A symbol indicates the content of the lexeme. 18 | // 19 | // For example, the string "CREATE DATABASE id" will be tokenized into a vector 20 | // of three tokens: 21 | // * token_t { TOKEN_TYPE_KEYWORD ... } 22 | // * token_t { TOKEN_TYPE_KEYWORD ... } 23 | // * token_t { TOKEN_TYPE_IDENTIFIER ... } 24 | // 25 | // While tokenizing, we want to be able to indicate that the first two tokens 26 | // are not just of type TOKEN_TYPE_KEYWORD, but contain the keywords "CREATE" 27 | // and "DATABASE". However, of course, we don't want to store the strings 28 | // "CREATE" or "DATABASE". So, instead, we'll mark that the token represents 29 | // the SYMBOL_CREATE or SYMBOL_DATABASE symbols... 30 | typedef enum symbol { 31 | SYMBOL_NONE, 32 | SYMBOL_ERROR, 33 | 34 | SYMBOL_SOS, // Start of the input stream 35 | SYMBOL_EOS, // End of the input stream 36 | 37 | // Punctuators 38 | SYMBOL_ASTERISK, 39 | SYMBOL_COLON, 40 | SYMBOL_CONCATENATION, // This is the || double-char symbol 41 | SYMBOL_COMMA, 42 | SYMBOL_EQUAL, 43 | SYMBOL_EXCLAMATION, 44 | SYMBOL_GREATER_THAN, 45 | SYMBOL_LESS_THAN, 46 | SYMBOL_LPAREN, 47 | SYMBOL_MINUS, 48 | SYMBOL_NOT_EQUAL, // This is the <> double-char symbol 49 | SYMBOL_PLUS, 50 | SYMBOL_QUESTION_MARK, 51 | SYMBOL_RPAREN, 52 | SYMBOL_SEMICOLON, 53 | SYMBOL_SOLIDUS, 54 | SYMBOL_VERTICAL_BAR, 55 | 56 | // Reserved keywords 57 | SYMBOL_ACTION, 58 | SYMBOL_ADD, 59 | SYMBOL_ALL, 60 | SYMBOL_ALTER, 61 | SYMBOL_AND, 62 | SYMBOL_ANY, 63 | SYMBOL_AS, 64 | SYMBOL_AT, 65 | SYMBOL_AUTHORIZATION, 66 | SYMBOL_AVG, 67 | SYMBOL_BETWEEN, 68 | SYMBOL_BIT, 69 | SYMBOL_BIT_LENGTH, 70 | SYMBOL_BOTH, 71 | SYMBOL_BY, 72 | SYMBOL_CASCADE, 73 | SYMBOL_CASCADED, 74 | SYMBOL_CASE, 75 | SYMBOL_CHAR, 76 | SYMBOL_CHARACTER, 77 | SYMBOL_CHAR_LENGTH, 78 | SYMBOL_CHARACTER_LENGTH, 79 | SYMBOL_CHECK, 80 | SYMBOL_COALESCE, 81 | SYMBOL_COLLATE, 82 | SYMBOL_COLLATION, 83 | SYMBOL_COLUMN, 84 | SYMBOL_COMMIT, 85 | SYMBOL_CONSTRAINT, 86 | SYMBOL_CONVERT, 87 | SYMBOL_COUNT, 88 | SYMBOL_CREATE, 89 | SYMBOL_CROSS, 90 | SYMBOL_CURRENT_DATE, 91 | SYMBOL_CURRENT_TIME, 92 | SYMBOL_CURRENT_TIMESTAMP, 93 | SYMBOL_CURRENT_USER, 94 | SYMBOL_DATE, 95 | SYMBOL_DAY, 96 | SYMBOL_DEC, 97 | SYMBOL_DECIMAL, 98 | SYMBOL_DEFAULT, 99 | SYMBOL_DELETE, 100 | SYMBOL_DISTINCT, 101 | SYMBOL_DOMAIN, 102 | SYMBOL_DOUBLE, 103 | SYMBOL_DROP, 104 | SYMBOL_ELSE, 105 | SYMBOL_END, 106 | SYMBOL_ESCAPE, 107 | SYMBOL_EXISTS, 108 | SYMBOL_EXTRACT, 109 | SYMBOL_FLOAT, 110 | SYMBOL_FOR, 111 | SYMBOL_FOREIGN, 112 | SYMBOL_FROM, 113 | SYMBOL_FULL, 114 | SYMBOL_GLOBAL, 115 | SYMBOL_GRANT, 116 | SYMBOL_GROUP, 117 | SYMBOL_HAVING, 118 | SYMBOL_HOUR, 119 | SYMBOL_IN, 120 | SYMBOL_INNER, 121 | SYMBOL_INSERT, 122 | SYMBOL_INT, 123 | SYMBOL_INTO, 124 | SYMBOL_INTEGER, 125 | SYMBOL_INTERVAL, 126 | SYMBOL_IS, 127 | SYMBOL_JOIN, 128 | SYMBOL_KEY, 129 | SYMBOL_LEADING, 130 | SYMBOL_LEFT, 131 | SYMBOL_LOCAL, 132 | SYMBOL_LOWER, 133 | SYMBOL_LIKE, 134 | SYMBOL_MATCH, 135 | SYMBOL_MAX, 136 | SYMBOL_MIN, 137 | SYMBOL_MINUTE, 138 | SYMBOL_MONTH, 139 | SYMBOL_NATIONAL, 140 | SYMBOL_NATURAL, 141 | SYMBOL_NCHAR, 142 | SYMBOL_NO, 143 | SYMBOL_NOT, 144 | SYMBOL_NUMERIC, 145 | SYMBOL_NULL, 146 | SYMBOL_NULLIF, 147 | SYMBOL_OCTET_LENGTH, 148 | SYMBOL_ON, 149 | SYMBOL_OPTION, 150 | SYMBOL_OR, 151 | SYMBOL_OVERLAPS, 152 | SYMBOL_OUTER, 153 | SYMBOL_PARTIAL, 154 | SYMBOL_POSITION, 155 | SYMBOL_PRECISION, 156 | SYMBOL_PRIMARY, 157 | SYMBOL_PRIVILEGES, 158 | SYMBOL_PUBLIC, 159 | SYMBOL_REAL, 160 | SYMBOL_REFERENCES, 161 | SYMBOL_RESTRICT, 162 | SYMBOL_RIGHT, 163 | SYMBOL_ROLLBACK, 164 | SYMBOL_SCHEMA, 165 | SYMBOL_SECOND, 166 | SYMBOL_SELECT, 167 | SYMBOL_SET, 168 | SYMBOL_SMALLINT, 169 | SYMBOL_SESSION_USER, 170 | SYMBOL_SOME, 171 | SYMBOL_SUBSTRING, 172 | SYMBOL_SUM, 173 | SYMBOL_SYSTEM_USER, 174 | SYMBOL_TABLE, 175 | SYMBOL_TEMPORARY, 176 | SYMBOL_THEN, 177 | SYMBOL_TIME, 178 | SYMBOL_TIMESTAMP, 179 | SYMBOL_TO, 180 | SYMBOL_TRAILING, 181 | SYMBOL_TRANSLATE, 182 | SYMBOL_TRANSLATION, 183 | SYMBOL_TRIM, 184 | SYMBOL_UNION, 185 | SYMBOL_UNIQUE, 186 | SYMBOL_UPDATE, 187 | SYMBOL_UPPER, 188 | SYMBOL_USAGE, 189 | SYMBOL_USER, 190 | SYMBOL_USING, 191 | SYMBOL_VALUE, 192 | SYMBOL_VALUES, 193 | SYMBOL_VARCHAR, 194 | SYMBOL_VARYING, 195 | SYMBOL_VIEW, 196 | SYMBOL_WHEN, 197 | SYMBOL_WHERE, 198 | SYMBOL_WITH, 199 | SYMBOL_WORK, 200 | SYMBOL_YEAR, 201 | SYMBOL_ZONE, 202 | 203 | // Non-reserved keywords 204 | 205 | // Other symbols 206 | SYMBOL_IDENTIFIER, 207 | SYMBOL_COMMENT, 208 | 209 | // Literals 210 | SYMBOL_LITERAL_APPROXIMATE_NUMBER, 211 | SYMBOL_LITERAL_BIT_STRING, 212 | SYMBOL_LITERAL_CHARACTER_STRING, 213 | SYMBOL_LITERAL_HEX_STRING, 214 | SYMBOL_LITERAL_NATIONAL_CHARACTER_STRING, 215 | SYMBOL_LITERAL_SIGNED_DECIMAL, 216 | SYMBOL_LITERAL_SIGNED_INTEGER, 217 | SYMBOL_LITERAL_UNSIGNED_DECIMAL, 218 | SYMBOL_LITERAL_UNSIGNED_INTEGER 219 | } symbol_t; 220 | 221 | std::ostream& operator<< (std::ostream& out, const symbol_t& sym); 222 | 223 | inline bool is_value_expression_terminator(const symbol_t& sym) { 224 | switch (sym) { 225 | case SYMBOL_AND: 226 | case SYMBOL_COMMA: 227 | case SYMBOL_ELSE: 228 | case SYMBOL_ESCAPE: 229 | case SYMBOL_END: 230 | case SYMBOL_EOS: 231 | case SYMBOL_EQUAL: 232 | case SYMBOL_FOR: 233 | case SYMBOL_FROM: 234 | case SYMBOL_GREATER_THAN: 235 | case SYMBOL_GROUP: 236 | case SYMBOL_HAVING: 237 | case SYMBOL_IN: 238 | case SYMBOL_LESS_THAN: 239 | case SYMBOL_LIKE: 240 | case SYMBOL_LPAREN: 241 | case SYMBOL_MATCH: 242 | case SYMBOL_NOT: 243 | case SYMBOL_NOT_EQUAL: 244 | case SYMBOL_OR: 245 | case SYMBOL_RPAREN: 246 | case SYMBOL_SEMICOLON: 247 | case SYMBOL_THEN: 248 | case SYMBOL_USING: 249 | case SYMBOL_WHEN: 250 | case SYMBOL_WHERE: 251 | return true; 252 | default: 253 | return false; 254 | } 255 | } 256 | 257 | struct symbol_map { 258 | typedef std::map symbol_map_t; 259 | static symbol_map_t m; 260 | }; 261 | 262 | symbol_map::symbol_map_t _init_symbol_map(); 263 | 264 | } // namespace sqltoast 265 | 266 | #endif /* SQLTOAST_PARSER_SYMBOL_H */ 267 | -------------------------------------------------------------------------------- /libsqltoast/src/parser/token.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/sqltoast.h" 8 | 9 | #include "parser/token.h" 10 | 11 | namespace sqltoast { 12 | 13 | std::ostream& operator<< (std::ostream& out, const token_t& token) { 14 | if (token.is_keyword()) { 15 | out << "keyword[" << token.symbol << "]"; 16 | return out; 17 | } 18 | if (token.is_literal()){ 19 | // TODO(jaypipes): Add typing of literal... 20 | size_t tok_len = token.lexeme.size(); 21 | if (tok_len < 20) { 22 | out << "literal[" << std::string(token.lexeme.start, token.lexeme.end) << "]"; 23 | } else { 24 | out << "literal[length: " << tok_len << "]"; 25 | } 26 | return out; 27 | } 28 | if (token.is_identifier()){ 29 | size_t tok_len = token.lexeme.size(); 30 | if (tok_len < 20) { 31 | out << "identifier[" << std::string(token.lexeme.start, token.lexeme.end) << "]"; 32 | } else { 33 | out << "identifier[length: " << tok_len << "]"; 34 | } 35 | return out; 36 | } 37 | if (token.symbol == SYMBOL_COMMENT) { 38 | out << "comment[length: " << token.lexeme.size() << "]"; 39 | return out; 40 | } else { 41 | out << "symbol[" << token.symbol << "]"; 42 | return out; 43 | } 44 | return out; 45 | } 46 | 47 | } // namespace sqltoast 48 | -------------------------------------------------------------------------------- /libsqltoast/src/parser/token.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOAST_PARSER_TOKEN_H 8 | #define SQLTOAST_PARSER_TOKEN_H 9 | 10 | #include 11 | 12 | #include "symbol.h" 13 | 14 | namespace sqltoast { 15 | 16 | typedef struct token { 17 | symbol_t symbol; 18 | lexeme_t lexeme; 19 | token() : 20 | symbol(SYMBOL_NONE), 21 | lexeme() 22 | {} 23 | token( 24 | symbol_t symbol, 25 | parse_position_t start, 26 | parse_position_t end) : 27 | symbol(symbol), lexeme(start, end) 28 | {} 29 | inline bool is_literal() const { 30 | return (symbol >= SYMBOL_LITERAL_APPROXIMATE_NUMBER && symbol <= SYMBOL_LITERAL_UNSIGNED_INTEGER); 31 | } 32 | inline bool is_punctuator() const { 33 | return (symbol >= SYMBOL_ASTERISK && symbol <= SYMBOL_VERTICAL_BAR); 34 | } 35 | inline bool is_keyword() const { 36 | return (symbol >= SYMBOL_ALL && symbol <= SYMBOL_VARYING); 37 | } 38 | inline bool is_identifier() const { 39 | return (symbol == SYMBOL_IDENTIFIER); 40 | } 41 | } token_t; 42 | 43 | std::ostream& operator<< (std::ostream& out, const token_t& token); 44 | 45 | } // namespace sqltoast 46 | 47 | #endif /* SQLTOAST_PARSER_TOKEN_H */ 48 | -------------------------------------------------------------------------------- /libsqltoast/src/print/column_definition.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const default_descriptor_t& default_desc) { 12 | out << "DEFAULT "; 13 | switch (default_desc.type) { 14 | case DEFAULT_TYPE_NULL: 15 | out << "NULL"; 16 | break; 17 | case DEFAULT_TYPE_CURRENT_USER: 18 | out << "CURRENT_USER"; 19 | break; 20 | case DEFAULT_TYPE_SESSION_USER: 21 | out << "SESSION_USER"; 22 | break; 23 | case DEFAULT_TYPE_SYSTEM_USER: 24 | out << "SYSTEM_USER"; 25 | break; 26 | case DEFAULT_TYPE_USER: 27 | out << "USER"; 28 | break; 29 | case DEFAULT_TYPE_CURRENT_DATE: 30 | out << "CURRENT_DATE"; 31 | break; 32 | case DEFAULT_TYPE_CURRENT_TIME: 33 | out << "CURRENT_TIME"; 34 | if (default_desc.precision > 0) 35 | out << "(" << default_desc.precision << ")"; 36 | break; 37 | case DEFAULT_TYPE_CURRENT_TIMESTAMP: 38 | out << "CURRENT_TIMESTAMP"; 39 | if (default_desc.precision > 0) 40 | out << "(" << default_desc.precision << ")"; 41 | break; 42 | case DEFAULT_TYPE_LITERAL: 43 | out << default_desc.lexeme; 44 | break; 45 | default: 46 | break; 47 | } 48 | return out; 49 | } 50 | 51 | std::ostream& operator<< (std::ostream& out, const column_definition_t& column_def) { 52 | out << column_def.name << " "; 53 | if (column_def.data_type.get()) { 54 | out << *column_def.data_type; 55 | } else { 56 | out << " UNKNOWN"; 57 | } 58 | if (column_def.default_descriptor.get()) { 59 | out << " " << *column_def.default_descriptor; 60 | } 61 | for (const std::unique_ptr& c: column_def.constraints) 62 | out << *c; 63 | if (column_def.collate) { 64 | out << " COLLATE " << column_def.collate; 65 | } 66 | return out; 67 | } 68 | 69 | } // namespace sqltoast 70 | -------------------------------------------------------------------------------- /libsqltoast/src/print/column_reference.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const derived_column_t& dc) { 12 | if (dc.value) 13 | out << *dc.value; 14 | else 15 | out << "*"; 16 | if (dc.has_alias()) 17 | out << " AS " << dc.alias; 18 | return out; 19 | } 20 | 21 | std::ostream& operator<< (std::ostream& out, const grouping_column_reference_t& gcr) { 22 | out << gcr.column; 23 | if (gcr.has_collation()) 24 | out << " COLLATE " << gcr.collation; 25 | return out; 26 | } 27 | 28 | } // namespace sqltoast 29 | -------------------------------------------------------------------------------- /libsqltoast/src/print/constraint.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const constraint_t& constraint) { 12 | if (constraint.name) 13 | out << " CONSTRAINT " << constraint.name; 14 | switch (constraint.type) { 15 | case CONSTRAINT_TYPE_NOT_NULL: 16 | { 17 | const not_null_constraint_t& nnc = 18 | static_cast(constraint); 19 | out << nnc; 20 | } 21 | break; 22 | case CONSTRAINT_TYPE_UNIQUE: 23 | case CONSTRAINT_TYPE_PRIMARY_KEY: 24 | { 25 | const unique_constraint_t& uniq_c = 26 | static_cast(constraint); 27 | out << uniq_c; 28 | } 29 | break; 30 | case CONSTRAINT_TYPE_FOREIGN_KEY: 31 | { 32 | const foreign_key_constraint_t& ref_c = 33 | static_cast(constraint); 34 | out << ref_c; 35 | } 36 | break; 37 | case CONSTRAINT_TYPE_CHECK: 38 | out << "CHECK "; 39 | // TODO 40 | break; 41 | default: 42 | break; 43 | } 44 | return out; 45 | } 46 | 47 | std::ostream& operator<< (std::ostream& out, const not_null_constraint_t& nnc) { 48 | out << " NOT NULL"; 49 | return out; 50 | } 51 | 52 | std::ostream& operator<< (std::ostream& out, const unique_constraint_t& constraint) { 53 | switch (constraint.type) { 54 | case CONSTRAINT_TYPE_UNIQUE: 55 | out << " UNIQUE"; 56 | break; 57 | case CONSTRAINT_TYPE_PRIMARY_KEY: 58 | out << " PRIMARY KEY"; 59 | break; 60 | default: 61 | // Should never happen... 62 | break; 63 | } 64 | size_t x = 0; 65 | size_t num_columns = constraint.columns.size(); 66 | if (num_columns > 0) { 67 | out << " ("; 68 | for (auto col : constraint.columns) { 69 | out << col; 70 | if (x++ < (num_columns - 1)) { 71 | out << ","; 72 | } 73 | } 74 | out << ")"; 75 | } 76 | return out; 77 | } 78 | 79 | std::ostream& operator<< (std::ostream& out, const foreign_key_constraint_t& constraint) { 80 | size_t num_columns = constraint.columns.size(); 81 | size_t x = 0; 82 | out << " FOREIGN KEY ("; 83 | for (const lexeme_t& col_name : constraint.columns) { 84 | out << col_name; 85 | if (x++ != (num_columns - 1)) 86 | out << ","; 87 | } 88 | size_t num_referenced_columns = constraint.referenced_columns.size(); 89 | out << ") REFERENCES " << constraint.referenced_table; 90 | if (num_referenced_columns > 0) { 91 | out << " ("; 92 | x = 0; 93 | for (const lexeme_t& col_name : constraint.referenced_columns) { 94 | out << col_name; 95 | if (x++ != (num_referenced_columns - 1)) 96 | out << ","; 97 | } 98 | out << ")"; 99 | } 100 | switch (constraint.match_type) { 101 | case MATCH_TYPE_FULL: 102 | out << " MATCH FULL"; 103 | break; 104 | case MATCH_TYPE_PARTIAL: 105 | out << " MATCH PARTIAL"; 106 | break; 107 | default: 108 | break; 109 | } 110 | switch (constraint.on_update) { 111 | case REFERENTIAL_ACTION_SET_NULL: 112 | out << " ON UPDATE SET NULL"; 113 | break; 114 | case REFERENTIAL_ACTION_SET_DEFAULT: 115 | out << " ON UPDATE SET DEFAULT"; 116 | break; 117 | case REFERENTIAL_ACTION_CASCADE: 118 | out << " ON UPDATE CASCADE"; 119 | break; 120 | default: 121 | break; 122 | } 123 | switch (constraint.on_delete) { 124 | case REFERENTIAL_ACTION_SET_NULL: 125 | out << " ON DELETE SET NULL"; 126 | break; 127 | case REFERENTIAL_ACTION_SET_DEFAULT: 128 | out << " ON DELETE SET DEFAULT"; 129 | break; 130 | case REFERENTIAL_ACTION_CASCADE: 131 | out << " ON DELETE CASCADE"; 132 | break; 133 | default: 134 | break; 135 | } 136 | return out; 137 | } 138 | 139 | } // namespace sqltoast 140 | -------------------------------------------------------------------------------- /libsqltoast/src/print/data_type.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const data_type_descriptor_t& dt) { 12 | switch (dt.type) { 13 | case DATA_TYPE_CHAR: 14 | case DATA_TYPE_VARCHAR: 15 | case DATA_TYPE_NCHAR: 16 | case DATA_TYPE_NVARCHAR: 17 | { 18 | const char_string_t& sub = static_cast(dt); 19 | out << sub; 20 | } 21 | break; 22 | case DATA_TYPE_BIT: 23 | case DATA_TYPE_VARBIT: 24 | { 25 | const bit_string_t& sub = static_cast(dt); 26 | out << sub; 27 | } 28 | break; 29 | case DATA_TYPE_INT: 30 | case DATA_TYPE_SMALLINT: 31 | case DATA_TYPE_NUMERIC: 32 | { 33 | const exact_numeric_t& sub = static_cast(dt); 34 | out << sub; 35 | } 36 | break; 37 | case DATA_TYPE_DOUBLE: 38 | case DATA_TYPE_FLOAT: 39 | { 40 | const approximate_numeric_t& sub = static_cast(dt); 41 | out << sub; 42 | } 43 | break; 44 | case DATA_TYPE_DATE: 45 | case DATA_TYPE_TIME: 46 | case DATA_TYPE_TIMESTAMP: 47 | { 48 | const datetime_t& sub = static_cast(dt); 49 | out << sub; 50 | } 51 | break; 52 | case DATA_TYPE_INTERVAL: 53 | { 54 | const interval_t& sub = static_cast(dt); 55 | out << sub; 56 | } 57 | break; 58 | default: 59 | return out; 60 | } 61 | return out; 62 | } 63 | 64 | std::ostream& operator<< (std::ostream& out, const char_string_t& cs) { 65 | switch (cs.type) { 66 | case DATA_TYPE_CHAR: 67 | out << "CHAR"; 68 | break; 69 | case DATA_TYPE_NCHAR: 70 | out << "NCHAR"; 71 | break; 72 | case DATA_TYPE_VARCHAR: 73 | out << "VARCHAR"; 74 | break; 75 | case DATA_TYPE_NVARCHAR: 76 | out << "NVARCHAR"; 77 | break; 78 | default: 79 | return out; 80 | } 81 | if (cs.size > 0) 82 | out << "(" << cs.size << ")"; 83 | if (cs.charset) 84 | out << " CHARACTER SET " << cs.charset; 85 | return out; 86 | } 87 | 88 | std::ostream& operator<< (std::ostream& out, const bit_string_t& bs) { 89 | out << "BIT"; 90 | if (bs.type == DATA_TYPE_VARBIT) 91 | out << " VARYING"; 92 | if (bs.size > 0) 93 | out << "(" << bs.size << ")"; 94 | return out; 95 | } 96 | 97 | std::ostream& operator<< (std::ostream& out, const exact_numeric_t& num) { 98 | switch (num.type) { 99 | case DATA_TYPE_INT: 100 | out << "INT"; 101 | break; 102 | case DATA_TYPE_SMALLINT: 103 | out << "SMALLINT"; 104 | break; 105 | case DATA_TYPE_NUMERIC: 106 | out << "NUMERIC"; 107 | break; 108 | default: 109 | return out; 110 | } 111 | if (num.precision > 0) { 112 | out << "(" << num.precision; 113 | if (num.scale > 0) { 114 | out << "," << num.scale; 115 | } 116 | out << ")"; 117 | } 118 | return out; 119 | } 120 | 121 | std::ostream& operator<< (std::ostream& out, const approximate_numeric_t& num) { 122 | switch (num.type) { 123 | case DATA_TYPE_FLOAT: 124 | out << "FLOAT"; 125 | break; 126 | case DATA_TYPE_DOUBLE: 127 | out << "DOUBLE PRECISION"; 128 | break; 129 | default: 130 | return out; 131 | } 132 | if (num.precision > 0) 133 | out << "(" << num.precision << ")"; 134 | return out; 135 | } 136 | 137 | std::ostream& operator<< (std::ostream& out, const datetime_t& dt) { 138 | switch (dt.type) { 139 | case DATA_TYPE_DATE: 140 | out << "DATE"; 141 | break; 142 | case DATA_TYPE_TIME: 143 | out << "TIME"; 144 | break; 145 | case DATA_TYPE_TIMESTAMP: 146 | out << "TIMESTAMP"; 147 | break; 148 | default: 149 | return out; 150 | } 151 | if (dt.precision > 0) 152 | out << "(" << dt.precision << ")"; 153 | if (dt.with_tz) 154 | out << " WITH TIME ZONE"; 155 | return out; 156 | } 157 | 158 | std::ostream& operator<< (std::ostream& out, const interval_t& interval) { 159 | out << "INTERVAL (" << interval.unit; 160 | if (interval.unit == INTERVAL_UNIT_SECOND && interval.precision > 0) 161 | out << "(" << interval.precision << ")"; 162 | out << ")"; 163 | return out; 164 | } 165 | 166 | std::ostream& operator<< (std::ostream& out, const interval_unit_t& unit) { 167 | switch (unit) { 168 | case INTERVAL_UNIT_YEAR: 169 | out << "YEAR"; 170 | break; 171 | case INTERVAL_UNIT_MONTH: 172 | out << "MONTH"; 173 | break; 174 | case INTERVAL_UNIT_DAY: 175 | out << "DAY"; 176 | break; 177 | case INTERVAL_UNIT_HOUR: 178 | out << "HOUR"; 179 | break; 180 | case INTERVAL_UNIT_MINUTE: 181 | out << "MINUTE"; 182 | break; 183 | case INTERVAL_UNIT_SECOND: 184 | out << "SECOND"; 185 | break; 186 | } 187 | return out; 188 | } 189 | 190 | } // namespace sqltoast 191 | -------------------------------------------------------------------------------- /libsqltoast/src/print/identifier.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const identifier_t& id) { 12 | out << id.name; 13 | return out; 14 | } 15 | 16 | } // namespace sqltoast 17 | -------------------------------------------------------------------------------- /libsqltoast/src/print/query.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const query_specification_t& query) { 12 | out << "query["; 13 | if (query.distinct) 14 | out << "distinct: true "; 15 | out << "selected-columns["; 16 | size_t x = 0; 17 | for (const derived_column_t& dc : query.selected_columns) { 18 | if (x++ > 0) 19 | out << ','; 20 | out << dc; 21 | } 22 | out << "] "; 23 | out << *query.table_expression << "]"; 24 | 25 | return out; 26 | } 27 | 28 | std::ostream& operator<< (std::ostream& out, const table_expression_t& table_exp) { 29 | out << "table-expression["; 30 | out << "referenced-tables["; 31 | size_t x = 0; 32 | for (const std::unique_ptr& tr : table_exp.referenced_tables) { 33 | if (x++ > 0) 34 | out << ','; 35 | out << *tr; 36 | } 37 | if (table_exp.where_condition) 38 | out << " where[" << *table_exp.where_condition << ']'; 39 | if (! table_exp.group_by_columns.empty()) { 40 | out << " group-by["; 41 | x = 0; 42 | for (const grouping_column_reference_t& gcr : table_exp.group_by_columns) { 43 | if (x++ > 0) 44 | out << ','; 45 | out << gcr; 46 | } 47 | out << ']'; 48 | } 49 | if (table_exp.having_condition) 50 | out << " having[" << *table_exp.having_condition << ']'; 51 | out << "]"; 52 | 53 | return out; 54 | } 55 | 56 | std::ostream& operator<< (std::ostream& out, const query_expression_t& qe) { 57 | switch (qe.query_expression_type) { 58 | case QUERY_EXPRESSION_TYPE_NON_JOIN_QUERY_EXPRESSION: 59 | { 60 | const non_join_query_expression_t& sub = 61 | static_cast(qe); 62 | out << sub; 63 | } 64 | break; 65 | case QUERY_EXPRESSION_TYPE_JOINED_TABLE: 66 | { 67 | const joined_table_query_expression_t& sub = 68 | static_cast(qe); 69 | out << sub; 70 | } 71 | break; 72 | } 73 | return out; 74 | } 75 | 76 | std::ostream& operator<< (std::ostream& out, const non_join_query_expression_t& qe) { 77 | out << *qe.term; 78 | return out; 79 | } 80 | 81 | std::ostream& operator<< (std::ostream& out, const non_join_query_term_t& term) { 82 | out << *term.primary; 83 | return out; 84 | } 85 | 86 | std::ostream& operator<< (std::ostream& out, const non_join_query_primary_t& primary) { 87 | switch (primary.primary_type) { 88 | case NON_JOIN_QUERY_PRIMARY_TYPE_QUERY_SPECIFICATION: 89 | { 90 | const query_specification_non_join_query_primary_t& sub = 91 | static_cast(primary); 92 | out << sub; 93 | } 94 | break; 95 | case NON_JOIN_QUERY_PRIMARY_TYPE_TABLE_VALUE_CONSTRUCTOR: 96 | { 97 | const table_value_constructor_non_join_query_primary_t& sub = 98 | static_cast(primary); 99 | out << sub; 100 | } 101 | break; 102 | case NON_JOIN_QUERY_PRIMARY_TYPE_EXPLICIT_TABLE: 103 | case NON_JOIN_QUERY_PRIMARY_TYPE_SUBEXPRESSION: 104 | // TODO 105 | break; 106 | } 107 | return out; 108 | } 109 | 110 | std::ostream& operator<< (std::ostream& out, const query_specification_non_join_query_primary_t& primary) { 111 | out << *primary.query_spec; 112 | return out; 113 | } 114 | 115 | std::ostream& operator<< (std::ostream& out, const table_value_constructor_non_join_query_primary_t& primary) { 116 | out << "values[" << *primary.table_value << ']'; 117 | return out; 118 | } 119 | 120 | std::ostream& operator<< (std::ostream& out, const table_value_constructor_t& table_value) { 121 | size_t x = 0; 122 | for (const std::unique_ptr& value : table_value.values) { 123 | if (x++ > 0) 124 | out << ','; 125 | out << *value; 126 | } 127 | return out; 128 | } 129 | 130 | std::ostream& operator<< (std::ostream& out, const joined_table_query_expression_t& qe) { 131 | out << *qe.joined_table; 132 | return out; 133 | } 134 | 135 | } // namespace sqltoast 136 | -------------------------------------------------------------------------------- /libsqltoast/src/print/table_reference.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const table_reference_t& tr) { 12 | switch (tr.type) { 13 | case TABLE_REFERENCE_TYPE_TABLE: 14 | { 15 | const table_t& t = static_cast(tr); 16 | out << t; 17 | } 18 | break; 19 | case TABLE_REFERENCE_TYPE_DERIVED_TABLE: 20 | { 21 | const derived_table_t& dt = 22 | static_cast(tr); 23 | out << dt; 24 | } 25 | break; 26 | } 27 | if (tr.joined) 28 | out << *tr.joined; 29 | return out; 30 | } 31 | 32 | std::ostream& operator<< (std::ostream& out, const table_t& t) { 33 | out << std::string(t.table_name.start, t.table_name.end); 34 | if (t.has_alias()) 35 | out << " AS " << t.correlation_spec->alias; 36 | return out; 37 | } 38 | 39 | std::ostream& operator<< (std::ostream& out, const derived_table_t& dt) { 40 | out << " AS " << dt.correlation_spec.alias; 41 | return out; 42 | } 43 | 44 | std::ostream& operator<< (std::ostream& out, const join_target_t& jt) { 45 | switch (jt.join_type) { 46 | case JOIN_TYPE_INNER: 47 | out << "inner-join["; 48 | break; 49 | case JOIN_TYPE_LEFT: 50 | out << "left-join["; 51 | break; 52 | case JOIN_TYPE_RIGHT: 53 | out << "right-join["; 54 | break; 55 | case JOIN_TYPE_FULL: 56 | out << "full-join["; 57 | break; 58 | case JOIN_TYPE_CROSS: 59 | out << "cross-join["; 60 | break; 61 | case JOIN_TYPE_NATURAL: 62 | out << "natural-join["; 63 | break; 64 | case JOIN_TYPE_UNION: 65 | out << "union-join["; 66 | break; 67 | default: 68 | break; 69 | } 70 | out << *jt.table_ref; 71 | if (jt.join_spec) 72 | out << *jt.join_spec; 73 | out << ']'; 74 | return out; 75 | } 76 | 77 | std::ostream& operator<< (std::ostream& out, const join_specification_t& js) { 78 | if (js.condition) 79 | out << ',' << *js.condition; 80 | else if (! js.named_columns.empty()) { 81 | out << ",using["; 82 | size_t x = 0; 83 | for (const lexeme_t& col : js.named_columns) { 84 | if (x++ > 0) 85 | out << ','; 86 | out << col; 87 | } 88 | out << ']'; 89 | } 90 | return out; 91 | } 92 | 93 | } // namespace sqltoast 94 | -------------------------------------------------------------------------------- /libsqltoast/src/print/value_expression.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include "sqltoast/print.h" 8 | 9 | namespace sqltoast { 10 | 11 | std::ostream& operator<< (std::ostream& out, const row_value_constructor_t& rvc) { 12 | switch (rvc.rvc_type) { 13 | case RVC_TYPE_ELEMENT: 14 | { 15 | const row_value_constructor_element_t& el = 16 | static_cast(rvc); 17 | out << el; 18 | } 19 | break; 20 | case RVC_TYPE_LIST: 21 | { 22 | const row_value_constructor_list_t& els = 23 | static_cast(rvc); 24 | out << '('; 25 | size_t x = 0; 26 | for (const auto& el : els.elements) { 27 | if (x++ > 0) 28 | out << ','; 29 | out << *el; 30 | } 31 | out << ')'; 32 | } 33 | break; 34 | default: 35 | out << "row-value-constructor[UNKNOWN]"; 36 | break; 37 | } 38 | return out; 39 | } 40 | 41 | std::ostream& operator<< (std::ostream& out, const row_value_constructor_element_t& rvce) { 42 | switch (rvce.rvc_element_type) { 43 | case RVC_ELEMENT_TYPE_DEFAULT: 44 | out << "DEFAULT"; 45 | break; 46 | case RVC_ELEMENT_TYPE_NULL: 47 | out << "NULL"; 48 | break; 49 | case RVC_ELEMENT_TYPE_VALUE_EXPRESSION: 50 | { 51 | const row_value_expression_t& val = static_cast(rvce); 52 | out << val; 53 | } 54 | break; 55 | } 56 | return out; 57 | } 58 | 59 | std::ostream& operator<< (std::ostream& out, const row_value_expression_t& rve) { 60 | out << *rve.value; 61 | return out; 62 | } 63 | 64 | std::ostream& operator<< (std::ostream& out, const value_expression_t& ve) { 65 | switch (ve.type) { 66 | case VALUE_EXPRESSION_TYPE_NUMERIC_EXPRESSION: 67 | { 68 | const numeric_expression_t& ne = 69 | static_cast(ve); 70 | out << ne; 71 | } 72 | break; 73 | case VALUE_EXPRESSION_TYPE_STRING_EXPRESSION: 74 | { 75 | const character_value_expression_t& cve = 76 | static_cast(ve); 77 | out << cve; 78 | } 79 | break; 80 | case VALUE_EXPRESSION_TYPE_DATETIME_EXPRESSION: 81 | { 82 | const datetime_value_expression_t& dtve = 83 | static_cast(ve); 84 | out << dtve; 85 | } 86 | break; 87 | case VALUE_EXPRESSION_TYPE_INTERVAL_EXPRESSION: 88 | { 89 | const interval_value_expression_t& ive = 90 | static_cast(ve); 91 | out << ive; 92 | } 93 | break; 94 | default: 95 | out << "unknown-value-expression"; 96 | break; 97 | } 98 | return out; 99 | } 100 | 101 | std::ostream& operator<< (std::ostream& out, const numeric_expression_t& ne) { 102 | // numeric expressions are the container for things that may be evaluated 103 | // to a number. However, numeric expressions that have only a single 104 | // element can be reduced to just that one element 105 | if (! ne.right) { 106 | if (! ne.left->right) 107 | out << *ne.left; 108 | else 109 | out << "numeric-expression[" << *ne.left << "]"; 110 | } else { 111 | out << "numeric-expression["; 112 | out << *ne.left; 113 | if (ne.op == NUMERIC_OP_ADD) 114 | out << " + "; 115 | else 116 | out << " - "; 117 | out << *ne.right << "]"; 118 | } 119 | return out; 120 | } 121 | 122 | std::ostream& operator<< (std::ostream& out, const character_value_expression_t& cve) { 123 | if (cve.values.size() > 1) { 124 | out << "concatenate["; 125 | size_t x = 0; 126 | for (const std::unique_ptr& val : cve.values) { 127 | if (x++ > 0) 128 | out << ", "; 129 | out << *val; 130 | } 131 | out << "]"; 132 | } else 133 | out << *cve.values[0]; 134 | return out; 135 | } 136 | 137 | std::ostream& operator<< (std::ostream& out, const datetime_value_expression_t& de) { 138 | // datetime expressions are the container for things that may be evaluated 139 | // to a number. However, datetime expressions that have only a single 140 | // element can be reduced to just that one element 141 | if (! de.right) 142 | out << "datetime-expression[" << *de.left << "]"; 143 | else { 144 | out << "datetime-expression["; 145 | out << *de.left; 146 | if (de.op == NUMERIC_OP_ADD) 147 | out << " + "; 148 | else 149 | out << " - "; 150 | out << *de.right << "]"; 151 | } 152 | return out; 153 | } 154 | 155 | std::ostream& operator<< (std::ostream& out, const interval_value_expression_t& ie) { 156 | // interval expressions are the container for things that may be evaluated 157 | // to a number. However, interval expressions that have only a single 158 | // element can be reduced to just that one element 159 | if (! ie.right) 160 | out << "interval-expression[" << *ie.left << "]"; 161 | else { 162 | out << "interval-expression["; 163 | out << *ie.left; 164 | if (ie.op == NUMERIC_OP_ADD) 165 | out << " + "; 166 | else 167 | out << " - "; 168 | out << *ie.right << "]"; 169 | } 170 | return out; 171 | } 172 | 173 | } // namespace sqltoast 174 | -------------------------------------------------------------------------------- /sqltoaster/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(sqltoaster) 2 | 3 | SET(PROJECT_VERSION 0.1) 4 | SET(PROJECT_DESCRIPTION "A demonstration of the sqltoast library") 5 | 6 | SET(SQLTOASTER_SOURCES 7 | main.cc 8 | node.cc 9 | printer.cc 10 | node/statement.cc 11 | ) 12 | 13 | ADD_EXECUTABLE(sqltoaster ${SQLTOASTER_SOURCES}) 14 | SET_TARGET_PROPERTIES(sqltoaster PROPERTIES 15 | CXX_STANDARD 14 16 | CXX_STANDARD_REQUIRED YES 17 | CXX_EXTENSIONS NO 18 | ) 19 | SET(SQLTOASTER_BUILD_OPTS, "-Wall --no-rtti") 20 | TARGET_COMPILE_OPTIONS(sqltoaster 21 | PUBLIC ${SQLTOASTER_BUILD_OPTS} 22 | ) 23 | TARGET_LINK_LIBRARIES(sqltoaster sqltoast) 24 | -------------------------------------------------------------------------------- /sqltoaster/fill.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOASTER_FILL_H 8 | #define SQLTOASTER_FILL_H 9 | 10 | #include 11 | 12 | #include "printer.h" 13 | #include "node.h" 14 | 15 | namespace sqltoaster { 16 | 17 | void fill(mapping_t& node, const sqltoast::alter_table_statement_t& stmt); 18 | void fill(mapping_t& node, const sqltoast::between_predicate_t& pred); 19 | void fill(mapping_t& node, const sqltoast::boolean_factor_t& bf); 20 | void fill(mapping_t& node, const sqltoast::boolean_primary_t& bp); 21 | void fill(mapping_t& node, const sqltoast::boolean_term_t& bt); 22 | void fill(mapping_t& node, const sqltoast::case_expression_t& expr); 23 | void fill(mapping_t& node, const sqltoast::character_factor_t& factor); 24 | void fill(mapping_t& node, const sqltoast::character_primary_t& cp); 25 | void fill(mapping_t& node, const sqltoast::character_value_expression_t& cve); 26 | void fill(mapping_t& node, const sqltoast::coalesce_function_t& func); 27 | void fill(mapping_t& node, const sqltoast::comp_op_t& op); 28 | void fill(mapping_t& node, const sqltoast::comp_predicate_t& pred); 29 | void fill(mapping_t& node, const sqltoast::convert_function_t& func); 30 | void fill(mapping_t& node, const sqltoast::create_schema_statement_t& stmt); 31 | void fill(mapping_t& node, const sqltoast::create_table_statement_t& stmt); 32 | void fill(mapping_t& node, const sqltoast::create_view_statement_t& stmt); 33 | void fill(mapping_t& node, const sqltoast::datetime_factor_t& factor); 34 | void fill(mapping_t& node, const sqltoast::datetime_field_t& field); 35 | void fill(mapping_t& node, const sqltoast::datetime_primary_t& primary); 36 | void fill(mapping_t& node, const sqltoast::datetime_term_t& term); 37 | void fill(mapping_t& node, const sqltoast::datetime_value_t& value); 38 | void fill(mapping_t& node, const sqltoast::datetime_value_expression_t& de); 39 | void fill(mapping_t& node, const sqltoast::delete_statement_t& stmt); 40 | void fill(mapping_t& node, const sqltoast::derived_column_t& dc); 41 | void fill(mapping_t& node, const sqltoast::derived_table_t& t); 42 | void fill(mapping_t& node, const sqltoast::drop_column_action_t& action); 43 | void fill(mapping_t& node, const sqltoast::drop_column_action_t& action); 44 | void fill(mapping_t& node, const sqltoast::drop_schema_statement_t& stmt); 45 | void fill(mapping_t& node, const sqltoast::drop_table_statement_t& stmt); 46 | void fill(mapping_t& node, const sqltoast::drop_view_statement_t& stmt); 47 | void fill(mapping_t& node, const sqltoast::exists_predicate_t& pred); 48 | void fill(mapping_t& node, const sqltoast::extract_expression_t& expr); 49 | void fill(mapping_t& node, const sqltoast::grant_statement_t& stmt); 50 | void fill(mapping_t& node, const sqltoast::in_subquery_predicate_t& pred); 51 | void fill(mapping_t& node, const sqltoast::in_values_predicate_t& pred); 52 | void fill(mapping_t& node, const sqltoast::insert_statement_t& stmt); 53 | void fill(mapping_t& node, const sqltoast::interval_factor_t& factor); 54 | void fill(mapping_t& node, const sqltoast::interval_primary_t& primary); 55 | void fill(mapping_t& node, const sqltoast::interval_qualifier_t& qualifier); 56 | void fill(mapping_t& node, const sqltoast::interval_term_t& term); 57 | void fill(mapping_t& node, const sqltoast::interval_value_expression_t& ie); 58 | void fill(mapping_t& node, const sqltoast::join_specification_t& spec); 59 | void fill(mapping_t& node, const sqltoast::joined_table_query_expression_t& qe); 60 | void fill(mapping_t& node, const sqltoast::join_target_t& jt); 61 | void fill(mapping_t& node, const sqltoast::length_expression_t& expr); 62 | void fill(mapping_t& node, const sqltoast::like_predicate_t& pred); 63 | void fill(mapping_t& node, const sqltoast::match_predicate_t& pred); 64 | void fill(mapping_t& node, const sqltoast::non_join_query_expression_t& qe); 65 | void fill(mapping_t& node, const sqltoast::non_join_query_primary_t& primary); 66 | void fill(mapping_t& node, const sqltoast::non_join_query_term_t& term); 67 | void fill(mapping_t& node, const sqltoast::nullif_function_t& func); 68 | void fill(mapping_t& node, const sqltoast::null_predicate_t& pred); 69 | void fill(mapping_t& node, const sqltoast::numeric_expression_t& expr); 70 | void fill(mapping_t& node, const sqltoast::numeric_factor_t& factor); 71 | void fill(mapping_t& node, const sqltoast::numeric_function_t& func); 72 | void fill(mapping_t& node, const sqltoast::numeric_primary_t& primary); 73 | void fill(mapping_t& node, const sqltoast::numeric_term_t& term); 74 | void fill(mapping_t& node, const sqltoast::numeric_value_t& value); 75 | void fill(mapping_t& node, const sqltoast::overlaps_predicate_t& pred); 76 | void fill(mapping_t& node, const sqltoast::parenthesized_value_expression_t& expr); 77 | void fill(mapping_t& node, const sqltoast::position_expression_t& expr); 78 | void fill(mapping_t& node, const sqltoast::predicate_t& pred); 79 | void fill(mapping_t& node, const sqltoast::quantified_comparison_predicate_t& pred); 80 | void fill(mapping_t& node, const sqltoast::query_expression_t& qe); 81 | void fill(mapping_t& node, const sqltoast::query_specification_non_join_query_primary_t& primary); 82 | void fill(mapping_t& node, const sqltoast::query_specification_t& query); 83 | void fill(mapping_t& node, const sqltoast::row_value_constructor_element_t& rvce); 84 | void fill(mapping_t& node, const sqltoast::row_value_constructor_t& rvc); 85 | void fill(mapping_t& node, const sqltoast::row_value_expression_t& rve); 86 | void fill(mapping_t& node, const sqltoast::scalar_subquery_t& subq); 87 | void fill(mapping_t& node, const sqltoast::search_condition_t& sc); 88 | void fill(mapping_t& node, const sqltoast::searched_case_expression_t& expr); 89 | void fill(mapping_t& node, const sqltoast::select_statement_t& stmt); 90 | void fill(mapping_t& node, const sqltoast::set_function_t& func); 91 | void fill(mapping_t& node, const sqltoast::simple_case_expression_t& expr); 92 | void fill(mapping_t& node, const sqltoast::statement_t& stmt); 93 | void fill(mapping_t& node, const sqltoast::string_function_t& func); 94 | void fill(mapping_t& node, const sqltoast::substring_function_t& func); 95 | void fill(mapping_t& node, const sqltoast::table_t& t); 96 | void fill(mapping_t& node, const sqltoast::table_expression_t& table_exp); 97 | void fill(mapping_t& node, const sqltoast::table_reference_t& tr); 98 | void fill(mapping_t& node, const sqltoast::table_value_constructor_t& table_value); 99 | void fill(mapping_t& node, const sqltoast::table_value_constructor_non_join_query_primary_t& primary); 100 | void fill(mapping_t& node, const sqltoast::translate_function_t& func); 101 | void fill(mapping_t& node, const sqltoast::trim_function_t& func); 102 | void fill(mapping_t& node, const sqltoast::unique_predicate_t& pred); 103 | void fill(mapping_t& node, const sqltoast::update_statement_t& stmt); 104 | void fill(mapping_t& node, const sqltoast::value_expression_t& ve); 105 | void fill(mapping_t& node, const sqltoast::value_expression_primary_t& primary); 106 | 107 | } // namespace sqltoaster 108 | 109 | #endif /* SQLTOASTER_FILL_H */ 110 | -------------------------------------------------------------------------------- /sqltoaster/main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "measure.h" 14 | #include "printer.h" 15 | 16 | struct parser { 17 | sqltoast::parse_options_t opts; 18 | sqltoast::parse_input_t subject; 19 | sqltoast::parse_result_t res; 20 | parser(sqltoast::parse_options_t& opts, const std::string &input) : 21 | opts(opts), 22 | subject(input.cbegin(), input.cend()) 23 | {} 24 | void operator()() { 25 | res = sqltoast::parse(subject, opts); 26 | } 27 | }; 28 | 29 | void usage(const char* prg_name) { 30 | std::cout << "Usage: " << prg_name << 31 | " [--disable-timer] [--yaml] " << std::endl; 32 | std::cout << " using libsqltoast version " << 33 | SQLTOAST_VERSION_MAJOR << '.' << 34 | SQLTOAST_VERSION_MINOR << std::endl; 35 | } 36 | 37 | int main (int argc, char *argv[]) 38 | { 39 | std::string input; 40 | bool disable_timer = false; 41 | bool use_yaml = false; 42 | 43 | for (int x = 1; x < argc; x++) { 44 | if (strcmp(argv[x], "--disable-timer") == 0) { 45 | disable_timer = true; 46 | continue; 47 | } 48 | if (strcmp(argv[x], "--yaml") == 0) { 49 | use_yaml = true; 50 | continue; 51 | } 52 | input.assign(argv[x]); 53 | break; 54 | } 55 | if (input.empty()) { 56 | usage(argv[0]); 57 | return 1; 58 | } 59 | 60 | sqltoast::parse_options_t opts = {sqltoast::SQL_DIALECT_ANSI_1992, false}; 61 | parser p(opts, input); 62 | 63 | auto dur = measure::execution(p); 64 | sqltoaster::printer ptr(p.res, std::cout); 65 | if (use_yaml) 66 | ptr.output_format = sqltoaster::OUTPUT_FORMAT_YAML; 67 | if (p.res.code == sqltoast::PARSE_OK) 68 | std::cout << ptr << std::endl; 69 | else if (p.res.code == sqltoast::PARSE_INPUT_ERROR) 70 | std::cout << "Input error: " << p.res.error << std::endl; 71 | else { 72 | std::cout << "Syntax error." << std::endl; 73 | std::cout << p.res.error << std::endl; 74 | } 75 | if (! disable_timer) 76 | std::cout << "(took " << dur << " nanoseconds)" << std::endl; 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /sqltoaster/measure.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | 8 | #ifndef SQLTOASTER_MEASURE_H 9 | #define SQLTOASTER_MEASURE_H 10 | 11 | #include 12 | 13 | template 14 | struct measure 15 | { 16 | template 17 | static typename TimeT::rep execution(F&& func, Args&&... args) 18 | { 19 | auto start = std::chrono::steady_clock::now(); 20 | std::forward(func)(std::forward(args)...); 21 | auto duration = std::chrono::duration_cast 22 | (std::chrono::steady_clock::now() - start); 23 | return duration.count(); 24 | } 25 | }; 26 | 27 | #endif /* SQLTOASTER_MEASURE_H */ 28 | -------------------------------------------------------------------------------- /sqltoaster/node.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include 8 | 9 | #include "node.h" 10 | #include "printer.h" 11 | 12 | namespace sqltoaster { 13 | 14 | void print_map(std::ostream& out, const mapping_t& mapping, size_t indent_level, bool is_list_item) { 15 | for (const std::unique_ptr& el : mapping.elements) { 16 | if (! is_list_item) { 17 | if (indent_level > 0) 18 | out << std::endl; 19 | out << std::string(indent_level * 2, ' '); 20 | } 21 | else { 22 | out << std::endl << std::string((indent_level - 1) * 2, ' ') << "- "; 23 | is_list_item = false; 24 | } 25 | 26 | switch (el->value->type) { 27 | case SCALAR: 28 | { 29 | const scalar_t& sub = 30 | static_cast(*el->value); 31 | out << el->key << ": " << sub.value; 32 | } 33 | break; 34 | case MAPPING: 35 | { 36 | const mapping_t& sub = 37 | static_cast(*el->value); 38 | out << el->key << ":"; 39 | print_map(out, sub, indent_level + 1, false); 40 | } 41 | break; 42 | case SEQUENCE: 43 | { 44 | const sequence_t& sub = 45 | static_cast(*el->value); 46 | out << el->key << ":"; 47 | for (const std::unique_ptr& list_el : sub.elements) { 48 | if (list_el->type == SCALAR) { 49 | const scalar_t& sub = 50 | static_cast(*list_el); 51 | out << std::endl << std::string((indent_level + 1) * 2, ' ') << "- "; 52 | out << sub.value; 53 | } else if (list_el->type == MAPPING) { 54 | const mapping_t& sub = 55 | static_cast(*list_el); 56 | print_map(out, sub, indent_level + 2, true); 57 | } 58 | } 59 | } 60 | break; 61 | } 62 | } 63 | } 64 | 65 | } // namespace sqltoaster 66 | -------------------------------------------------------------------------------- /sqltoaster/node.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOASTER_NODE_H 8 | #define SQLTOASTER_NODE_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace sqltoaster { 18 | 19 | typedef enum node_type { 20 | SCALAR, 21 | SEQUENCE, 22 | MAPPING 23 | } node_type_t; 24 | 25 | struct printer; 26 | typedef struct node { 27 | node_type_t type; 28 | node(node_type_t type) : 29 | type(type) 30 | {} 31 | } node_t; 32 | 33 | typedef struct scalar : node_t { 34 | std::string value; 35 | scalar() : 36 | node_t(SCALAR) 37 | {} 38 | scalar(const char *val) : 39 | node_t(SCALAR), 40 | value(val) 41 | {} 42 | scalar(const std::string& val) : 43 | node_t(SCALAR), 44 | value(val) 45 | {} 46 | scalar(const sqltoast::lexeme_t& val) : 47 | node_t(SCALAR), 48 | value(std::string(val.start, val.end)) 49 | {} 50 | inline void assign(const char *val) { 51 | value.assign(std::string(val)); 52 | } 53 | } scalar_t; 54 | 55 | typedef struct sequence : node_t { 56 | std::vector> elements; 57 | sequence() : 58 | node_t(SEQUENCE) 59 | {} 60 | sequence(std::vector>& elements) : 61 | node_t(SEQUENCE), 62 | elements(std::move(elements)) 63 | {} 64 | inline void append(const sqltoast::lexeme_t& value) { 65 | std::unique_ptr val = std::make_unique(value); 66 | elements.emplace_back(std::move(val)); 67 | } 68 | inline void append(const std::string& value) { 69 | std::unique_ptr val = std::make_unique(value); 70 | elements.emplace_back(std::move(val)); 71 | } 72 | inline void append(std::unique_ptr& value) { 73 | elements.emplace_back(std::move(value)); 74 | } 75 | } sequence_t; 76 | 77 | typedef struct mapping_value { 78 | const std::string key; 79 | std::unique_ptr value; 80 | mapping_value(const std::string& key, std::unique_ptr& value) : 81 | key(key), 82 | value(std::move(value)) 83 | {} 84 | } mapping_value_t; 85 | 86 | typedef struct mapping : node_t { 87 | std::vector> elements; 88 | mapping() : 89 | node_t(MAPPING) 90 | {} 91 | mapping(std::vector>& elements) : 92 | node_t(MAPPING), 93 | elements(std::move(elements)) 94 | {} 95 | inline void setattr(const char *key, std::unique_ptr& value) { 96 | elements.emplace_back(std::make_unique(std::string(key), value)); 97 | } 98 | inline void setattr(const char *key, const char *value) { 99 | std::unique_ptr val = std::make_unique(value); 100 | setattr(key, val); 101 | } 102 | inline void setattr(const char *key, const sqltoast::lexeme_t& value) { 103 | setattr(key, std::string(value.start, value.end).c_str()); 104 | } 105 | inline void setattr(const char *key, const std::string& value) { 106 | setattr(key, value.c_str()); 107 | } 108 | inline void setattr(const sqltoast::lexeme_t& key, const std::string& value) { 109 | setattr(std::string(key.start, key.end).c_str(), value); 110 | } 111 | } mapping_t; 112 | 113 | void print_map(std::ostream& out, const mapping_t& mapping, size_t indent_level, bool is_list_item); 114 | 115 | } // namespace sqltoaster 116 | 117 | #endif /* SQLTOASTER_NODE_H */ 118 | -------------------------------------------------------------------------------- /sqltoaster/printer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #include 8 | 9 | #include "node.h" 10 | #include "fill.h" 11 | #include "printer.h" 12 | 13 | namespace sqltoaster { 14 | 15 | std::ostream& operator<< (std::ostream& out, printer_t& ptr) { 16 | if (ptr.output_format == OUTPUT_FORMAT_DEFAULT) { 17 | unsigned int x = 0; 18 | for (auto stmt_ptr_it = ptr.res.statements.cbegin(); 19 | stmt_ptr_it != ptr.res.statements.cend(); 20 | stmt_ptr_it++) { 21 | out << std::endl << "statements[" << x++ << "]:" << std::endl; 22 | out << " " << *(*stmt_ptr_it); 23 | } 24 | } else { 25 | ptr.process_statements(); 26 | if (ptr.statement_node_count()) { 27 | mapping_t statements; 28 | statements.setattr("statements", ptr.statements); 29 | print_map(out, statements, 0, false); 30 | } 31 | } 32 | return out; 33 | } 34 | 35 | void printer_t::process_statements() { 36 | std::unique_ptr statement_node; 37 | for (std::unique_ptr& stmt : res.statements) { 38 | std::unique_ptr statement_node = std::make_unique(); 39 | mapping_t& statement_map = 40 | static_cast(*statement_node); 41 | fill(statement_map, *stmt); 42 | add_statement_node(statement_node); 43 | } 44 | } 45 | 46 | } // namespace sqltoaster 47 | -------------------------------------------------------------------------------- /sqltoaster/printer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Use and distribution licensed under the Apache license version 2. 3 | * 4 | * See the COPYING file in the root project directory for full text. 5 | */ 6 | 7 | #ifndef SQLTOASTER_PRINTER_H 8 | #define SQLTOASTER_PRINTER_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "node.h" 15 | 16 | namespace sqltoaster { 17 | 18 | typedef enum output_format { 19 | OUTPUT_FORMAT_DEFAULT, 20 | OUTPUT_FORMAT_YAML 21 | } output_format_t; 22 | 23 | typedef struct printer { 24 | int iomanip_indexes[1]; 25 | sqltoast::parse_result_t& res; 26 | output_format_t output_format; 27 | size_t indent_level; 28 | bool list_item; 29 | std::unique_ptr statements; 30 | printer( 31 | sqltoast::parse_result_t& res, 32 | std::ostream& out) : 33 | res(res), 34 | output_format(OUTPUT_FORMAT_DEFAULT), 35 | indent_level(0), 36 | list_item(false), 37 | statements(std::make_unique()) 38 | {} 39 | inline void indent_push(std::ostream& out) { 40 | indent_level++; 41 | } 42 | inline void indent_pop(std::ostream& out) { 43 | indent_level--; 44 | } 45 | inline std::ostream& indent(std::ostream& out) { 46 | out << std::endl; 47 | if (indent_level > 0) 48 | out << std::string(indent_level * 2, ' '); 49 | return out; 50 | } 51 | inline void start_list(std::ostream& out) { 52 | list_item = true; 53 | } 54 | inline void end_list(std::ostream& out) { 55 | list_item = false; 56 | } 57 | inline bool in_list(std::ostream& out) const { 58 | return list_item; 59 | } 60 | inline void add_statement_node(std::unique_ptr& node) { 61 | sequence_t& stmt_seq = static_cast(*statements); 62 | stmt_seq.elements.emplace_back(std::move(node)); 63 | } 64 | inline size_t statement_node_count() const { 65 | sequence_t& stmt_seq = static_cast(*statements); 66 | return stmt_seq.elements.size(); 67 | } 68 | void process_statements(); 69 | } printer_t; 70 | 71 | std::ostream& operator<< (std::ostream& out, printer_t& ptr); 72 | 73 | } // namespace sqltoaster 74 | 75 | #endif /* SQLTOASTER_PRINTER_H */ 76 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/alter-table.test: -------------------------------------------------------------------------------- 1 | # ADD COLUMN action missing column definition 2 | >ALTER TABLE t1 ADD COLUMN; 3 | Syntax error. 4 | Expected but found symbol[';'] 5 | ALTER TABLE t1 ADD COLUMN; 6 | ^^ 7 | # ADD COLUMN action invalid column definition 8 | >ALTER TABLE t1 ADD COLUMN b; 9 | Syntax error. 10 | Expected but found symbol[';'] 11 | ALTER TABLE t1 ADD COLUMN b; 12 | ^^ 13 | # ADD COLUMN action 14 | >ALTER TABLE t1 ADD COLUMN b INT; 15 | statements: 16 | - type: ALTER_TABLE 17 | alter_table_statement: 18 | table_name: t1 19 | action: ADD COLUMN b INT 20 | # ADD COLUMN action without optional COLUMN keyword 21 | >ALTER TABLE t1 ADD b INT; 22 | statements: 23 | - type: ALTER_TABLE 24 | alter_table_statement: 25 | table_name: t1 26 | action: ADD COLUMN b INT 27 | # ALTER COLUMN SET DEFAULT action 28 | >ALTER TABLE t1 ALTER COLUMN b SET DEFAULT NULL; 29 | statements: 30 | - type: ALTER_TABLE 31 | alter_table_statement: 32 | table_name: t1 33 | action: ALTER COLUMN b SET DEFAULT NULL 34 | # ALTER COLUMN SET DEFAULT action optional COLUMN keyword 35 | >ALTER TABLE t1 ALTER b SET DEFAULT NULL; 36 | statements: 37 | - type: ALTER_TABLE 38 | alter_table_statement: 39 | table_name: t1 40 | action: ALTER COLUMN b SET DEFAULT NULL 41 | # ALTER COLUMN DROP DEFAULT action 42 | >ALTER TABLE t1 ALTER COLUMN b DROP DEFAULT; 43 | statements: 44 | - type: ALTER_TABLE 45 | alter_table_statement: 46 | table_name: t1 47 | action: ALTER COLUMN b DROP DEFAULT 48 | # DROP COLUMN action no drop behaviour 49 | >ALTER TABLE t1 DROP COLUMN b; 50 | statements: 51 | - type: ALTER_TABLE 52 | alter_table_statement: 53 | table_name: t1 54 | action: DROP COLUMN b CASCADE 55 | # DROP COLUMN action no drop behaviour no optional COLUMN keyword 56 | >ALTER TABLE t1 DROP b; 57 | statements: 58 | - type: ALTER_TABLE 59 | alter_table_statement: 60 | table_name: t1 61 | action: DROP COLUMN b CASCADE 62 | # DROP COLUMN action with explicit drop behaviour of default CASCADE 63 | >ALTER TABLE t1 DROP COLUMN b CASCADE; 64 | statements: 65 | - type: ALTER_TABLE 66 | alter_table_statement: 67 | table_name: t1 68 | action: DROP COLUMN b CASCADE 69 | # DROP COLUMN action with explicit drop behaviour of RESTRICT 70 | >ALTER TABLE t1 DROP COLUMN b RESTRICT; 71 | statements: 72 | - type: ALTER_TABLE 73 | alter_table_statement: 74 | table_name: t1 75 | action: DROP COLUMN b RESTRICT 76 | # ADD CONSTRAINT action with UNIQUE constraint 77 | >ALTER TABLE t1 ADD UNIQUE (b, c); 78 | statements: 79 | - type: ALTER_TABLE 80 | alter_table_statement: 81 | table_name: t1 82 | action: ADD UNIQUE (b,c) 83 | # ADD CONSTRAINT action with UNIQUE constraint with constraint name 84 | >ALTER TABLE t1 ADD CONSTRAINT u_bc UNIQUE (b, c); 85 | statements: 86 | - type: ALTER_TABLE 87 | alter_table_statement: 88 | table_name: t1 89 | action: ADD CONSTRAINT u_bc UNIQUE (b,c) 90 | # ADD CONSTRAINT action with PRIMARY KEY constraint 91 | >ALTER TABLE t1 ADD PRIMARY KEY (b, c); 92 | statements: 93 | - type: ALTER_TABLE 94 | alter_table_statement: 95 | table_name: t1 96 | action: ADD PRIMARY KEY (b,c) 97 | # ADD CONSTRAINT action with PRIMARY KEY constraint with constraint name 98 | >ALTER TABLE t1 ADD CONSTRAINT pk PRIMARY KEY (b, c); 99 | statements: 100 | - type: ALTER_TABLE 101 | alter_table_statement: 102 | table_name: t1 103 | action: ADD CONSTRAINT pk PRIMARY KEY (b,c) 104 | # ADD CONSTRAINT action with FOREIGN KEY constraint 105 | >ALTER TABLE t1 ADD FOREIGN KEY (t2_id) REFERENCES t2 (id); 106 | statements: 107 | - type: ALTER_TABLE 108 | alter_table_statement: 109 | table_name: t1 110 | action: ADD FOREIGN KEY (t2_id) REFERENCES t2 (id) 111 | # ADD CONSTRAINT action with FOREIGN KEY constraint with constraint name 112 | >ALTER TABLE t1 ADD CONSTRAINT fk_t2 FOREIGN KEY (t2_id) REFERENCES t2 (id); 113 | statements: 114 | - type: ALTER_TABLE 115 | alter_table_statement: 116 | table_name: t1 117 | action: ADD CONSTRAINT fk_t2 FOREIGN KEY (t2_id) REFERENCES t2 (id) 118 | # DROP CONSTRAINT action no drop behaviour 119 | >ALTER TABLE t1 DROP CONSTRAINT b; 120 | statements: 121 | - type: ALTER_TABLE 122 | alter_table_statement: 123 | table_name: t1 124 | action: DROP CONSTRAINT b CASCADE 125 | # DROP CONSTRAINT action with explicit drop behaviour of default CASCADE 126 | >ALTER TABLE t1 DROP CONSTRAINT b CASCADE; 127 | statements: 128 | - type: ALTER_TABLE 129 | alter_table_statement: 130 | table_name: t1 131 | action: DROP CONSTRAINT b CASCADE 132 | # DROP CONSTRAINT action with explicit drop behaviour of RESTRICT 133 | >ALTER TABLE t1 DROP CONSTRAINT b RESTRICT; 134 | statements: 135 | - type: ALTER_TABLE 136 | alter_table_statement: 137 | table_name: t1 138 | action: DROP CONSTRAINT b RESTRICT 139 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/column-definitions.test: -------------------------------------------------------------------------------- 1 | # Numeric column definitions 2 | >CREATE TABLE t1 ( 3 | > a INT, 4 | > b INTEGER, 5 | > c SMALLINT, 6 | > d DEC, 7 | > e DECIMAL, 8 | > f NUMERIC, 9 | > g FLOAT, 10 | > h REAL, 11 | > i DOUBLE PRECISION 12 | >) 13 | statements: 14 | - type: CREATE_TABLE 15 | create_table_statement: 16 | table_name: t1 17 | column_definitions: 18 | a: INT 19 | b: INT 20 | c: SMALLINT 21 | d: NUMERIC 22 | e: NUMERIC 23 | f: NUMERIC 24 | g: FLOAT 25 | h: FLOAT(24) 26 | i: DOUBLE PRECISION 27 | # Character column definitions 28 | >CREATE TABLE t1 ( 29 | > a CHAR, 30 | > b CHARACTER, 31 | > c CHAR(10), 32 | > d CHARACTER(10), 33 | > e VARCHAR, 34 | > f CHAR VARYING, 35 | > g CHARACTER VARYING, 36 | > h VARCHAR(10), 37 | > i CHAR VARYING(10), 38 | > j CHARACTER VARYING(10) 39 | >) 40 | statements: 41 | - type: CREATE_TABLE 42 | create_table_statement: 43 | table_name: t1 44 | column_definitions: 45 | a: CHAR 46 | b: CHAR 47 | c: CHAR(10) 48 | d: CHAR(10) 49 | e: VARCHAR 50 | f: VARCHAR 51 | g: VARCHAR 52 | h: VARCHAR(10) 53 | i: VARCHAR(10) 54 | j: VARCHAR(10) 55 | # default descriptors of various kinds 56 | >CREATE TABLE t1 ( 57 | > a INT DEFAULT 0, 58 | > b INT DEFAULT -1, 59 | > c VARCHAR DEFAULT CURRENT_USER, 60 | > d DATE DEFAULT CURRENT_DATE 61 | >) 62 | statements: 63 | - type: CREATE_TABLE 64 | create_table_statement: 65 | table_name: t1 66 | column_definitions: 67 | a: INT DEFAULT 0 68 | b: INT DEFAULT -1 69 | c: VARCHAR DEFAULT CURRENT_USER 70 | d: DATE DEFAULT CURRENT_DATE 71 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/create-schema.test: -------------------------------------------------------------------------------- 1 | # Missing schema name 2 | >CREATE SCHEMA 3 | Syntax error. 4 | Expected to find << identifier >> but found symbol[EOS] 5 | CREATE SCHEMA 6 | ^ 7 | # Simple CREATE SCHEMA no options 8 | >CREATE SCHEMA s1 9 | statements: 10 | - type: CREATE_SCHEMA 11 | create_schema_statement: 12 | schema_name: s1 13 | # Simple CREATE SCHEMA with authorizer 14 | >CREATE SCHEMA s1 AUTHORIZATION usr 15 | statements: 16 | - type: CREATE_SCHEMA 17 | create_schema_statement: 18 | schema_name: s1 19 | authorization_identifier: usr 20 | # Simple CREATE SCHEMA with default character set 21 | >CREATE SCHEMA s1 DEFAULT CHARACTER SET utf8 22 | statements: 23 | - type: CREATE_SCHEMA 24 | create_schema_statement: 25 | schema_name: s1 26 | default_charset: utf8 27 | # Simple CREATE SCHEMA with default character set and authorization 28 | >CREATE SCHEMA s1 AUTHORIZATION usr DEFAULT CHARACTER SET utf8 29 | statements: 30 | - type: CREATE_SCHEMA 31 | create_schema_statement: 32 | schema_name: s1 33 | authorization_identifier: usr 34 | default_charset: utf8 35 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/create-table.test: -------------------------------------------------------------------------------- 1 | # NOT NULL constraint 2 | >CREATE TABLE t1 ( 3 | > a INT NOT NULL 4 | >) 5 | statements: 6 | - type: CREATE_TABLE 7 | create_table_statement: 8 | table_name: t1 9 | column_definitions: 10 | a: INT NOT NULL 11 | # PRIMARY KEY 12 | >CREATE TABLE t1 ( 13 | > a INT PRIMARY KEY 14 | >) 15 | statements: 16 | - type: CREATE_TABLE 17 | create_table_statement: 18 | table_name: t1 19 | column_definitions: 20 | a: INT PRIMARY KEY 21 | # NOT NULL constraint plus PRIMARY KEY 22 | >CREATE TABLE t1 ( 23 | > a INT NOT NULL PRIMARY KEY 24 | >) 25 | statements: 26 | - type: CREATE_TABLE 27 | create_table_statement: 28 | table_name: t1 29 | column_definitions: 30 | a: INT NOT NULL PRIMARY KEY 31 | # UNIQUE constraint on single column 32 | >CREATE TABLE t1 ( 33 | > a CHAR UNIQUE 34 | >) 35 | statements: 36 | - type: CREATE_TABLE 37 | create_table_statement: 38 | table_name: t1 39 | column_definitions: 40 | a: CHAR UNIQUE 41 | # NOT NULL constraint plus UNIQUE 42 | >CREATE TABLE t1 ( 43 | > a CHAR(10) NOT NULL UNIQUE 44 | >) 45 | statements: 46 | - type: CREATE_TABLE 47 | create_table_statement: 48 | table_name: t1 49 | column_definitions: 50 | a: CHAR(10) NOT NULL UNIQUE 51 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/create-view.test: -------------------------------------------------------------------------------- 1 | # missing table/view name 2 | >CREATE VIEW AS SELECT * FROM t1 3 | Syntax error. 4 | Expected to find << identifier >> but found keyword[AS] 5 | CREATE VIEW AS SELECT * FROM t1 6 | ^^^^^^^^^^^^^^^^^^^^ 7 | # Missing "AS" keyword results in syntax error 8 | >CREATE VIEW v1 SELECT * FROM t1 9 | Syntax error. 10 | Expected to find AS but found keyword[SELECT] 11 | CREATE VIEW v1 SELECT * FROM t1 12 | ^^^^^^^^^^^^^^^^^ 13 | >CREATE VIEW v1 AS SELECT * FROM t1 14 | statements: 15 | - type: CREATE_VIEW 16 | create_view_statement: 17 | view_name: v1 18 | query: 19 | selected_columns: 20 | - asterisk: true 21 | referenced_tables: 22 | - type: TABLE 23 | table: 24 | name: t1 25 | # Use the optional column list 26 | >CREATE VIEW v1 (a, b) AS SELECT a, b FROM t1 27 | statements: 28 | - type: CREATE_VIEW 29 | create_view_statement: 30 | view_name: v1 31 | columns: 32 | - a 33 | - b 34 | query: 35 | selected_columns: 36 | - type: NUMERIC_EXPRESSION 37 | numeric_expression: 38 | left: 39 | left: 40 | primary: 41 | type: VALUE 42 | value: 43 | primary: 44 | type: COLUMN_REFERENCE 45 | column_reference: a 46 | - type: NUMERIC_EXPRESSION 47 | numeric_expression: 48 | left: 49 | left: 50 | primary: 51 | type: VALUE 52 | value: 53 | primary: 54 | type: COLUMN_REFERENCE 55 | column_reference: b 56 | referenced_tables: 57 | - type: TABLE 58 | table: 59 | name: t1 60 | # The optional WITH LOCAL CHECK OPTION clause 61 | >CREATE VIEW v1 AS SELECT * FROM t1 WITH LOCAL CHECK OPTION 62 | statements: 63 | - type: CREATE_VIEW 64 | create_view_statement: 65 | view_name: v1 66 | check_option: LOCAL 67 | query: 68 | selected_columns: 69 | - asterisk: true 70 | referenced_tables: 71 | - type: TABLE 72 | table: 73 | name: t1 74 | # The optional WITH CASCADED CHECK OPTION clause 75 | >CREATE VIEW v1 AS SELECT * FROM t1 WITH CASCADED CHECK OPTION 76 | statements: 77 | - type: CREATE_VIEW 78 | create_view_statement: 79 | view_name: v1 80 | check_option: CASCADED 81 | query: 82 | selected_columns: 83 | - asterisk: true 84 | referenced_tables: 85 | - type: TABLE 86 | table: 87 | name: t1 88 | # Missing either LOCAL or CASCADED for the check option clause 89 | >CREATE VIEW v1 AS SELECT * FROM t1 WITH CHECK OPTION 90 | Syntax error. 91 | Expected to find one of (CASCADED|LOCAL) but found keyword[CHECK] 92 | CREATE VIEW v1 AS SELECT * FROM t1 WITH CHECK OPTION 93 | ^^^^^^^^^^^^^ 94 | # Missing CHECK symbol for the check option clause 95 | >CREATE VIEW v1 AS SELECT * FROM t1 WITH LOCAL OPTION 96 | Syntax error. 97 | Expected to find CHECK but found keyword[OPTION] 98 | CREATE VIEW v1 AS SELECT * FROM t1 WITH LOCAL OPTION 99 | ^^^^^^^ 100 | # Missing CHECK symbol for the check option clause 101 | >CREATE VIEW v1 AS SELECT * FROM t1 WITH LOCAL CHECK 102 | Syntax error. 103 | Expected to find OPTION but found symbol[EOS] 104 | CREATE VIEW v1 AS SELECT * FROM t1 WITH LOCAL CHECK 105 | ^ 106 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/delete.test: -------------------------------------------------------------------------------- 1 | # DELETE with no WHERE condition 2 | >DELETE FROM t1 3 | statements: 4 | - type: DELETE 5 | delete_statement: 6 | table_name: t1 7 | # DELETE with simple WHERE condition with equality comparison 8 | >DELETE FROM t1 WHERE a = 10 9 | statements: 10 | - type: DELETE 11 | delete_statement: 12 | table_name: t1 13 | where: 14 | terms: 15 | - factor: 16 | predicate: 17 | type: COMPARISON 18 | comparison_predicate: 19 | op: EQUAL 20 | left: 21 | type: ELEMENT 22 | element: 23 | type: VALUE_EXPRESSION 24 | value_expression: 25 | type: NUMERIC_EXPRESSION 26 | numeric_expression: 27 | left: 28 | left: 29 | primary: 30 | type: VALUE 31 | value: 32 | primary: 33 | type: COLUMN_REFERENCE 34 | column_reference: a 35 | right: 36 | type: ELEMENT 37 | element: 38 | type: VALUE_EXPRESSION 39 | value_expression: 40 | type: NUMERIC_EXPRESSION 41 | numeric_expression: 42 | left: 43 | left: 44 | primary: 45 | type: VALUE 46 | value: 47 | primary: 48 | type: UNSIGNED_VALUE_SPECIFICATION 49 | unsigned_value_specification: literal[10] 50 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/drop-schema.test: -------------------------------------------------------------------------------- 1 | # Simple DROP SCHEMA with no drop behaviour defaults to CASCADE 2 | >DROP SCHEMA s1 3 | statements: 4 | - type: DROP_SCHEMA 5 | drop_schema_statement: 6 | schema_name: s1 7 | drop_behaviour: CASCADE 8 | # Simple DROP SCHEMA with explicit drop behaviour of CASCADE 9 | >DROP SCHEMA s1 CASCADE 10 | statements: 11 | - type: DROP_SCHEMA 12 | drop_schema_statement: 13 | schema_name: s1 14 | drop_behaviour: CASCADE 15 | # Simple DROP SCHEMA with explicit drop behaviour of RESTRICT 16 | >DROP SCHEMA s1 RESTRICT 17 | statements: 18 | - type: DROP_SCHEMA 19 | drop_schema_statement: 20 | schema_name: s1 21 | drop_behaviour: RESTRICT 22 | # Syntax error missing table/schema name 23 | >DROP SCHEMA 24 | Syntax error. 25 | Expected to find << identifier >> but found symbol[EOS] 26 | DROP SCHEMA 27 | ^ 28 | # Syntax error expecting statement ending 29 | >DROP SCHEMA s1 UNKNOWN 30 | Syntax error. 31 | Expected to find one of (EOS|';') but found identifier[UNKNOWN] 32 | DROP SCHEMA s1 UNKNOWN 33 | ^^^^^^^^ 34 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/drop-table.test: -------------------------------------------------------------------------------- 1 | # Simple DROP TABLE with no drop behaviour defaults to CASCADE 2 | >DROP TABLE t1 3 | statements: 4 | - type: DROP_TABLE 5 | drop_table_statement: 6 | table_name: t1 7 | drop_behaviour: CASCADE 8 | # Simple DROP TABLE with explicit drop behaviour of CASCADE 9 | >DROP TABLE t1 CASCADE 10 | statements: 11 | - type: DROP_TABLE 12 | drop_table_statement: 13 | table_name: t1 14 | drop_behaviour: CASCADE 15 | # Simple DROP TABLE with explicit drop behaviour of RESTRICT 16 | >DROP TABLE t1 RESTRICT 17 | statements: 18 | - type: DROP_TABLE 19 | drop_table_statement: 20 | table_name: t1 21 | drop_behaviour: RESTRICT 22 | # Syntax error missing table/table name 23 | >DROP TABLE 24 | Syntax error. 25 | Expected to find << identifier >> but found symbol[EOS] 26 | DROP TABLE 27 | ^ 28 | # Syntax error expecting statement ending 29 | >DROP TABLE t1 UNKNOWN 30 | Syntax error. 31 | Expected to find one of (EOS|';') but found identifier[UNKNOWN] 32 | DROP TABLE t1 UNKNOWN 33 | ^^^^^^^^ 34 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/drop-view.test: -------------------------------------------------------------------------------- 1 | # Simple DROP VIEW with no drop behaviour defaults to CASCADE 2 | >DROP VIEW v1 3 | statements: 4 | - type: DROP_VIEW 5 | drop_view_statement: 6 | view_name: v1 7 | drop_behaviour: CASCADE 8 | # Simple DROP VIEW with explicit drop behaviour of CASCADE 9 | >DROP VIEW v1 CASCADE 10 | statements: 11 | - type: DROP_VIEW 12 | drop_view_statement: 13 | view_name: v1 14 | drop_behaviour: CASCADE 15 | # Simple DROP VIEW with explicit drop behaviour of RESTRICT 16 | >DROP VIEW v1 RESTRICT 17 | statements: 18 | - type: DROP_VIEW 19 | drop_view_statement: 20 | view_name: v1 21 | drop_behaviour: RESTRICT 22 | # Syntax error missing table/view name 23 | >DROP VIEW 24 | Syntax error. 25 | Expected to find << identifier >> but found symbol[EOS] 26 | DROP VIEW 27 | ^ 28 | # Syntax error expecting statement ending 29 | >DROP VIEW v1 UNKNOWN 30 | Syntax error. 31 | Expected to find one of (EOS|';') but found identifier[UNKNOWN] 32 | DROP VIEW v1 UNKNOWN 33 | ^^^^^^^^ 34 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/grant.test: -------------------------------------------------------------------------------- 1 | # Syntax error expected PRIVILEGES 2 | >GRANT ALL 3 | Syntax error. 4 | Expected to find PRIVILEGES but found symbol[EOS] 5 | GRANT ALL 6 | ^ 7 | # Syntax error expected ON 8 | >GRANT ALL PRIVILEGES 9 | Syntax error. 10 | Expected to find ON but found symbol[EOS] 11 | GRANT ALL PRIVILEGES 12 | ^ 13 | # Syntax error expected TO 14 | >GRANT ALL PRIVILEGES ON db 15 | Syntax error. 16 | Expected to find TO but found symbol[EOS] 17 | GRANT ALL PRIVILEGES ON db 18 | ^ 19 | # Syntax error expected identifier or PUBLIC 20 | >GRANT ALL PRIVILEGES ON db TO WITH GRANT 21 | Syntax error. 22 | Expected to find one of (<< identifier >>|PUBLIC) but found symbol[WITH] 23 | GRANT ALL PRIVILEGES ON db TO WITH GRANT 24 | ^^^^^^^^^^^ 25 | # Syntax error expected GRANT 26 | >GRANT ALL PRIVILEGES ON db TO usr WITH 27 | Syntax error. 28 | Expected to find GRANT but found symbol[EOS] 29 | GRANT ALL PRIVILEGES ON db TO usr WITH 30 | ^ 31 | # Syntax error expected OPTION 32 | >GRANT ALL PRIVILEGES ON db TO usr WITH GRANT 33 | Syntax error. 34 | Expected to find OPTION but found symbol[EOS] 35 | GRANT ALL PRIVILEGES ON db TO usr WITH GRANT 36 | ^ 37 | # GRANT all to a user, no grant option 38 | >GRANT ALL PRIVILEGES ON db TO usr 39 | statements: 40 | - type: GRANT 41 | grant_statement: 42 | on: db 43 | to: usr 44 | privileges: 45 | - ALL 46 | # GRANT specific privileges to a user, no grant option 47 | >GRANT SELECT, DELETE, USAGE ON db TO usr 48 | statements: 49 | - type: GRANT 50 | grant_statement: 51 | on: db 52 | to: usr 53 | privileges: 54 | - SELECT 55 | - DELETE 56 | - USAGE 57 | # GRANT privilege with action taking columns 58 | >GRANT INSERT (a, b, c) ON tbl TO usr 59 | statements: 60 | - type: GRANT 61 | grant_statement: 62 | on: tbl 63 | to: usr 64 | privileges: 65 | - INSERT (a,b,c) 66 | # GRANT privilege with action taking columns along with no optional columns for 67 | # update 68 | >GRANT INSERT (a, b, c), UPDATE ON tbl TO usr 69 | statements: 70 | - type: GRANT 71 | grant_statement: 72 | on: tbl 73 | to: usr 74 | privileges: 75 | - INSERT (a,b,c) 76 | - UPDATE 77 | # GRANT all on domain object to a user 78 | >GRANT ALL PRIVILEGES ON DOMAIN dom TO usr 79 | statements: 80 | - type: GRANT 81 | grant_statement: 82 | on: DOMAIN dom 83 | to: usr 84 | privileges: 85 | - ALL 86 | # GRANT all on collation object to a user 87 | >GRANT ALL PRIVILEGES ON COLLATION utf8bin TO usr 88 | statements: 89 | - type: GRANT 90 | grant_statement: 91 | on: COLLATION utf8bin 92 | to: usr 93 | privileges: 94 | - ALL 95 | # GRANT all on characterset object to a user 96 | >GRANT ALL PRIVILEGES ON CHARACTER SET utf8 TO usr 97 | statements: 98 | - type: GRANT 99 | grant_statement: 100 | on: CHARACTER SET utf8 101 | to: usr 102 | privileges: 103 | - ALL 104 | # GRANT all on translation object to a user 105 | >GRANT ALL PRIVILEGES ON TRANSLATION trns TO usr 106 | statements: 107 | - type: GRANT 108 | grant_statement: 109 | on: TRANSLATION trns 110 | to: usr 111 | privileges: 112 | - ALL 113 | # Syntax error expecting SET after CHARACTER 114 | >GRANT ALL PRIVILEGES ON CHARACTER utf8 TO usr 115 | Syntax error. 116 | Expected to find SET but found identifier[utf8] 117 | GRANT ALL PRIVILEGES ON CHARACTER utf8 TO usr 118 | ^^^^^^^^^^^^ 119 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/identifiers.test: -------------------------------------------------------------------------------- 1 | # Simple identifier all alphanumeric 2 | >SELECT * FROM t1 3 | statements: 4 | - type: SELECT 5 | select_statement: 6 | query: 7 | selected_columns: 8 | - asterisk: true 9 | referenced_tables: 10 | - type: TABLE 11 | table: 12 | name: t1 13 | # Identifier includes an underscore 14 | >SELECT * FROM t1_backup 15 | statements: 16 | - type: SELECT 17 | select_statement: 18 | query: 19 | selected_columns: 20 | - asterisk: true 21 | referenced_tables: 22 | - type: TABLE 23 | table: 24 | name: t1_backup 25 | # Identifier includes a period 26 | >SELECT * FROM s1.t1 27 | statements: 28 | - type: SELECT 29 | select_statement: 30 | query: 31 | selected_columns: 32 | - asterisk: true 33 | referenced_tables: 34 | - type: TABLE 35 | table: 36 | name: s1.t1 37 | # Identifier includes multiple periods and underscore 38 | >SELECT * FROM c1.s1.t1_backup 39 | statements: 40 | - type: SELECT 41 | select_statement: 42 | query: 43 | selected_columns: 44 | - asterisk: true 45 | referenced_tables: 46 | - type: TABLE 47 | table: 48 | name: c1.s1.t1_backup 49 | # Identifier includes a prefix and a star projection 50 | >SELECT t1.* FROM t1 51 | statements: 52 | - type: SELECT 53 | select_statement: 54 | query: 55 | selected_columns: 56 | - type: NUMERIC_EXPRESSION 57 | numeric_expression: 58 | left: 59 | left: 60 | primary: 61 | type: VALUE 62 | value: 63 | primary: 64 | type: COLUMN_REFERENCE 65 | column_reference: t1.* 66 | referenced_tables: 67 | - type: TABLE 68 | table: 69 | name: t1 70 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/insert-select.test: -------------------------------------------------------------------------------- 1 | # INSERT SELECT with default columns 2 | >INSERT INTO t1 SELECT a, b FROM t1 3 | statements: 4 | - type: INSERT 5 | insert_statement: 6 | table_name: t1 7 | query: 8 | selected_columns: 9 | - type: NUMERIC_EXPRESSION 10 | numeric_expression: 11 | left: 12 | left: 13 | primary: 14 | type: VALUE 15 | value: 16 | primary: 17 | type: COLUMN_REFERENCE 18 | column_reference: a 19 | - type: NUMERIC_EXPRESSION 20 | numeric_expression: 21 | left: 22 | left: 23 | primary: 24 | type: VALUE 25 | value: 26 | primary: 27 | type: COLUMN_REFERENCE 28 | column_reference: b 29 | referenced_tables: 30 | - type: TABLE 31 | table: 32 | name: t1 33 | # INSERT SELECT with target columns and a search condition 34 | >INSERT INTO t1 (t1_a, t1_b) SELECT a, b FROM t1 WHERE c < 3 35 | statements: 36 | - type: INSERT 37 | insert_statement: 38 | table_name: t1 39 | columns: 40 | - t1_a 41 | - t1_b 42 | query: 43 | selected_columns: 44 | - type: NUMERIC_EXPRESSION 45 | numeric_expression: 46 | left: 47 | left: 48 | primary: 49 | type: VALUE 50 | value: 51 | primary: 52 | type: COLUMN_REFERENCE 53 | column_reference: a 54 | - type: NUMERIC_EXPRESSION 55 | numeric_expression: 56 | left: 57 | left: 58 | primary: 59 | type: VALUE 60 | value: 61 | primary: 62 | type: COLUMN_REFERENCE 63 | column_reference: b 64 | referenced_tables: 65 | - type: TABLE 66 | table: 67 | name: t1 68 | where: 69 | terms: 70 | - factor: 71 | predicate: 72 | type: COMPARISON 73 | comparison_predicate: 74 | op: LESS_THAN 75 | left: 76 | type: ELEMENT 77 | element: 78 | type: VALUE_EXPRESSION 79 | value_expression: 80 | type: NUMERIC_EXPRESSION 81 | numeric_expression: 82 | left: 83 | left: 84 | primary: 85 | type: VALUE 86 | value: 87 | primary: 88 | type: COLUMN_REFERENCE 89 | column_reference: c 90 | right: 91 | type: ELEMENT 92 | element: 93 | type: VALUE_EXPRESSION 94 | value_expression: 95 | type: NUMERIC_EXPRESSION 96 | numeric_expression: 97 | left: 98 | left: 99 | primary: 100 | type: VALUE 101 | value: 102 | primary: 103 | type: UNSIGNED_VALUE_SPECIFICATION 104 | unsigned_value_specification: literal[3] 105 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/insert-values.test: -------------------------------------------------------------------------------- 1 | >INSERT INTO t1 DEFAULT VALUES 2 | statements: 3 | - type: INSERT 4 | insert_statement: 5 | table_name: t1 6 | default_values: true 7 | >INSERT INTO t1 (a, b) VALUES (1, 2) 8 | statements: 9 | - type: INSERT 10 | insert_statement: 11 | table_name: t1 12 | columns: 13 | - a 14 | - b 15 | query: 16 | values: 17 | - type: LIST 18 | elements: 19 | - type: VALUE_EXPRESSION 20 | value_expression: 21 | type: NUMERIC_EXPRESSION 22 | numeric_expression: 23 | left: 24 | left: 25 | primary: 26 | type: VALUE 27 | value: 28 | primary: 29 | type: UNSIGNED_VALUE_SPECIFICATION 30 | unsigned_value_specification: literal[1] 31 | - type: VALUE_EXPRESSION 32 | value_expression: 33 | type: NUMERIC_EXPRESSION 34 | numeric_expression: 35 | left: 36 | left: 37 | primary: 38 | type: VALUE 39 | value: 40 | primary: 41 | type: UNSIGNED_VALUE_SPECIFICATION 42 | unsigned_value_specification: literal[2] 43 | # INSERT INTO with a default columns list 44 | >INSERT INTO t1 VALUES (1, 2) 45 | statements: 46 | - type: INSERT 47 | insert_statement: 48 | table_name: t1 49 | query: 50 | values: 51 | - type: LIST 52 | elements: 53 | - type: VALUE_EXPRESSION 54 | value_expression: 55 | type: NUMERIC_EXPRESSION 56 | numeric_expression: 57 | left: 58 | left: 59 | primary: 60 | type: VALUE 61 | value: 62 | primary: 63 | type: UNSIGNED_VALUE_SPECIFICATION 64 | unsigned_value_specification: literal[1] 65 | - type: VALUE_EXPRESSION 66 | value_expression: 67 | type: NUMERIC_EXPRESSION 68 | numeric_expression: 69 | left: 70 | left: 71 | primary: 72 | type: VALUE 73 | value: 74 | primary: 75 | type: UNSIGNED_VALUE_SPECIFICATION 76 | unsigned_value_specification: literal[2] 77 | # INSERT INTO using a character values expression 78 | # >INSERT INTO t1 VALUES ('a' COLLATE utf8bin) 79 | # statements: 80 | # - type: INSERT 81 | # insert_statement: 82 | # table_name: t1 83 | # query: 84 | # values: 85 | # - row_value_constructor: 86 | # type: LIST 87 | # elements: 88 | # - type: VALUE_EXPRESSION 89 | # value_expression: 90 | # type: STRING_EXPRESSION 91 | # character_expression: 92 | # factors: 93 | # - primary: 94 | # value: literal['a'] 95 | # collation: utf8bin 96 | # INSERT INTO using datetime value expressions 97 | >INSERT INTO t1 (create_date, my_date) VALUES (CURRENT_DATE, '2001-01-01' AT TIME ZONE 'UTC') 98 | statements: 99 | - type: INSERT 100 | insert_statement: 101 | table_name: t1 102 | columns: 103 | - create_date 104 | - my_date 105 | query: 106 | values: 107 | - type: LIST 108 | elements: 109 | - type: VALUE_EXPRESSION 110 | value_expression: 111 | type: DATETIME_EXPRESSION 112 | datetime_expression: 113 | left: 114 | factor: 115 | time_zone: LOCAL 116 | primary: 117 | type: FUNCTION 118 | function: current-date[] 119 | - type: VALUE_EXPRESSION 120 | value_expression: 121 | type: DATETIME_EXPRESSION 122 | datetime_expression: 123 | left: 124 | factor: 125 | time_zone: 'UTC' 126 | primary: 127 | type: VALUE 128 | value: 129 | primary: 130 | type: UNSIGNED_VALUE_SPECIFICATION 131 | unsigned_value_specification: literal['2001-01-01'] 132 | # INSERT INTO using interval value expressions 133 | # >INSERT INTO t1 (num_seconds) VALUES ('2001-01-01' DAY TO SECOND) 134 | # statements: 135 | # - type: INSERT 136 | # insert_statement: 137 | # table_name: t1 138 | # columns: 139 | # - num_seconds 140 | # query: 141 | # values: 142 | # - row_value_constructor: 143 | # type: LIST 144 | # elements: 145 | # - type: VALUE_EXPRESSION 146 | # value_expression: 147 | # type: INTERVAL_EXPRESSION 148 | # interval_expression: 149 | # left: 150 | # term: 151 | # left: 152 | # factor: 153 | # primary: 154 | # value: literal['2001-01-01'] 155 | # qualifier: 156 | # start: 157 | # interval: DAY 158 | # end: 159 | # interval: SECOND 160 | # INSERT INTO using numeric value expressions 161 | # >INSERT INTO t1 (num_seconds) VALUES (1 + (2 * 3)) 162 | # statements: 163 | # - type: INSERT 164 | # insert_statement: 165 | # table_name: t1 166 | # columns: 167 | # - num_seconds 168 | # query: 169 | # values: 170 | # - row_value_constructor: 171 | # type: LIST 172 | # elements: 173 | # - type: VALUE_EXPRESSION 174 | # value_expression: 175 | # type: NUMERIC_EXPRESSION 176 | # numeric_expression: 177 | # left: 178 | # term: 179 | # left: 180 | # factor: 181 | # primary: 182 | # type: VALUE 183 | # value: literal[1] 184 | # op: ADD 185 | # right: 186 | # term: 187 | # left: 188 | # factor: 189 | # primary: 190 | # type: VALUE 191 | # value: (numeric-expression[literal[2] * literal[3]]) 192 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/table-references.test: -------------------------------------------------------------------------------- 1 | # Normal table with no alias 2 | >SELECT * FROM t1 3 | statements: 4 | - type: SELECT 5 | select_statement: 6 | query: 7 | selected_columns: 8 | - asterisk: true 9 | referenced_tables: 10 | - type: TABLE 11 | table: 12 | name: t1 13 | # Normal table with an alias using AS keyword 14 | >SELECT * FROM t1 AS t1_alias 15 | statements: 16 | - type: SELECT 17 | select_statement: 18 | query: 19 | selected_columns: 20 | - asterisk: true 21 | referenced_tables: 22 | - type: TABLE 23 | table: 24 | name: t1 25 | alias: t1_alias 26 | # Normal table with an alias NOT using AS keyword 27 | >SELECT * FROM t1 t1_alias 28 | statements: 29 | - type: SELECT 30 | select_statement: 31 | query: 32 | selected_columns: 33 | - asterisk: true 34 | referenced_tables: 35 | - type: TABLE 36 | table: 37 | name: t1 38 | alias: t1_alias 39 | # Derived table with name using AS keyword 40 | >SELECT * FROM (SELECT a, b FROM t1) AS t 41 | statements: 42 | - type: SELECT 43 | select_statement: 44 | query: 45 | selected_columns: 46 | - asterisk: true 47 | referenced_tables: 48 | - type: DERIVED_TABLE 49 | derived_table: 50 | name: t 51 | query: 52 | selected_columns: 53 | - type: NUMERIC_EXPRESSION 54 | numeric_expression: 55 | left: 56 | left: 57 | primary: 58 | type: VALUE 59 | value: 60 | primary: 61 | type: COLUMN_REFERENCE 62 | column_reference: a 63 | - type: NUMERIC_EXPRESSION 64 | numeric_expression: 65 | left: 66 | left: 67 | primary: 68 | type: VALUE 69 | value: 70 | primary: 71 | type: COLUMN_REFERENCE 72 | column_reference: b 73 | referenced_tables: 74 | - type: TABLE 75 | table: 76 | name: t1 77 | -------------------------------------------------------------------------------- /tests/grammar/ansi-92/update.test: -------------------------------------------------------------------------------- 1 | # UPDATE with no WHERE condition 2 | >UPDATE t1 SET a = 1 3 | statements: 4 | - type: UPDATE 5 | update_statement: 6 | table_name: t1 7 | set_columns: 8 | a: literal[1] 9 | # UPDATE with simple WHERE condition with equality comparison 10 | >UPDATE t1 SET a = 1 WHERE b = 2 11 | statements: 12 | - type: UPDATE 13 | update_statement: 14 | table_name: t1 15 | set_columns: 16 | a: literal[1] 17 | where: 18 | terms: 19 | - factor: 20 | predicate: 21 | type: COMPARISON 22 | comparison_predicate: 23 | op: EQUAL 24 | left: 25 | type: ELEMENT 26 | element: 27 | type: VALUE_EXPRESSION 28 | value_expression: 29 | type: NUMERIC_EXPRESSION 30 | numeric_expression: 31 | left: 32 | left: 33 | primary: 34 | type: VALUE 35 | value: 36 | primary: 37 | type: COLUMN_REFERENCE 38 | column_reference: b 39 | right: 40 | type: ELEMENT 41 | element: 42 | type: VALUE_EXPRESSION 43 | value_expression: 44 | type: NUMERIC_EXPRESSION 45 | numeric_expression: 46 | left: 47 | left: 48 | primary: 49 | type: VALUE 50 | value: 51 | primary: 52 | type: UNSIGNED_VALUE_SPECIFICATION 53 | unsigned_value_specification: literal[2] 54 | -------------------------------------------------------------------------------- /tests/grammar/runner.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | import argparse 4 | import difflib 5 | import os 6 | import re 7 | import subprocess 8 | import sys 9 | 10 | TEST_DIR = os.path.dirname(os.path.realpath(__file__)) 11 | RESULT_OK = 0 12 | RESULT_TEST_ERROR = 1 13 | RESULT_TEST_FAILURE = 1 14 | SQLTOASTER_BINARY = os.path.join(TEST_DIR, '..', '..', '_build', 'sqltoaster', 15 | 'sqltoaster') 16 | 17 | 18 | def parse_options(): 19 | """ 20 | Parse any command line options and environs defaults and return an options 21 | object. 22 | """ 23 | p = argparse.ArgumentParser(description="Run SQL grammar tests.") 24 | p.add_argument("command", default="run", choices=['run', 'list']) 25 | p.add_argument("--regex", "-r", default=None, 26 | help="(optional) regex pattern to filter tests to run") 27 | p.add_argument("--dialect", choices=get_dialects(), default=None, 28 | help="(optional) Only run SQL grammar tests for the " 29 | "dialect specified. By default, all dialect tests " 30 | "are run") 31 | 32 | return p.parse_args() 33 | 34 | 35 | def get_dialects(): 36 | """Returns a set of string dialect names for the supported grammar 37 | tests.""" 38 | dialects = set() 39 | for fname in os.listdir(TEST_DIR): 40 | if os.path.isdir(os.path.join(TEST_DIR, fname)): 41 | dialects.add(fname) 42 | return dialects 43 | 44 | 45 | def get_test_names(args): 46 | """Returns the list of filtered test names""" 47 | if args.dialect is not None: 48 | dialects = set(args.dialect) 49 | else: 50 | dialects = get_dialects() 51 | name_regex = None 52 | if args.regex: 53 | try: 54 | name_regex = re.compile(args.regex) 55 | except Exception as err: 56 | sys.stderr.write("ERROR with regex: %s\n" % err) 57 | return [] 58 | test_names = [] 59 | for dialect in dialects: 60 | dpath = os.path.join(TEST_DIR, dialect) 61 | for fname in os.listdir(dpath): 62 | if fname.endswith(".test"): 63 | if name_regex: 64 | if not name_regex.search(fname): 65 | continue 66 | test_names.append("%s/%s" % (dialect, fname[:-5])) 67 | return sorted(test_names) 68 | 69 | 70 | def run_test(test_name): 71 | test_path = os.path.join(TEST_DIR, test_name + ".test") 72 | input_blocks = [] 73 | output_blocks = [] 74 | input_block = [] 75 | output_block = [] 76 | with open(test_path, 'rb') as tfile: 77 | line = tfile.readline().rstrip("\n") 78 | while True: 79 | if not line: 80 | break; 81 | if line.startswith("#"): 82 | line = tfile.readline().rstrip("\n") 83 | continue 84 | if line.startswith('>'): 85 | # Clear out previous output block... 86 | if output_block: 87 | output_blocks.append(output_block) 88 | output_block = [] 89 | input_block.append(line[1:]) 90 | else: 91 | # Clear out previous input block... 92 | if input_block: 93 | input_blocks.append(input_block) 94 | input_block = [] 95 | output_block.append(line) 96 | line = tfile.readline().rstrip("\n") 97 | if output_block: 98 | output_blocks.append(output_block) 99 | 100 | if len(input_blocks) != len(output_blocks): 101 | msg = ("Error in test file %s: expected same amount of input to " 102 | "output blocks but got %d input blocks and %d output blocks.") 103 | msg = msg % (test_name, len(input_blocks), len(output_blocks)) 104 | return RESULT_TEST_ERROR, msg 105 | for testno, iblock in enumerate(input_blocks): 106 | expected = output_blocks[testno] 107 | input_sql = "\n".join(iblock) 108 | cmd_args = [SQLTOASTER_BINARY, '--disable-timer', '--yaml', input_sql] 109 | try: 110 | actual = subprocess.check_output(cmd_args) 111 | except subprocess.CalledProcessError as err: 112 | msg = ("Failed to execute test number %d inside %s. Got: %s") 113 | msg = msg % (testno, test_name, err) 114 | return RESULT_TEST_ERROR, msg 115 | 116 | actual = actual.splitlines() 117 | 118 | if actual != expected: 119 | msg = "Test #%d\n" % testno 120 | msg += "---------------------------------------------\n" 121 | msg += "Input SQL:\n" 122 | msg += input_sql 123 | msg += "\n---------------------------------------------\n" 124 | msg += "expected != actual\n" 125 | diffs = difflib.ndiff(expected, actual) 126 | diffs = [d.strip("\n") for d in diffs] 127 | msg += "\n".join(diffs) 128 | return RESULT_TEST_FAILURE, msg 129 | 130 | return RESULT_OK, None 131 | 132 | 133 | def command_list(args): 134 | """Lists tests that would meet any (optional) regex or dialect filters.""" 135 | test_names = get_test_names(args) 136 | for tname in test_names: 137 | sys.stdout.write("%s\n" % tname) 138 | 139 | 140 | def command_run(args): 141 | """Runs tests that meet any (optional) regex or dialect filters.""" 142 | test_names = get_test_names(args) 143 | for tname in test_names: 144 | sys.stdout.write("Running %s ... " % tname) 145 | res, err = run_test(tname) 146 | if res == RESULT_OK: 147 | sys.stdout.write("OK\n") 148 | elif res == RESULT_TEST_ERROR: 149 | sys.stdout.write("Error: %s\n" % err) 150 | else: 151 | sys.stdout.write("FAIL\n") 152 | sys.stdout.write(err) 153 | 154 | 155 | COMMAND_CALLBACKS = { 156 | 'run': command_run, 157 | 'list': command_list, 158 | } 159 | 160 | 161 | if __name__ == "__main__": 162 | args = parse_options() 163 | COMMAND_CALLBACKS[args.command](args) 164 | --------------------------------------------------------------------------------