zsv 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +36 -0
- data/LICENSE +21 -0
- data/README.md +311 -0
- data/ext/zsv/common.h +34 -0
- data/ext/zsv/extconf.rb +137 -0
- data/ext/zsv/options.c +126 -0
- data/ext/zsv/options.h +31 -0
- data/ext/zsv/options_internal.h +8 -0
- data/ext/zsv/parser.c +300 -0
- data/ext/zsv/parser.h +62 -0
- data/ext/zsv/row.c +122 -0
- data/ext/zsv/row.h +39 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2db.c +756 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2json.c +381 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2tsv.c +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/help.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/license.c +39 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/register.c +104 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/thirdparty.c +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/unregister.c +1 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/version.c +14 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check/simdutf_wrapper.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check/utf8.c +116 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check.c +194 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli.c +796 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_const.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_export.h +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_ini.c +280 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_internal.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare.c +913 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare.h +23 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_added_column.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_internal.h +140 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_sort.c +91 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_unique_colname.c +81 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/count-pull.c +82 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/count.c +404 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/desc.c +569 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/echo.c +365 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/my_extension.c +366 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/mysheet_extension.c +341 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_template/YOUR_EXTENSION_zsvext.c +263 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.c +298 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.h +157 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/json_numeric.c +177 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.c +444 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.h +145 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/utils.c +110 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/include/memfile.h +15 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/src/memfile.c +64 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sglib/sglib.h +1955 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/simdutf/simdutf.h +6802 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.c +230517 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.h +12174 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_and_csv_vtab.c +2 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.c +142 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-zsv.c +485 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab.c +1015 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3ext.h +663 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/vtab_helper.c +85 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_common.h +75 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_gen.h +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_parse.h +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_tree.h +186 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_version.h +23 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_common.h +76 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_gen.h +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_parse.h +238 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_tree.h +186 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl.c +184 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.c +52 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.h +34 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.c +103 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.h +57 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_bytestack.h +69 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.c +220 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.h +34 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_gen.c +362 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.c +764 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.h +117 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.c +508 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.h +78 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_tree.c +505 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_version.c +7 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/json_value.h +59 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/yajl_helper.h +208 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper.c +795 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper_internal.h +28 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/flatten.c +851 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/jq.c +106 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/jq.h +6 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/mv.c +113 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/noop.c +90 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/overwrite.c +295 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/paste.c +175 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/pretty.c +693 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/prop.c +980 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/rm.c +131 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/fixed.c +130 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/internal.h +118 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.c +45 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/processing.c +107 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/rand.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/regex.c +61 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/search.c +14 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/selection.c +192 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/usage.c +72 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select-pull.c +812 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select.c +753 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/serialize.c +372 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/curses.h +15 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/cursor.c +119 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/errors.c +45 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.c +63 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.h +12 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/filter.c +166 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers.c +214 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers_internal.h +128 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/help.c +43 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.c +81 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.h +25 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.c +325 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.h +73 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/lexer.c +203 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/newline_handler.c +7 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/pivot.c +318 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.c +134 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.h +119 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/read-data.c +322 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.c +203 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet-sql.c +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet_internal.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sqlfilter.c +153 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/terminfo.c +32 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.c +312 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.h +29 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/ui_buffer.c +266 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/usage.c +9 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/utf8-width.c +60 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet.c +1007 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql.c +453 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.c +101 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/stack.c +393 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/arg.c +322 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/cache.c +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/cat.c +91 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.c +240 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.h +63 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/clock.c +57 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/db.c +148 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs-no-jq.c +2 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs.c +427 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_from_json.c +253 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_to_json.c +121 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dl.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/emcc/fs_api.c +159 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/err.c +24 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/file-mem.c +180 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/file.c +256 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.c +197 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/jq.c +400 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/json.c +120 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/mem.c +18 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/memmem.c +132 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/os.c +178 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite.c +258 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite_writer.c +246 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8-test.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.c +153 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.h +54 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/prop.c +267 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/signal.c +53 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/string.c +357 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dir_exists_longpath.c +83 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dl.c +33 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/fopen_longpath.c +184 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/foreach_dirent_longpath.c +292 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.c +259 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.h +13 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/mkdir_longpath.c +255 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/remove_longpath.c +96 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/writer.c +361 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command.h +40 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command_standalone.c +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_main.h +44 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/js/zsv_parser_api_dummy.c +3 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/parse_by_chunk.c +100 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/print_my_column.c +143 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/pull.c +89 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/simple.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/fuzz/fuzz.c +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/api.h +336 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/common.h +361 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation.h +62 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation_private.h +113 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/sheet.h +73 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext.h +329 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/arg.h +90 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/cache.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/clock.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/compiler.h +58 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/db.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dirs.h +147 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dl.h +22 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/emcc/fs_api.h +28 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/err.h +22 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file-mem.h +17 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file.h +99 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/jq.h +65 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/json.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/mem.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/memmem.h +13 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/os.h +54 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite.h +71 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite_writer.h +53 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/prop.h +107 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/signal.h +18 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/sql.h +11 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/string.h +148 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/utf8.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/win/dl.h +25 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/writer.h +101 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/zsv_export.h +33 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv.h +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/vector_delim.c +60 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv.c +484 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_internal.c +731 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_delim.c +285 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_fixed.c +88 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_strencode.c +51 -0
- data/ext/zsv/zsv_ext.c +343 -0
- data/lib/zsv/version.rb +5 -0
- data/lib/zsv.rb +81 -0
- metadata +340 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#include <pthread.h>
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* see sqlite3_csv_vtab-mem.h for background info
|
|
5
|
+
*/
|
|
6
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
7
|
+
#include <process.h>
|
|
8
|
+
#else
|
|
9
|
+
#include <unistd.h>
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
struct sqlite3_zsv_data {
|
|
13
|
+
struct sqlite3_zsv_data *next;
|
|
14
|
+
pid_t pid;
|
|
15
|
+
char *filename;
|
|
16
|
+
struct zsv_opts opts;
|
|
17
|
+
struct zsv_prop_handler custom_prop_handler;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
pthread_mutex_t sqlite3_zsv_data_mutex;
|
|
21
|
+
struct sqlite3_zsv_data *sqlite3_zsv_data_g = NULL;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Our shared memory structure should be locked for read/write
|
|
25
|
+
*/
|
|
26
|
+
static int sqlite3_zsv_data_lock(void) {
|
|
27
|
+
#ifndef NO_THREADING
|
|
28
|
+
pthread_mutex_lock(&sqlite3_zsv_data_mutex);
|
|
29
|
+
#endif
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static int sqlite3_zsv_data_unlock(void) {
|
|
34
|
+
#ifndef NO_THREADING
|
|
35
|
+
pthread_mutex_unlock(&sqlite3_zsv_data_mutex);
|
|
36
|
+
#endif
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static void sqlite3_zsv_data_delete(struct sqlite3_zsv_data *e) {
|
|
41
|
+
if (e) {
|
|
42
|
+
free(e->filename);
|
|
43
|
+
}
|
|
44
|
+
free(e);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
void sqlite3_zsv_list_delete(void **list) {
|
|
48
|
+
for (struct sqlite3_zsv_data *next, *e = *list; e; e = next) {
|
|
49
|
+
next = e->next;
|
|
50
|
+
sqlite3_zsv_data_delete(e);
|
|
51
|
+
}
|
|
52
|
+
#ifndef NO_THREADING
|
|
53
|
+
pthread_mutex_destroy(&sqlite3_zsv_data_mutex);
|
|
54
|
+
#endif
|
|
55
|
+
*list = NULL;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static struct sqlite3_zsv_data *sqlite3_zsv_data_new(const char *filename, struct zsv_opts *opts,
|
|
59
|
+
struct zsv_prop_handler *custom_prop_handler) {
|
|
60
|
+
if (!filename)
|
|
61
|
+
return NULL;
|
|
62
|
+
struct sqlite3_zsv_data *e = calloc(1, sizeof(*e));
|
|
63
|
+
if (e) {
|
|
64
|
+
e->pid = getpid();
|
|
65
|
+
e->filename = strdup(filename);
|
|
66
|
+
if (opts)
|
|
67
|
+
e->opts = *opts;
|
|
68
|
+
if (custom_prop_handler)
|
|
69
|
+
e->custom_prop_handler = *custom_prop_handler;
|
|
70
|
+
if (e->filename)
|
|
71
|
+
return e;
|
|
72
|
+
}
|
|
73
|
+
sqlite3_zsv_data_delete(e);
|
|
74
|
+
return NULL;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
int sqlite3_zsv_list_add(const char *filename, struct zsv_opts *opts, struct zsv_prop_handler *custom_prop_handler) {
|
|
78
|
+
struct sqlite3_zsv_data **list = &sqlite3_zsv_data_g;
|
|
79
|
+
struct sqlite3_zsv_data *e = sqlite3_zsv_data_new(filename, opts, custom_prop_handler);
|
|
80
|
+
if (e) {
|
|
81
|
+
struct sqlite3_zsv_data **next;
|
|
82
|
+
if (sqlite3_zsv_data_lock()) {
|
|
83
|
+
sqlite3_zsv_data_delete(e);
|
|
84
|
+
return -1;
|
|
85
|
+
} else {
|
|
86
|
+
for (next = list; *next; next = &(*next)->next)
|
|
87
|
+
;
|
|
88
|
+
*next = e;
|
|
89
|
+
sqlite3_zsv_data_unlock();
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return ENOMEM;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static int sqlite3_zsv_data_cmp(struct sqlite3_zsv_data *x, const char *filename, pid_t pid) {
|
|
97
|
+
return strcmp(x->filename, filename) && x->pid == pid;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
struct sqlite3_zsv_data *sqlite3_zsv_data_find(const char *filename) {
|
|
101
|
+
struct sqlite3_zsv_data *list = sqlite3_zsv_data_g;
|
|
102
|
+
struct sqlite3_zsv_data *found = NULL;
|
|
103
|
+
pid_t pid = getpid();
|
|
104
|
+
if (!sqlite3_zsv_data_lock()) {
|
|
105
|
+
for (struct sqlite3_zsv_data *e = list; e && !found; e = e->next) {
|
|
106
|
+
if (!sqlite3_zsv_data_cmp(e, filename, pid))
|
|
107
|
+
found = e;
|
|
108
|
+
}
|
|
109
|
+
if (sqlite3_zsv_data_unlock())
|
|
110
|
+
fprintf(stderr, "Error unlocking sqlite3-csv-zsv shared mem lock\n");
|
|
111
|
+
}
|
|
112
|
+
return found;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
int sqlite3_zsv_list_remove(const char *filename) {
|
|
116
|
+
if (!filename)
|
|
117
|
+
return 0;
|
|
118
|
+
struct sqlite3_zsv_data **list = &sqlite3_zsv_data_g;
|
|
119
|
+
struct sqlite3_zsv_data *found = NULL;
|
|
120
|
+
pid_t pid = getpid();
|
|
121
|
+
if (*list) {
|
|
122
|
+
if (!sqlite3_zsv_data_cmp(*list, filename, pid)) {
|
|
123
|
+
// found a match at the head of list
|
|
124
|
+
found = *list;
|
|
125
|
+
*list = found->next;
|
|
126
|
+
} else {
|
|
127
|
+
// look for a match somewhere after the first element
|
|
128
|
+
for (struct sqlite3_zsv_data *prior = *list; prior->next != NULL; prior = prior->next) {
|
|
129
|
+
if (!sqlite3_zsv_data_cmp(prior->next, filename, pid)) {
|
|
130
|
+
found = prior->next;
|
|
131
|
+
prior->next = prior->next->next;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (found) {
|
|
138
|
+
sqlite3_zsv_data_delete(found);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
return ENOENT; // not found
|
|
142
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#ifndef SQLITE3_CSV_VTAB_ZSV_H
|
|
2
|
+
#define SQLITE3_CSV_VTAB_ZSV_H
|
|
3
|
+
|
|
4
|
+
#include <zsv.h>
|
|
5
|
+
#include <zsv/utils/prop.h>
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* when sqlite3 opens a CSV file using ZSV, it needs a way to know
|
|
9
|
+
* what options to open with (such as user-specified delimiter, header offset
|
|
10
|
+
* or span, etc
|
|
11
|
+
*
|
|
12
|
+
* In particular, it needs access to:
|
|
13
|
+
* - zsv options (struct zsv_opts)
|
|
14
|
+
* - custom property handler (struct zsv_prop_handler *)
|
|
15
|
+
* - options used (const char *) [but this can be passed via connection string]
|
|
16
|
+
*
|
|
17
|
+
* Some ways to pass this info are:
|
|
18
|
+
* - Embed it in the text of the URI passed to the module's xConnect function.
|
|
19
|
+
* This is not practical because we need to pass pointers
|
|
20
|
+
* - Use a single global variable that can hold only one set of data at a time.
|
|
21
|
+
* This was the old approach, via `zsv_set_default_opts` etc, which has the
|
|
22
|
+
* usual drawbacks of using a single global variable structure
|
|
23
|
+
* - Use a shared memory structure that can support multiple sets of data
|
|
24
|
+
* That is the approach implemented here. Data is identified by the related
|
|
25
|
+
* filename and caller pid
|
|
26
|
+
*
|
|
27
|
+
* sqlite3_create_module_v2 is passed the shared memory root pointer,
|
|
28
|
+
* but it's not really needed because there is no way for it to be
|
|
29
|
+
* dynamic so it always has to point to the single global location
|
|
30
|
+
*
|
|
31
|
+
* Prior to calling xConnect, the caller should save data for the related
|
|
32
|
+
* file via `sqlite3_zsv_data_add()`; xConnect then does a lookup to
|
|
33
|
+
* locate and use the saved data
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
struct sqlite3_zsv_data;
|
|
37
|
+
|
|
38
|
+
void sqlite3_zsv_list_delete(struct sqlite3_zsv_data **list);
|
|
39
|
+
|
|
40
|
+
int sqlite3_zsv_list_add(const char *filename, struct zsv_opts *opts, struct zsv_prop_handler *custom_prop_handler);
|
|
41
|
+
|
|
42
|
+
struct sqlite3_zsv_data *sqlite3_csv_vtab_zsv_find(const char *filename);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Remove from list. Return 0 on success, non-zero on error
|
|
46
|
+
*/
|
|
47
|
+
int sqlite3_zsv_list_remove(const char *filename);
|
|
48
|
+
|
|
49
|
+
#endif
|
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
/* clang-format off */
|
|
2
|
+
/*
|
|
3
|
+
* This file has been modified from its original form, in order to use the ZSV csv parser
|
|
4
|
+
* The preamble / disclaimer to the original file is included below
|
|
5
|
+
* The modifications to this file are subject to the same license (MIT) as the ZSV parser
|
|
6
|
+
* as described at https://github.com/liquidaty/zsv/blob/main/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
** 2016-05-28
|
|
11
|
+
**
|
|
12
|
+
** The author disclaims copyright to this source code. In place of
|
|
13
|
+
** a legal notice, here is a blessing:
|
|
14
|
+
**
|
|
15
|
+
** May you do good and not evil.
|
|
16
|
+
** May you find forgiveness for yourself and forgive others.
|
|
17
|
+
** May you share freely, never taking more than you give.
|
|
18
|
+
**
|
|
19
|
+
******************************************************************************
|
|
20
|
+
**
|
|
21
|
+
** This file contains the implementation of an SQLite virtual table for
|
|
22
|
+
** reading CSV files
|
|
23
|
+
**
|
|
24
|
+
** Usage:
|
|
25
|
+
**
|
|
26
|
+
** .load ./csv
|
|
27
|
+
** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);
|
|
28
|
+
** SELECT * FROM csv;
|
|
29
|
+
**
|
|
30
|
+
** The input file is assumed to have a single header row, followed by data rows
|
|
31
|
+
** Instead of specifying a file, the text of the CSV can be loaded using
|
|
32
|
+
** the data= parameter.
|
|
33
|
+
**
|
|
34
|
+
** If the columns=N parameter is supplied, then the CSV file is assumed to have
|
|
35
|
+
** N columns. If both the columns= and schema= parameters are omitted, then
|
|
36
|
+
** the number and names of the columns is determined by the first line of
|
|
37
|
+
** the CSV input.
|
|
38
|
+
**
|
|
39
|
+
** Some extra debugging features (used for testing virtual tables) are available
|
|
40
|
+
** if this module is compiled with -DSQLITE_TEST.
|
|
41
|
+
*/
|
|
42
|
+
#include "sqlite3.h"
|
|
43
|
+
#include "sqlite3ext.h"
|
|
44
|
+
SQLITE_EXTENSION_INIT1
|
|
45
|
+
#include <string.h>
|
|
46
|
+
#include <stdlib.h>
|
|
47
|
+
#include <assert.h>
|
|
48
|
+
#include <stdarg.h>
|
|
49
|
+
#include <ctype.h>
|
|
50
|
+
#include <stdio.h>
|
|
51
|
+
#include <zsv.h>
|
|
52
|
+
#include <zsv/utils/string.h>
|
|
53
|
+
#include <zsv/utils/arg.h>
|
|
54
|
+
#include <zsv/utils/prop.h>
|
|
55
|
+
#include "sqlite3_csv_vtab-mem.c"
|
|
56
|
+
|
|
57
|
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
** A macro to hint to the compiler that a function should not be
|
|
61
|
+
** inlined.
|
|
62
|
+
*/
|
|
63
|
+
#if defined(__GNUC__)
|
|
64
|
+
# define CSV_NOINLINE __attribute__((noinline))
|
|
65
|
+
#elif defined(_MSC_VER) && _MSC_VER>=1310
|
|
66
|
+
# define CSV_NOINLINE __declspec(noinline)
|
|
67
|
+
#else
|
|
68
|
+
# define CSV_NOINLINE
|
|
69
|
+
#endif
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/* Max size of the error message in a CsvReader */
|
|
73
|
+
#define CSV_MXERR 200
|
|
74
|
+
|
|
75
|
+
/* Size of the CsvReader input buffer */
|
|
76
|
+
#define CSV_INBUFSZ 1024
|
|
77
|
+
|
|
78
|
+
/* Forward references to the various virtual table methods implemented
|
|
79
|
+
** in this file. */
|
|
80
|
+
static int zsvtabCreate(sqlite3*, void*, int, const char*const*,
|
|
81
|
+
sqlite3_vtab**,char**);
|
|
82
|
+
static int zsvtabConnect(sqlite3*, void*, int, const char*const*,
|
|
83
|
+
sqlite3_vtab**,char**);
|
|
84
|
+
static int zsvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
|
|
85
|
+
static int zsvtabDisconnect(sqlite3_vtab*);
|
|
86
|
+
static int zsvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
|
|
87
|
+
static int zsvtabClose(sqlite3_vtab_cursor*);
|
|
88
|
+
static int zsvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
|
|
89
|
+
int argc, sqlite3_value **argv);
|
|
90
|
+
static int zsvtabNext(sqlite3_vtab_cursor*);
|
|
91
|
+
static int zsvtabEof(sqlite3_vtab_cursor*);
|
|
92
|
+
static int zsvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
|
|
93
|
+
static int zsvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
|
|
94
|
+
|
|
95
|
+
/* An instance of the CSV virtual table */
|
|
96
|
+
typedef struct zsvTable {
|
|
97
|
+
sqlite3_vtab base; /* Base class. Must be first */
|
|
98
|
+
char *zFilename; /* Name of the CSV file */
|
|
99
|
+
struct zsv_opts parser_opts;
|
|
100
|
+
struct zsv_prop_handler custom_prop_handler;
|
|
101
|
+
enum zsv_status parser_status;
|
|
102
|
+
zsv_parser parser;
|
|
103
|
+
sqlite_int64 rowCount;
|
|
104
|
+
} zsvTable;
|
|
105
|
+
|
|
106
|
+
struct zsvTable *zsvTable_new(const char *filename) {
|
|
107
|
+
struct zsvTable *z = sqlite3_malloc(sizeof(*z));
|
|
108
|
+
if(z) {
|
|
109
|
+
memset(z, 0, sizeof(*z));
|
|
110
|
+
struct sqlite3_zsv_data *d = sqlite3_zsv_data_find(filename);
|
|
111
|
+
if(d) {
|
|
112
|
+
z->parser_opts = d->opts; // zsv_get_default_opts();
|
|
113
|
+
z->custom_prop_handler = d->custom_prop_handler; // zsv_get_default_custom_prop_handler();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return z;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Allowed values for tstFlags */
|
|
120
|
+
#define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/
|
|
121
|
+
|
|
122
|
+
/* A cursor for the CSV virtual table */
|
|
123
|
+
typedef struct zsvCursor {
|
|
124
|
+
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
|
125
|
+
} zsvCursor;
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
** The xConnect and xCreate methods do the same thing, but they must be
|
|
129
|
+
** different so that the virtual table is not an eponymous virtual table.
|
|
130
|
+
o*/
|
|
131
|
+
static int zsvtabCreate(
|
|
132
|
+
sqlite3 *db,
|
|
133
|
+
void *pAux,
|
|
134
|
+
int argc, const char *const*argv,
|
|
135
|
+
sqlite3_vtab **ppVtab,
|
|
136
|
+
char **pzErr
|
|
137
|
+
){
|
|
138
|
+
return zsvtabConnect(db, pAux, argc, argv, ppVtab, pzErr);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static void zsvTable_free(struct zsvTable *z) {
|
|
142
|
+
if(z->parser)
|
|
143
|
+
zsv_delete(z->parser);
|
|
144
|
+
z->parser = NULL;
|
|
145
|
+
z->rowCount = 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static void zsvTable_delete(struct zsvTable *z) {
|
|
149
|
+
if(z) {
|
|
150
|
+
zsvTable_free(z);
|
|
151
|
+
sqlite3_free(z->zFilename);
|
|
152
|
+
sqlite3_free(z);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#include "vtab_helper.c"
|
|
157
|
+
|
|
158
|
+
#define BLANK_COLUMN_NAME_PREFIX "Blank_Column"
|
|
159
|
+
unsigned blank_column_name_count = 0;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Parameters:
|
|
163
|
+
* filename=FILENAME Name of file containing CSV content
|
|
164
|
+
*
|
|
165
|
+
* The number of columns in the first row of the input file determines the
|
|
166
|
+
* column names and column count
|
|
167
|
+
*/
|
|
168
|
+
static int zsvtabConnect(
|
|
169
|
+
sqlite3 *db,
|
|
170
|
+
void *_pAux,
|
|
171
|
+
int argc, const char *const*argv,
|
|
172
|
+
sqlite3_vtab **ppVtab,
|
|
173
|
+
char **pzErr
|
|
174
|
+
){
|
|
175
|
+
(void)(_pAux);
|
|
176
|
+
zsvTable pTmp = { 0 };
|
|
177
|
+
int rc = SQLITE_OK; /* Result code from this routine */
|
|
178
|
+
#define ZSVTABCONNECT_PARAM_MAX 2
|
|
179
|
+
static const char *azParam[ZSVTABCONNECT_PARAM_MAX] = {
|
|
180
|
+
"filename"
|
|
181
|
+
};
|
|
182
|
+
char *azPValue[ZSVTABCONNECT_PARAM_MAX]; /* Parameter values */
|
|
183
|
+
memset(azPValue, 0, sizeof(azPValue));
|
|
184
|
+
# define CSV_FILENAME (azPValue[0])
|
|
185
|
+
|
|
186
|
+
char *schema = NULL;
|
|
187
|
+
zsvTable *pNew = NULL;
|
|
188
|
+
|
|
189
|
+
char *errmsg = NULL;
|
|
190
|
+
// set parameters
|
|
191
|
+
for(int i=3; i<argc; i++){
|
|
192
|
+
const char *z = argv[i];
|
|
193
|
+
const char *zValue;
|
|
194
|
+
size_t j;
|
|
195
|
+
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
|
|
196
|
+
if(csv_string_parameter(&errmsg, azParam[j], z, &azPValue[j]) ) break;
|
|
197
|
+
}
|
|
198
|
+
if( j<sizeof(azParam)/sizeof(azParam[0]) ){
|
|
199
|
+
if( errmsg ) goto zsvtab_connect_error;
|
|
200
|
+
} else {
|
|
201
|
+
asprintf(&errmsg, "bad parameter: '%s'", z);
|
|
202
|
+
goto zsvtab_connect_error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if(!CSV_FILENAME) {
|
|
207
|
+
asprintf(&errmsg, "No csv filename provided");
|
|
208
|
+
goto zsvtab_connect_error;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
pNew = zsvTable_new(CSV_FILENAME);
|
|
212
|
+
if(!pNew)
|
|
213
|
+
goto zsvtab_connect_oom;
|
|
214
|
+
if(pTmp.parser_opts.max_columns)
|
|
215
|
+
pNew->parser_opts.max_columns = pTmp.parser_opts.max_columns;
|
|
216
|
+
else if(!pNew->parser_opts.max_columns)
|
|
217
|
+
pNew->parser_opts.max_columns = 2000; /* default max columns */
|
|
218
|
+
|
|
219
|
+
if(!(pNew->parser_opts.stream = fopen(CSV_FILENAME, "rb"))) {
|
|
220
|
+
asprintf(&errmsg, "Unable to open for reading: %s", CSV_FILENAME);
|
|
221
|
+
goto zsvtab_connect_error;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pNew->zFilename = CSV_FILENAME;
|
|
225
|
+
CSV_FILENAME = 0; // in use; don't free
|
|
226
|
+
if(zsv_new_with_properties(&pNew->parser_opts, &pNew->custom_prop_handler, pNew->zFilename,
|
|
227
|
+
&pNew->parser) != zsv_status_ok)
|
|
228
|
+
goto zsvtab_connect_error;
|
|
229
|
+
|
|
230
|
+
if((pNew->parser_status = zsv_next_row(pNew->parser)) != zsv_status_row) {
|
|
231
|
+
asprintf(&errmsg, "Could not fetch header row: %s", zsv_parse_status_desc(pNew->parser_status));
|
|
232
|
+
goto zsvtab_connect_error;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
*ppVtab = (sqlite3_vtab*)pNew;
|
|
236
|
+
|
|
237
|
+
// generate the CREATE TABLE statement
|
|
238
|
+
sqlite3_str *pStr = sqlite3_str_new(0);
|
|
239
|
+
sqlite3_str_appendf(pStr, "CREATE TABLE x(");
|
|
240
|
+
|
|
241
|
+
// for each column, add a spec to CREATE TABLE
|
|
242
|
+
for(size_t i = 0, j = zsv_cell_count(pNew->parser); i < j; i++) {
|
|
243
|
+
struct zsv_cell cell = zsv_get_cell(pNew->parser, i);
|
|
244
|
+
size_t len = cell.len;
|
|
245
|
+
unsigned char *utf8_value = (unsigned char *)zsv_strtrim(cell.str, &len);
|
|
246
|
+
|
|
247
|
+
if(!len) {
|
|
248
|
+
if(blank_column_name_count++)
|
|
249
|
+
sqlite3_str_appendf(pStr, "%s\"%s_%u\" TEXT", i > 0 ? "," : "", BLANK_COLUMN_NAME_PREFIX, blank_column_name_count - 1);
|
|
250
|
+
else
|
|
251
|
+
sqlite3_str_appendf(pStr, "%s\"%s\" TEXT", i > 0 ? "," : "", BLANK_COLUMN_NAME_PREFIX);
|
|
252
|
+
} else
|
|
253
|
+
sqlite3_str_appendf(pStr, "%s\"%.*w\" TEXT", i > 0 ? "," : "", len, utf8_value);
|
|
254
|
+
// to do: deal with duplicate column names
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
sqlite3_str_appendf(pStr, ")");
|
|
258
|
+
schema = sqlite3_str_finish(pStr);
|
|
259
|
+
if(!schema)
|
|
260
|
+
goto zsvtab_connect_oom;
|
|
261
|
+
|
|
262
|
+
// advance cursor to first data row
|
|
263
|
+
pNew->parser_status = zsv_next_row(pNew->parser);
|
|
264
|
+
pNew->rowCount = 1;
|
|
265
|
+
|
|
266
|
+
#ifdef SQLITE_TEST
|
|
267
|
+
pNew->tstFlags = tstFlags;
|
|
268
|
+
#endif
|
|
269
|
+
|
|
270
|
+
rc = sqlite3_declare_vtab(db, schema);
|
|
271
|
+
if( rc ){
|
|
272
|
+
asprintf(&errmsg, "bad schema: '%s' - %s", schema, sqlite3_errmsg(db));
|
|
273
|
+
goto zsvtab_connect_error;
|
|
274
|
+
}
|
|
275
|
+
for(unsigned int i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++) {
|
|
276
|
+
sqlite3_free(azPValue[i]);
|
|
277
|
+
}
|
|
278
|
+
sqlite3_free(schema);
|
|
279
|
+
|
|
280
|
+
/* Rationale for DIRECTONLY:
|
|
281
|
+
** An attacker who controls a database schema could use this vtab
|
|
282
|
+
** to exfiltrate sensitive data from other files in the filesystem.
|
|
283
|
+
** And, recommended practice is to put all CSV virtual tables in the
|
|
284
|
+
** TEMP namespace, so they should still be usable from within TEMP
|
|
285
|
+
** views, so there shouldn't be a serious loss of functionality by
|
|
286
|
+
** prohibiting the use of this vtab from persistent triggers and views.
|
|
287
|
+
*/
|
|
288
|
+
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
|
289
|
+
return SQLITE_OK;
|
|
290
|
+
|
|
291
|
+
zsvtab_connect_oom:
|
|
292
|
+
rc = SQLITE_NOMEM;
|
|
293
|
+
asprintf(&errmsg, "Out of memory!");
|
|
294
|
+
|
|
295
|
+
zsvtab_connect_error:
|
|
296
|
+
if( pNew ) zsvtabDisconnect(&pNew->base);
|
|
297
|
+
for(unsigned int i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
|
298
|
+
sqlite3_free(azPValue[i]);
|
|
299
|
+
}
|
|
300
|
+
sqlite3_free(schema);
|
|
301
|
+
if(errmsg) {
|
|
302
|
+
sqlite3_free(*pzErr);
|
|
303
|
+
*pzErr = sqlite3_mprintf("%s", errmsg);
|
|
304
|
+
free(errmsg);
|
|
305
|
+
}
|
|
306
|
+
if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
|
307
|
+
return rc;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/*
|
|
311
|
+
** Only a forward full table scan is supported. xBestIndex is mostly
|
|
312
|
+
** a no-op. If CSVTEST_FIDX is set, then the presence of equality
|
|
313
|
+
** constraints lowers the estimated cost, which is fiction, but is useful
|
|
314
|
+
** for testing certain kinds of virtual table behavior.
|
|
315
|
+
*/
|
|
316
|
+
static int zsvtabBestIndex(
|
|
317
|
+
sqlite3_vtab *tab,
|
|
318
|
+
sqlite3_index_info *pIdxInfo
|
|
319
|
+
){
|
|
320
|
+
(void)(tab);
|
|
321
|
+
pIdxInfo->estimatedCost = 1000000;
|
|
322
|
+
return SQLITE_OK;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/*
|
|
326
|
+
** This method is the destructor for a zsvTable object.
|
|
327
|
+
*/
|
|
328
|
+
static int zsvtabDisconnect(sqlite3_vtab *pVtab){
|
|
329
|
+
zsvTable *p = (zsvTable*)pVtab;
|
|
330
|
+
zsvTable_delete(p);
|
|
331
|
+
return SQLITE_OK;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/*
|
|
335
|
+
** Constructor for a new zsvTable cursor object.
|
|
336
|
+
*/
|
|
337
|
+
static int zsvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|
338
|
+
(void)(p);
|
|
339
|
+
struct zsvCursor *pCur = sqlite3_malloc64(sizeof(*pCur));
|
|
340
|
+
if( pCur==0 ) return SQLITE_NOMEM;
|
|
341
|
+
memset(pCur, 0, sizeof(*pCur));
|
|
342
|
+
*ppCursor = &pCur->base;
|
|
343
|
+
return SQLITE_OK;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/*
|
|
347
|
+
** Destructor for a zsvCursor.
|
|
348
|
+
*/
|
|
349
|
+
static int zsvtabClose(sqlite3_vtab_cursor *cur){
|
|
350
|
+
sqlite3_free(cur);
|
|
351
|
+
return SQLITE_OK;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
** Only a full table scan is supported. So xFilter simply rewinds to
|
|
356
|
+
** the beginning.
|
|
357
|
+
*/
|
|
358
|
+
static int zsvtabFilter(
|
|
359
|
+
sqlite3_vtab_cursor *pVtabCursor,
|
|
360
|
+
int idxNum, const char *idxStr,
|
|
361
|
+
int argc, sqlite3_value **argv
|
|
362
|
+
){
|
|
363
|
+
(void)(idxNum);
|
|
364
|
+
(void)(idxStr);
|
|
365
|
+
(void)(argc);
|
|
366
|
+
(void)(argv);
|
|
367
|
+
zsvTable *pTab = (zsvTable*)pVtabCursor->pVtab;
|
|
368
|
+
|
|
369
|
+
zsvTable_free(pTab);
|
|
370
|
+
fseek(pTab->parser_opts.stream, 0, SEEK_SET);
|
|
371
|
+
|
|
372
|
+
// reload and advance header, then first data row
|
|
373
|
+
if(zsv_new_with_properties(&pTab->parser_opts, &pTab->custom_prop_handler, pTab->zFilename,
|
|
374
|
+
&pTab->parser) != zsv_status_ok
|
|
375
|
+
|| (pTab->parser_status = zsv_next_row(pTab->parser)) != zsv_status_row)
|
|
376
|
+
return SQLITE_ERROR;
|
|
377
|
+
pTab->parser_status = zsv_next_row(pTab->parser);
|
|
378
|
+
pTab->rowCount = 1;
|
|
379
|
+
return SQLITE_OK;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
/*
|
|
384
|
+
** Advance a zsvCursor to its next row of input.
|
|
385
|
+
** Set the EOF marker via pTab->parser_status if we reach the end of input.
|
|
386
|
+
*/
|
|
387
|
+
static int zsvtabNext(sqlite3_vtab_cursor *cur){
|
|
388
|
+
zsvTable *pTab = (zsvTable*)cur->pVtab;
|
|
389
|
+
pTab->parser_status = zsv_next_row(pTab->parser);
|
|
390
|
+
pTab->rowCount++;
|
|
391
|
+
return SQLITE_OK;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
** Return TRUE if the cursor has been moved off of the last
|
|
396
|
+
** row of output.
|
|
397
|
+
*/
|
|
398
|
+
static int zsvtabEof(sqlite3_vtab_cursor *cur){
|
|
399
|
+
zsvTable *pTab = (zsvTable*)cur->pVtab;
|
|
400
|
+
return pTab->parser_status != zsv_status_row;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/*
|
|
404
|
+
** Return values of columns for the row at which the zsvCursor
|
|
405
|
+
** is currently pointing.
|
|
406
|
+
*/
|
|
407
|
+
static int zsvtabColumn(
|
|
408
|
+
sqlite3_vtab_cursor *cur, /* The cursor */
|
|
409
|
+
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
|
410
|
+
int i /* Which column to return */
|
|
411
|
+
){
|
|
412
|
+
zsvTable *pTab = (zsvTable*)cur->pVtab;
|
|
413
|
+
struct zsv_cell c = zsv_get_cell(pTab->parser, i);
|
|
414
|
+
sqlite3_result_text(ctx, (char *)c.str, c.len, SQLITE_STATIC);
|
|
415
|
+
return SQLITE_OK;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
/*
|
|
420
|
+
** Return the rowid for the current row.
|
|
421
|
+
*/
|
|
422
|
+
static int zsvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
|
423
|
+
zsvTable *pTab = (zsvTable*)cur->pVtab;
|
|
424
|
+
*pRowid = pTab->rowCount;
|
|
425
|
+
return SQLITE_OK;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
sqlite3_module CsvModule = {
|
|
429
|
+
0, /* iVersion */
|
|
430
|
+
zsvtabCreate, /* xCreate */
|
|
431
|
+
zsvtabConnect, /* xConnect */
|
|
432
|
+
zsvtabBestIndex, /* xBestIndex */
|
|
433
|
+
zsvtabDisconnect, /* xDisconnect */
|
|
434
|
+
zsvtabDisconnect, /* xDestroy */
|
|
435
|
+
zsvtabOpen, /* xOpen - open a cursor */
|
|
436
|
+
zsvtabClose, /* xClose - close a cursor */
|
|
437
|
+
zsvtabFilter, /* xFilter - configure scan constraints */
|
|
438
|
+
zsvtabNext, /* xNext - advance a cursor */
|
|
439
|
+
zsvtabEof, /* xEof - check for end of scan */
|
|
440
|
+
zsvtabColumn, /* xColumn - read data */
|
|
441
|
+
zsvtabRowid, /* xRowid - read data */
|
|
442
|
+
0, /* xUpdate */
|
|
443
|
+
0, /* xBegin */
|
|
444
|
+
0, /* xSync */
|
|
445
|
+
0, /* xCommit */
|
|
446
|
+
0, /* xRollback */
|
|
447
|
+
0, /* xFindMethod */
|
|
448
|
+
0, /* xRename */
|
|
449
|
+
0, 0, 0, 0 /* xSavepoint, xRelease, xRollbackTo, xShadowName */
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
#ifdef _WIN32
|
|
456
|
+
__declspec(dllexport)
|
|
457
|
+
#endif
|
|
458
|
+
/*
|
|
459
|
+
** This routine is called when the extension is loaded. The new
|
|
460
|
+
** CSV virtual table module is registered with the calling database
|
|
461
|
+
** connection.
|
|
462
|
+
*/
|
|
463
|
+
int sqlite3_csv_init(
|
|
464
|
+
sqlite3 *db,
|
|
465
|
+
char **pzErrMsg,
|
|
466
|
+
const sqlite3_api_routines *pApi
|
|
467
|
+
){
|
|
468
|
+
(void)(pzErrMsg);
|
|
469
|
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
470
|
+
int rc;
|
|
471
|
+
SQLITE_EXTENSION_INIT2(pApi);
|
|
472
|
+
pthread_mutex_t init = PTHREAD_MUTEX_INITIALIZER;
|
|
473
|
+
memcpy(&sqlite3_zsv_data_mutex, &init, sizeof(init));
|
|
474
|
+
rc = sqlite3_create_module_v2(db, "csv", &CsvModule, &sqlite3_zsv_data_g, (void (*)(void *))sqlite3_zsv_list_delete);
|
|
475
|
+
#ifdef SQLITE_TEST
|
|
476
|
+
if( rc==SQLITE_OK ){
|
|
477
|
+
rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0);
|
|
478
|
+
}
|
|
479
|
+
#endif
|
|
480
|
+
return rc;
|
|
481
|
+
#else
|
|
482
|
+
return SQLITE_OK;
|
|
483
|
+
#endif
|
|
484
|
+
}
|
|
485
|
+
/* clang-format on */
|