diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9e13152..ca00651 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,6 +25,6 @@ jobs: env: RUST_BACKTRACE: full - name: Run tests - run: cargo run --example basic + run: cargo test env: RUST_BACKTRACE: full diff --git a/.gitignore b/.gitignore index 7886496..58c8d71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ /target -/Cargo.lock +Cargo.lock *.tar.gz *.so *.h var udf -*.parquet \ No newline at end of file +*.parquet diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index b3135c2..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,680 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "bindgen" -version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chdb-rust" -version = "0.7.0" -dependencies = [ - "bindgen", - "clap", - "serde", - "thiserror", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "clang-sys" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "prettyplease" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "2.0.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index 6992cb6..bde8879 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,11 @@ [package] name = "chdb-rust" -version = "0.7.0" +version = "1.0.0" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +keywords = ["clickhouse", "chdb", "database", "embedded", "analytics"] [dependencies] thiserror = "1" -serde = { version = "1", features = ["derive"] } -tracing = { version="0.1", features=["log"] } - [build-dependencies] -bindgen = "0.65.1" - -[dev-dependencies] -tracing-subscriber = { version="0.3.16", features=["env-filter"] } -clap = { version = "4", features = ["derive"] } +bindgen = "0.70.1" diff --git a/README.md b/README.md index 7e0fb27..f2e6fd2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ # chdb-rust Experimental [chDB](https://github.com/chdb-io/chdb) FFI bindings for Rust + ### Status - Experimental, unstable, subject to changes @@ -13,5 +14,10 @@ Experimental [chDB](https://github.com/chdb-io/chdb) FFI bindings for Rust ```bash ./update_libchdb.sh RUST_BACKTRACE=full cargo build --verbose -cargo run --example basic ``` + +### Run tests +`cargo test` + +### Examples +See `tests` directory. diff --git a/build.rs b/build.rs index 225fb25..fd76fcf 100644 --- a/build.rs +++ b/build.rs @@ -4,11 +4,10 @@ fn main() { // Tell cargo to look for shared libraries in the specified directory println!("cargo:rustc-link-search=./"); - // Tell cargo to tell rustc to link the system bzip2 - // shared library. + // Tell cargo to tell rustc to link the system chdb library. println!("cargo:rustc-link-lib=chdb"); - // Tell cargo to invalidate the built crate whenever the wrapper changes + // Tell cargo to invalidate the built crate whenever the wrapper changes. println!("cargo:rerun-if-changed=chdb.h"); // The bindgen::Builder is the main entry point @@ -20,7 +19,7 @@ fn main() { .header("chdb.h") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. @@ -31,4 +30,4 @@ fn main() { bindings .write_to_file(out_path.join("bindings.rs")) .expect("Couldn't write bindings!"); -} \ No newline at end of file +} diff --git a/examples/basic.rs b/examples/basic.rs deleted file mode 100644 index 7b354f9..0000000 --- a/examples/basic.rs +++ /dev/null @@ -1,9 +0,0 @@ -use chdb_rust::query; - -fn main() { - let v = query("SELECT 'Hello libchdb.so from chdbSimple'", "CSV").unwrap(); - match String::from_utf8(v.buf().to_vec()) { - Ok(s) => println!("{}", s), - Err(e) => println!("Invalid UTF-8 sequence: {}", e), - } -} diff --git a/examples/session.rs b/examples/session.rs deleted file mode 100644 index 10743fe..0000000 --- a/examples/session.rs +++ /dev/null @@ -1,117 +0,0 @@ -use chdb_rust::*; - -use tracing::*; - -#[derive(clap::Parser)] -#[command(version)] -#[command(about = "")] -#[command(author = "tekjar ")] -struct CommandLine { - /// log level (v: info, vv: debug, vvv: trace) - #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)] - verbose: u8, - /// Table name - #[arg(short = 'c', long = "create")] - create_imu: bool, - /// Path to load IMU data from - #[arg(short = 'l', long = "load")] - load_imu: Option, - /// /// Query IMU data - #[arg(short = 'q', long = "query")] - query: String, -} - -fn level(verbose: u8) -> String { - let level = match verbose { - 0 => "warn", - 1 => "info", - 2 => "debug", - _ => "trace", - }; - - level.to_owned() -} - -fn init() -> CommandLine { - let commandline: CommandLine = CommandLine::parse(); - use clap::Parser; - let level = level(commandline.verbose); - - // tracing syntax -> - let builder = tracing_subscriber::fmt() - .pretty() - .with_line_number(false) - .with_file(false) - .with_thread_ids(false) - .with_thread_names(false) - .with_env_filter(&level) - .with_filter_reloading(); - - // let reload_handle = builder.reload_handle(); - - builder - .try_init() - .expect("initialized subscriber succesfully"); - - commandline -} - -fn create_imu(session: &Session) { - session.execute( - " - CREATE DATABASE IF NOT EXISTS demo; - CREATE TABLE IF NOT EXISTS demo.imu - ( - ax Float32, - ay Float32, - az Float32, - magx Float32, - magy Float32, - magz Float32, - roll Float32, - pitch Float32, - yaw Float32, - id String, - date Date DEFAULT toDate(timestamp), - timestamp DateTime64(3), - sequence UInt32 - ) - ENGINE = MergeTree - PARTITION BY date - ORDER BY id - SETTINGS index_granularity = 8192", - ); -} - -fn load_imu(session: &Session, dir: &str) { - session.execute(format!( - " - set input_format_parquet_allow_missing_columns = 1; - INSERT INTO demo.imu SELECT * FROM file('{dir}/*.parquet', Parquet) - " - )); -} - -fn main() { - let cli = init(); - let level = level(cli.verbose); - - error!("error.."); - info!("info.."); - debug!("debug.."); - - let session = SessionBuilder::new().log_level(&level).build().unwrap(); - if cli.create_imu { - create_imu(&session); - } - - if let Some(dir) = cli.load_imu { - load_imu(&session, &dir); - } - - let v = session.execute(cli.query).unwrap(); - println!("Rows = {}, Bytes = {}, Elapsed = {:?}", v.rows_read(), v.bytes_read(), v.elapsed()); - - let result = String::from_utf8(v.buf().to_vec()).unwrap(); - println!("{}", result); -} diff --git a/src/arg.rs b/src/arg.rs new file mode 100644 index 0000000..111ea79 --- /dev/null +++ b/src/arg.rs @@ -0,0 +1,46 @@ +use std::borrow::Cow; +use std::ffi::CString; + +use crate::error::Error; +use crate::format::OutputFormat; +use crate::log_level::LogLevel; + +#[derive(Debug)] +pub enum Arg<'a> { + /// --config-file= + ConfigFilePath(Cow<'a, str>), + /// --log-level= + LogLevel(LogLevel), + /// --output-format= + OutputFormat(OutputFormat), + /// --multiquery + MultiQuery, + /// Custom argument. + /// + /// "--path=/tmp/chdb" translates into one of the following: + /// 1. Arg::Custom("path".to_string().into(), Some("/tmp/chdb".to_string().into())). + /// 2. Arg::Custom("path".into(), Some("/tmp/chdb".into())). + /// + /// "--multiline" translates into one of the following: + /// 1. Arg::Custom("multiline".to_string().into(), None). + /// 2. Arg::Custom("multiline".into(), None). + /// + /// We should tell user where to look for officially supported arguments. + /// Here is some hint for now: https://github.com/fixcik/chdb-rs/blob/master/OPTIONS.md . + Custom(Cow<'a, str>, Option>), +} + +impl<'a> Arg<'a> { + pub(crate) fn to_cstring(&self) -> Result { + Ok(match self { + Self::ConfigFilePath(v) => CString::new(format!("--config-file={}", v)), + Self::LogLevel(v) => CString::new(format!("--log-level={}", v.as_str())), + Self::OutputFormat(v) => CString::new(format!("--output-format={}", v.as_str())), + Self::MultiQuery => CString::new("-n"), + Self::Custom(k, v) => match v { + None => CString::new(k.as_ref()), + Some(v) => CString::new(format!("--{}={}", k, v)), + }, + }?) + } +} diff --git a/src/basic.rs b/src/basic.rs deleted file mode 100644 index d388fc3..0000000 --- a/src/basic.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::{ - ffi::{c_char, CString}, - slice, - time::Duration, -}; - -use crate::bindings; - -pub fn query(query: &str, format: &str) -> Option { - let mut argv: Vec = Vec::new(); - argv.push("clickhouse".to_string()); - argv.push("--multiquery".to_string()); - argv.push(format!("--output-format={format}")); - argv.push(format!("--query={query}")); - - let argc = argv.len() as i32; - let mut argv: Vec<*mut c_char> = argv - .into_iter() - .map(|arg| CString::new(arg).unwrap().into_raw()) - .collect(); - - let argv = argv.as_mut_ptr(); - let local = unsafe { bindings::query_stable(argc, argv) }; - if local.is_null() { - return None; - } - - Some(LocalResult { local }) -} - -#[derive(Debug, Clone)] -pub struct LocalResult { - pub(crate) local: *mut bindings::local_result, -} - -impl LocalResult { - pub fn rows_read(&self) -> u64 { - (unsafe { *self.local }).rows_read - } - - pub fn bytes_read(&self) -> u64 { - unsafe { (*self.local).bytes_read } - } - - pub fn buf(&self) -> &[u8] { - let buf = unsafe { (*self.local).buf }; - let len = unsafe { (*self.local).len }; - let bytes: &[u8] = unsafe { slice::from_raw_parts(buf as *const u8, len) }; - bytes - } - - pub fn elapsed(&self) -> Duration { - let elapsed = unsafe { (*self.local).elapsed }; - Duration::from_secs_f64(elapsed) - } -} - -impl Drop for LocalResult { - fn drop(&mut self) { - unsafe { bindings::free_result(self.local) }; - } -} diff --git a/src/bindings.rs b/src/bindings.rs index 77ad7d4..7de91ba 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -1,731 +1,265 @@ -/* automatically generated by rust-bindgen 0.65.1 */ +/* automatically generated by rust-bindgen 0.70.1 */ +pub const _STDINT_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC2X: u32 = 0; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; pub const __WORDSIZE: u32 = 64; -pub const __DARWIN_ONLY_64_BIT_INO_T: u32 = 0; -pub const __DARWIN_ONLY_UNIX_CONFORMANCE: u32 = 1; -pub const __DARWIN_ONLY_VERS_1050: u32 = 0; -pub const __DARWIN_UNIX03: u32 = 1; -pub const __DARWIN_64_BIT_INO_T: u32 = 1; -pub const __DARWIN_VERS_1050: u32 = 1; -pub const __DARWIN_NON_CANCELABLE: u32 = 0; -pub const __DARWIN_SUF_64_BIT_INO_T: &[u8; 9usize] = b"$INODE64\0"; -pub const __DARWIN_SUF_1050: &[u8; 6usize] = b"$1050\0"; -pub const __DARWIN_SUF_EXTSN: &[u8; 14usize] = b"$DARWIN_EXTSN\0"; -pub const __DARWIN_C_ANSI: u32 = 4096; -pub const __DARWIN_C_FULL: u32 = 900000; -pub const __DARWIN_C_LEVEL: u32 = 900000; -pub const __STDC_WANT_LIB_EXT1__: u32 = 1; -pub const __DARWIN_NO_LONG_LONG: u32 = 0; -pub const _DARWIN_FEATURE_64_BIT_INODE: u32 = 1; -pub const _DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE: u32 = 1; -pub const _DARWIN_FEATURE_UNIX_CONFORMANCE: u32 = 3; -pub const __has_ptrcheck: u32 = 0; -pub const __PTHREAD_SIZE__: u32 = 8176; -pub const __PTHREAD_ATTR_SIZE__: u32 = 56; -pub const __PTHREAD_MUTEXATTR_SIZE__: u32 = 8; -pub const __PTHREAD_MUTEX_SIZE__: u32 = 56; -pub const __PTHREAD_CONDATTR_SIZE__: u32 = 8; -pub const __PTHREAD_COND_SIZE__: u32 = 40; -pub const __PTHREAD_ONCE_SIZE__: u32 = 8; -pub const __PTHREAD_RWLOCK_SIZE__: u32 = 192; -pub const __PTHREAD_RWLOCKATTR_SIZE__: u32 = 16; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const INT64_MAX: u64 = 9223372036854775807; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __TIMESIZE: u32 = 64; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const __GLIBC_USE_C2X_STRTOL: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_60559_BFP__: u32 = 201404; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 39; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 1; +pub const __GLIBC_USE_LIB_EXT2: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0; +pub const _BITS_TYPES_H: u32 = 1; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const _BITS_STDINT_LEAST_H: u32 = 1; pub const INT8_MIN: i32 = -128; pub const INT16_MIN: i32 = -32768; pub const INT32_MIN: i32 = -2147483648; -pub const INT64_MIN: i64 = -9223372036854775808; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; pub const UINT8_MAX: u32 = 255; pub const UINT16_MAX: u32 = 65535; pub const UINT32_MAX: u32 = 4294967295; -pub const UINT64_MAX: i32 = -1; pub const INT_LEAST8_MIN: i32 = -128; pub const INT_LEAST16_MIN: i32 = -32768; pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST64_MIN: i64 = -9223372036854775808; pub const INT_LEAST8_MAX: u32 = 127; pub const INT_LEAST16_MAX: u32 = 32767; pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const INT_LEAST64_MAX: u64 = 9223372036854775807; pub const UINT_LEAST8_MAX: u32 = 255; pub const UINT_LEAST16_MAX: u32 = 65535; pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const UINT_LEAST64_MAX: i32 = -1; pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i32 = -32768; -pub const INT_FAST32_MIN: i32 = -2147483648; -pub const INT_FAST64_MIN: i64 = -9223372036854775808; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u32 = 32767; -pub const INT_FAST32_MAX: u32 = 2147483647; -pub const INT_FAST64_MAX: u64 = 9223372036854775807; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: u32 = 65535; -pub const UINT_FAST32_MAX: u32 = 4294967295; -pub const UINT_FAST64_MAX: i32 = -1; -pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; pub const UINTPTR_MAX: i32 = -1; -pub const SIZE_MAX: i32 = -1; -pub const RSIZE_MAX: i32 = -1; -pub const WINT_MIN: i32 = -2147483648; -pub const WINT_MAX: u32 = 2147483647; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; pub const SIG_ATOMIC_MIN: i32 = -2147483648; pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; pub type wchar_t = ::std::os::raw::c_int; -pub type max_align_t = u128; -pub type int_least8_t = i8; -pub type int_least16_t = i16; -pub type int_least32_t = i32; -pub type int_least64_t = i64; -pub type uint_least8_t = u8; -pub type uint_least16_t = u16; -pub type uint_least32_t = u32; -pub type uint_least64_t = u64; -pub type int_fast8_t = i8; -pub type int_fast16_t = i16; -pub type int_fast32_t = i32; -pub type int_fast64_t = i64; -pub type uint_fast8_t = u8; -pub type uint_fast16_t = u16; -pub type uint_fast32_t = u32; -pub type uint_fast64_t = u64; +#[repr(C)] +#[repr(align(16))] +#[derive(Debug, Copy, Clone)] +pub struct max_align_t { + pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, + pub __bindgen_padding_0: u64, + pub __clang_max_align_nonce2: u128, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of max_align_t"][::std::mem::size_of::() - 32usize]; + ["Alignment of max_align_t"][::std::mem::align_of::() - 16usize]; + ["Offset of field: max_align_t::__clang_max_align_nonce1"] + [::std::mem::offset_of!(max_align_t, __clang_max_align_nonce1) - 0usize]; + ["Offset of field: max_align_t::__clang_max_align_nonce2"] + [::std::mem::offset_of!(max_align_t, __clang_max_align_nonce2) - 16usize]; +}; +pub type __u_char = ::std::os::raw::c_uchar; +pub type __u_short = ::std::os::raw::c_ushort; +pub type __u_int = ::std::os::raw::c_uint; +pub type __u_long = ::std::os::raw::c_ulong; pub type __int8_t = ::std::os::raw::c_schar; pub type __uint8_t = ::std::os::raw::c_uchar; pub type __int16_t = ::std::os::raw::c_short; pub type __uint16_t = ::std::os::raw::c_ushort; pub type __int32_t = ::std::os::raw::c_int; pub type __uint32_t = ::std::os::raw::c_uint; -pub type __int64_t = ::std::os::raw::c_longlong; -pub type __uint64_t = ::std::os::raw::c_ulonglong; -pub type __darwin_intptr_t = ::std::os::raw::c_long; -pub type __darwin_natural_t = ::std::os::raw::c_uint; -pub type __darwin_ct_rune_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Copy, Clone)] -pub union __mbstate_t { - pub __mbstate8: [::std::os::raw::c_char; 128usize], - pub _mbstateL: ::std::os::raw::c_longlong, -} -#[test] -fn bindgen_test_layout___mbstate_t() { - const UNINIT: ::std::mem::MaybeUninit<__mbstate_t> = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<__mbstate_t>(), - 128usize, - concat!("Size of: ", stringify!(__mbstate_t)) - ); - assert_eq!( - ::std::mem::align_of::<__mbstate_t>(), - 8usize, - concat!("Alignment of ", stringify!(__mbstate_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__mbstate8) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__mbstate_t), - "::", - stringify!(__mbstate8) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr)._mbstateL) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__mbstate_t), - "::", - stringify!(_mbstateL) - ) - ); -} -pub type __darwin_mbstate_t = __mbstate_t; -pub type __darwin_ptrdiff_t = ::std::os::raw::c_long; -pub type __darwin_size_t = ::std::os::raw::c_ulong; -pub type __darwin_va_list = __builtin_va_list; -pub type __darwin_wchar_t = ::std::os::raw::c_int; -pub type __darwin_rune_t = __darwin_wchar_t; -pub type __darwin_wint_t = ::std::os::raw::c_int; -pub type __darwin_clock_t = ::std::os::raw::c_ulong; -pub type __darwin_socklen_t = __uint32_t; -pub type __darwin_ssize_t = ::std::os::raw::c_long; -pub type __darwin_time_t = ::std::os::raw::c_long; -pub type __darwin_blkcnt_t = __int64_t; -pub type __darwin_blksize_t = __int32_t; -pub type __darwin_dev_t = __int32_t; -pub type __darwin_fsblkcnt_t = ::std::os::raw::c_uint; -pub type __darwin_fsfilcnt_t = ::std::os::raw::c_uint; -pub type __darwin_gid_t = __uint32_t; -pub type __darwin_id_t = __uint32_t; -pub type __darwin_ino64_t = __uint64_t; -pub type __darwin_ino_t = __darwin_ino64_t; -pub type __darwin_mach_port_name_t = __darwin_natural_t; -pub type __darwin_mach_port_t = __darwin_mach_port_name_t; -pub type __darwin_mode_t = __uint16_t; -pub type __darwin_off_t = __int64_t; -pub type __darwin_pid_t = __int32_t; -pub type __darwin_sigset_t = __uint32_t; -pub type __darwin_suseconds_t = __int32_t; -pub type __darwin_uid_t = __uint32_t; -pub type __darwin_useconds_t = __uint32_t; -pub type __darwin_uuid_t = [::std::os::raw::c_uchar; 16usize]; -pub type __darwin_uuid_string_t = [::std::os::raw::c_char; 37usize]; +pub type __int64_t = ::std::os::raw::c_long; +pub type __uint64_t = ::std::os::raw::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::std::os::raw::c_long; +pub type __u_quad_t = ::std::os::raw::c_ulong; +pub type __intmax_t = ::std::os::raw::c_long; +pub type __uintmax_t = ::std::os::raw::c_ulong; +pub type __dev_t = ::std::os::raw::c_ulong; +pub type __uid_t = ::std::os::raw::c_uint; +pub type __gid_t = ::std::os::raw::c_uint; +pub type __ino_t = ::std::os::raw::c_ulong; +pub type __ino64_t = ::std::os::raw::c_ulong; +pub type __mode_t = ::std::os::raw::c_uint; +pub type __nlink_t = ::std::os::raw::c_ulong; +pub type __off_t = ::std::os::raw::c_long; +pub type __off64_t = ::std::os::raw::c_long; +pub type __pid_t = ::std::os::raw::c_int; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct __darwin_pthread_handler_rec { - pub __routine: ::std::option::Option, - pub __arg: *mut ::std::os::raw::c_void, - pub __next: *mut __darwin_pthread_handler_rec, -} -#[test] -fn bindgen_test_layout___darwin_pthread_handler_rec() { - const UNINIT: ::std::mem::MaybeUninit<__darwin_pthread_handler_rec> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<__darwin_pthread_handler_rec>(), - 24usize, - concat!("Size of: ", stringify!(__darwin_pthread_handler_rec)) - ); - assert_eq!( - ::std::mem::align_of::<__darwin_pthread_handler_rec>(), - 8usize, - concat!("Alignment of ", stringify!(__darwin_pthread_handler_rec)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__routine) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__darwin_pthread_handler_rec), - "::", - stringify!(__routine) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__arg) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__darwin_pthread_handler_rec), - "::", - stringify!(__arg) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__next) as usize - ptr as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__darwin_pthread_handler_rec), - "::", - stringify!(__next) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_attr_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 56usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_attr_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_attr_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_attr_t>(), - 64usize, - concat!("Size of: ", stringify!(_opaque_pthread_attr_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_attr_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_attr_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_attr_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_attr_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_cond_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 40usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_cond_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_cond_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_cond_t>(), - 48usize, - concat!("Size of: ", stringify!(_opaque_pthread_cond_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_cond_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_cond_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_cond_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_cond_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_condattr_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 8usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_condattr_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_condattr_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_condattr_t>(), - 16usize, - concat!("Size of: ", stringify!(_opaque_pthread_condattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_condattr_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_condattr_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_condattr_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_condattr_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_mutex_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 56usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_mutex_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_mutex_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_mutex_t>(), - 64usize, - concat!("Size of: ", stringify!(_opaque_pthread_mutex_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_mutex_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_mutex_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_mutex_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_mutex_t), - "::", - stringify!(__opaque) - ) - ); +pub struct __fsid_t { + pub __val: [::std::os::raw::c_int; 2usize], } +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of __fsid_t"][::std::mem::size_of::<__fsid_t>() - 8usize]; + ["Alignment of __fsid_t"][::std::mem::align_of::<__fsid_t>() - 4usize]; + ["Offset of field: __fsid_t::__val"][::std::mem::offset_of!(__fsid_t, __val) - 0usize]; +}; +pub type __clock_t = ::std::os::raw::c_long; +pub type __rlim_t = ::std::os::raw::c_ulong; +pub type __rlim64_t = ::std::os::raw::c_ulong; +pub type __id_t = ::std::os::raw::c_uint; +pub type __time_t = ::std::os::raw::c_long; +pub type __useconds_t = ::std::os::raw::c_uint; +pub type __suseconds_t = ::std::os::raw::c_long; +pub type __suseconds64_t = ::std::os::raw::c_long; +pub type __daddr_t = ::std::os::raw::c_int; +pub type __key_t = ::std::os::raw::c_int; +pub type __clockid_t = ::std::os::raw::c_int; +pub type __timer_t = *mut ::std::os::raw::c_void; +pub type __blksize_t = ::std::os::raw::c_long; +pub type __blkcnt_t = ::std::os::raw::c_long; +pub type __blkcnt64_t = ::std::os::raw::c_long; +pub type __fsblkcnt_t = ::std::os::raw::c_ulong; +pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; +pub type __fsword_t = ::std::os::raw::c_long; +pub type __ssize_t = ::std::os::raw::c_long; +pub type __syscall_slong_t = ::std::os::raw::c_long; +pub type __syscall_ulong_t = ::std::os::raw::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::std::os::raw::c_char; +pub type __intptr_t = ::std::os::raw::c_long; +pub type __socklen_t = ::std::os::raw::c_uint; +pub type __sig_atomic_t = ::std::os::raw::c_int; +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::std::os::raw::c_schar; +pub type int_fast16_t = ::std::os::raw::c_long; +pub type int_fast32_t = ::std::os::raw::c_long; +pub type int_fast64_t = ::std::os::raw::c_long; +pub type uint_fast8_t = ::std::os::raw::c_uchar; +pub type uint_fast16_t = ::std::os::raw::c_ulong; +pub type uint_fast32_t = ::std::os::raw::c_ulong; +pub type uint_fast64_t = ::std::os::raw::c_ulong; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_mutexattr_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 8usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_mutexattr_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_mutexattr_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_mutexattr_t>(), - 16usize, - concat!("Size of: ", stringify!(_opaque_pthread_mutexattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_mutexattr_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_mutexattr_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_mutexattr_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_mutexattr_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_once_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 8usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_once_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_once_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_once_t>(), - 16usize, - concat!("Size of: ", stringify!(_opaque_pthread_once_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_once_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_once_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_once_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_once_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_rwlock_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 192usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_rwlock_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_rwlock_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_rwlock_t>(), - 200usize, - concat!("Size of: ", stringify!(_opaque_pthread_rwlock_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_rwlock_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_rwlock_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_rwlock_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_rwlock_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_rwlockattr_t { - pub __sig: ::std::os::raw::c_long, - pub __opaque: [::std::os::raw::c_char; 16usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_rwlockattr_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_rwlockattr_t> = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_rwlockattr_t>(), - 24usize, - concat!("Size of: ", stringify!(_opaque_pthread_rwlockattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_rwlockattr_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_rwlockattr_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_rwlockattr_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_rwlockattr_t), - "::", - stringify!(__opaque) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _opaque_pthread_t { - pub __sig: ::std::os::raw::c_long, - pub __cleanup_stack: *mut __darwin_pthread_handler_rec, - pub __opaque: [::std::os::raw::c_char; 8176usize], -} -#[test] -fn bindgen_test_layout__opaque_pthread_t() { - const UNINIT: ::std::mem::MaybeUninit<_opaque_pthread_t> = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<_opaque_pthread_t>(), - 8192usize, - concat!("Size of: ", stringify!(_opaque_pthread_t)) - ); - assert_eq!( - ::std::mem::align_of::<_opaque_pthread_t>(), - 8usize, - concat!("Alignment of ", stringify!(_opaque_pthread_t)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__sig) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_t), - "::", - stringify!(__sig) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__cleanup_stack) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_t), - "::", - stringify!(__cleanup_stack) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).__opaque) as usize - ptr as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(_opaque_pthread_t), - "::", - stringify!(__opaque) - ) - ); +pub struct local_result { + pub buf: *mut ::std::os::raw::c_char, + pub len: usize, + pub _vec: *mut ::std::os::raw::c_void, + pub elapsed: f64, + pub rows_read: u64, + pub bytes_read: u64, } -pub type __darwin_pthread_attr_t = _opaque_pthread_attr_t; -pub type __darwin_pthread_cond_t = _opaque_pthread_cond_t; -pub type __darwin_pthread_condattr_t = _opaque_pthread_condattr_t; -pub type __darwin_pthread_key_t = ::std::os::raw::c_ulong; -pub type __darwin_pthread_mutex_t = _opaque_pthread_mutex_t; -pub type __darwin_pthread_mutexattr_t = _opaque_pthread_mutexattr_t; -pub type __darwin_pthread_once_t = _opaque_pthread_once_t; -pub type __darwin_pthread_rwlock_t = _opaque_pthread_rwlock_t; -pub type __darwin_pthread_rwlockattr_t = _opaque_pthread_rwlockattr_t; -pub type __darwin_pthread_t = *mut _opaque_pthread_t; -pub type u_int8_t = ::std::os::raw::c_uchar; -pub type u_int16_t = ::std::os::raw::c_ushort; -pub type u_int32_t = ::std::os::raw::c_uint; -pub type u_int64_t = ::std::os::raw::c_ulonglong; -pub type register_t = i64; -pub type user_addr_t = u_int64_t; -pub type user_size_t = u_int64_t; -pub type user_ssize_t = i64; -pub type user_long_t = i64; -pub type user_ulong_t = u_int64_t; -pub type user_time_t = i64; -pub type user_off_t = i64; -pub type syscall_arg_t = u_int64_t; -pub type intmax_t = ::std::os::raw::c_long; -pub type uintmax_t = ::std::os::raw::c_ulong; +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of local_result"][::std::mem::size_of::() - 48usize]; + ["Alignment of local_result"][::std::mem::align_of::() - 8usize]; + ["Offset of field: local_result::buf"][::std::mem::offset_of!(local_result, buf) - 0usize]; + ["Offset of field: local_result::len"][::std::mem::offset_of!(local_result, len) - 8usize]; + ["Offset of field: local_result::_vec"][::std::mem::offset_of!(local_result, _vec) - 16usize]; + ["Offset of field: local_result::elapsed"] + [::std::mem::offset_of!(local_result, elapsed) - 24usize]; + ["Offset of field: local_result::rows_read"] + [::std::mem::offset_of!(local_result, rows_read) - 32usize]; + ["Offset of field: local_result::bytes_read"] + [::std::mem::offset_of!(local_result, bytes_read) - 40usize]; +}; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct local_result { +pub struct local_result_v2 { pub buf: *mut ::std::os::raw::c_char, pub len: usize, pub _vec: *mut ::std::os::raw::c_void, pub elapsed: f64, pub rows_read: u64, pub bytes_read: u64, + pub error_message: *mut ::std::os::raw::c_char, } -#[test] -fn bindgen_test_layout_local_result() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 48usize, - concat!("Size of: ", stringify!(local_result)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(local_result)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).buf) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(buf) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(len) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr)._vec) as usize - ptr as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(_vec) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).elapsed) as usize - ptr as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(elapsed) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).rows_read) as usize - ptr as usize }, - 32usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(rows_read) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).bytes_read) as usize - ptr as usize }, - 40usize, - concat!( - "Offset of field: ", - stringify!(local_result), - "::", - stringify!(bytes_read) - ) - ); -} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of local_result_v2"][::std::mem::size_of::() - 56usize]; + ["Alignment of local_result_v2"][::std::mem::align_of::() - 8usize]; + ["Offset of field: local_result_v2::buf"] + [::std::mem::offset_of!(local_result_v2, buf) - 0usize]; + ["Offset of field: local_result_v2::len"] + [::std::mem::offset_of!(local_result_v2, len) - 8usize]; + ["Offset of field: local_result_v2::_vec"] + [::std::mem::offset_of!(local_result_v2, _vec) - 16usize]; + ["Offset of field: local_result_v2::elapsed"] + [::std::mem::offset_of!(local_result_v2, elapsed) - 24usize]; + ["Offset of field: local_result_v2::rows_read"] + [::std::mem::offset_of!(local_result_v2, rows_read) - 32usize]; + ["Offset of field: local_result_v2::bytes_read"] + [::std::mem::offset_of!(local_result_v2, bytes_read) - 40usize]; + ["Offset of field: local_result_v2::error_message"] + [::std::mem::offset_of!(local_result_v2, error_message) - 48usize]; +}; extern "C" { pub fn query_stable( argc: ::std::os::raw::c_int, @@ -735,67 +269,12 @@ extern "C" { extern "C" { pub fn free_result(result: *mut local_result); } -pub type __builtin_va_list = [__va_list_tag; 1usize]; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __va_list_tag { - pub gp_offset: ::std::os::raw::c_uint, - pub fp_offset: ::std::os::raw::c_uint, - pub overflow_arg_area: *mut ::std::os::raw::c_void, - pub reg_save_area: *mut ::std::os::raw::c_void, +extern "C" { + pub fn query_stable_v2( + argc: ::std::os::raw::c_int, + argv: *mut *mut ::std::os::raw::c_char, + ) -> *mut local_result_v2; } -#[test] -fn bindgen_test_layout___va_list_tag() { - const UNINIT: ::std::mem::MaybeUninit<__va_list_tag> = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::<__va_list_tag>(), - 24usize, - concat!("Size of: ", stringify!(__va_list_tag)) - ); - assert_eq!( - ::std::mem::align_of::<__va_list_tag>(), - 8usize, - concat!("Alignment of ", stringify!(__va_list_tag)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).gp_offset) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__va_list_tag), - "::", - stringify!(gp_offset) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).fp_offset) as usize - ptr as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(__va_list_tag), - "::", - stringify!(fp_offset) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).overflow_arg_area) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__va_list_tag), - "::", - stringify!(overflow_arg_area) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).reg_save_area) as usize - ptr as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__va_list_tag), - "::", - stringify!(reg_save_area) - ) - ); +extern "C" { + pub fn free_result_v2(result: *mut local_result_v2); } diff --git a/src/builder.rs b/src/builder.rs deleted file mode 100644 index 5072315..0000000 --- a/src/builder.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::{fs, path::PathBuf}; - -use tracing::error; - -use crate::{session::Session, Error}; - -pub struct SessionBuilder { - format: String, - log_level: String, - data_path: std::path::PathBuf, - udf_path: std::path::PathBuf, -} - -impl SessionBuilder { - pub fn new() -> Self { - let mut data_path = std::env::current_dir().unwrap(); - data_path.push("var"); - - let mut udf_path = std::env::current_dir().unwrap(); - udf_path.push("udf"); - - SessionBuilder { - format: "CSV".to_owned(), - log_level: "trace".to_owned(), - data_path, - udf_path, - } - } - - pub fn format(mut self, format: impl Into) -> Self { - self.format = format.into(); - self - } - - pub fn data_path(mut self, path: impl Into) -> Self { - self.data_path = path.into(); - self - } - - pub fn udf_path(mut self, path: impl Into) -> Self { - self.data_path = path.into(); - self - } - - pub fn log_level(mut self, level: &str) -> Self { - self.log_level = match level { - "trace" => "trace".to_string(), - "debug" => "debug".to_string(), - "info" => "information".to_string(), - "warn" => "warning".to_string(), - _ => { - error!("Invalid log level. Setting to info"); - "information".to_string() - } - }; - - self - } - - pub fn build(self) -> Result { - std::fs::create_dir_all(&self.data_path)?; - if fs::metadata(&self.data_path)?.permissions().readonly() { - return Err(Error::InsufficientPermissions); - } - - let data_path = self.data_path.to_str().ok_or(Error::PathError)?.to_string(); - - std::fs::create_dir_all(&self.udf_path)?; - if fs::metadata(&self.udf_path)?.permissions().readonly() { - return Err(Error::InsufficientPermissions); - } - - let udf_path = self.udf_path.to_str().ok_or(Error::PathError)?.to_string(); - - Ok(Session { - format: self.format, - data_path, - udf_path, - log_level: self.log_level, - }) - } -} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..cf9023f --- /dev/null +++ b/src/error.rs @@ -0,0 +1,21 @@ +use std::ffi::NulError; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("An unknown error has occurred")] + Unknown, + #[error("Invalid data: {0}")] + InvalidData(String), + #[error("Invalid path")] + PathError, + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Nul(#[from] NulError), + #[error("Insufficient dir permissions")] + InsufficientPermissions, + #[error("Non UTF-8 sequence: {0}")] + NonUtf8Sequence(String), + #[error("{0}")] + QueryError(String), +} diff --git a/src/format.rs b/src/format.rs new file mode 100644 index 0000000..fc2ec24 --- /dev/null +++ b/src/format.rs @@ -0,0 +1,281 @@ +#[derive(Debug, Clone, Copy)] +pub enum InputFormat { + TabSeparated, + TabSeparatedRaw, + TabSeparatedWithNames, + TabSeparatedWithNamesAndTypes, + TabSeparatedRawWithNames, + TabSeparatedRawWithNamesAndTypes, + Template, + TemplateIgnoreSpaces, + CSV, + CSVWithNames, + CSVWithNamesAndTypes, + CustomSeparated, + CustomSeparatedWithNames, + CustomSeparatedWithNamesAndTypes, + Values, + JSON, + JSONAsString, + JSONAsObject, + JSONStrings, + JSONColumns, + JSONColumnsWithMetadata, + JSONCompact, + JSONCompactColumns, + JSONEachRow, + JSONStringsEachRow, + JSONCompactEachRow, + JSONCompactEachRowWithNames, + JSONCompactEachRowWithNamesAndTypes, + JSONCompactStringsEachRow, + JSONCompactStringsEachRowWithNames, + JSONCompactStringsEachRowWithNamesAndTypes, + JSONObjectEachRow, + BSONEachRow, + TSKV, + Protobuf, + ProtobufSingle, + ProtobufList, + Avro, + AvroConfluent, + Parquet, + ParquetMetadata, + Arrow, + ArrowStream, + ORC, + One, + Npy, + RowBinary, + RowBinaryWithNames, + RowBinaryWithNamesAndTypes, + RowBinaryWithDefaults, + Native, + CapnProto, + LineAsString, + Regexp, + RawBLOB, + MsgPack, + MySQLDump, + DWARF, + Form, +} + +#[derive(Debug, Clone, Copy)] +pub enum OutputFormat { + TabSeparated, + TabSeparatedRaw, + TabSeparatedWithNames, + TabSeparatedWithNamesAndTypes, + TabSeparatedRawWithNames, + TabSeparatedRawWithNamesAndTypes, + Template, + CSV, + CSVWithNames, + CSVWithNamesAndTypes, + CustomSeparated, + CustomSeparatedWithNames, + CustomSeparatedWithNamesAndTypes, + Values, + JSON, + JSONStrings, + JSONColumns, + JSONColumnsWithMetadata, + JSONCompact, + JSONCompactStrings, + JSONCompactColumns, + JSONEachRow, + PrettyJSONEachRow, + JSONEachRowWithProgress, + JSONStringsEachRow, + JSONStringsEachRowWithProgress, + JSONCompactEachRow, + JSONCompactEachRowWithNames, + JSONCompactEachRowWithNamesAndTypes, + JSONCompactStringsEachRow, + JSONCompactStringsEachRowWithNames, + JSONCompactStringsEachRowWithNamesAndTypes, + JSONObjectEachRow, + BSONEachRow, + TSKV, + Pretty, + PrettyNoEscapes, + PrettyMonoBlock, + PrettyNoEscapesMonoBlock, + PrettyCompact, + PrettyCompactNoEscapes, + PrettyCompactMonoBlock, + PrettyCompactNoEscapesMonoBlock, + PrettySpace, + PrettySpaceNoEscapes, + PrettySpaceMonoBlock, + PrettySpaceNoEscapesMonoBlock, + Prometheus, + Protobuf, + ProtobufSingle, + ProtobufList, + Avro, + Parquet, + Arrow, + ArrowStream, + ORC, + Npy, + RowBinary, + RowBinaryWithNames, + RowBinaryWithNamesAndTypes, + Native, + Null, + XML, + CapnProto, + LineAsString, + RawBLOB, + MsgPack, + Markdown, + Vertical, +} + +impl InputFormat { + pub const fn as_str(self) -> &'static str { + match self { + Self::TabSeparated => "TabSeparated", + Self::TabSeparatedRaw => "TabSeparatedRaw", + Self::TabSeparatedWithNames => "TabSeparatedWithNames", + Self::TabSeparatedWithNamesAndTypes => "TabSeparatedWithNamesAndTypes", + Self::TabSeparatedRawWithNames => "TabSeparatedRawWithNames", + Self::TabSeparatedRawWithNamesAndTypes => "TabSeparatedRawWithNamesAndTypes", + Self::Template => "Template", + Self::TemplateIgnoreSpaces => "TemplateIgnoreSpaces", + Self::CSV => "CSV", + Self::CSVWithNames => "CSVWithNames", + Self::CSVWithNamesAndTypes => "CSVWithNamesAndTypes", + Self::CustomSeparated => "CustomSeparated", + Self::CustomSeparatedWithNames => "CustomSeparatedWithNames", + Self::CustomSeparatedWithNamesAndTypes => "CustomSeparatedWithNamesAndTypes", + Self::Values => "Values", + Self::JSON => "JSON", + Self::JSONAsString => "JSONAsString", + Self::JSONAsObject => "JSONAsObject", + Self::JSONStrings => "JSONStrings", + Self::JSONColumns => "JSONColumns", + Self::JSONColumnsWithMetadata => "JSONColumnsWithMetadata", + Self::JSONCompact => "JSONCompact", + Self::JSONCompactColumns => "JSONCompactColumns", + Self::JSONEachRow => "JSONEachRow", + Self::JSONStringsEachRow => "JSONStringsEachRow", + Self::JSONCompactEachRow => "JSONCompactEachRow", + Self::JSONCompactEachRowWithNames => "JSONCompactEachRowWithNames", + Self::JSONCompactEachRowWithNamesAndTypes => "JSONCompactEachRowWithNamesAndTypes", + Self::JSONCompactStringsEachRow => "JSONCompactStringsEachRow", + Self::JSONCompactStringsEachRowWithNames => "JSONCompactStringsEachRowWithNames", + Self::JSONCompactStringsEachRowWithNamesAndTypes => { + "JSONCompactStringsEachRowWithNamesAndTypes" + } + Self::JSONObjectEachRow => "JSONObjectEachRow", + Self::BSONEachRow => "BSONEachRow", + Self::TSKV => "TSKV", + Self::Protobuf => "Protobuf", + Self::ProtobufSingle => "ProtobufSingle", + Self::ProtobufList => "ProtobufList", + Self::Avro => "Avro", + Self::AvroConfluent => "AvroConfluent", + Self::Parquet => "Parquet", + Self::ParquetMetadata => "ParquetMetadata", + Self::Arrow => "Arrow", + Self::ArrowStream => "ArrowStream", + Self::ORC => "ORC", + Self::One => "One", + Self::Npy => "Npy", + Self::RowBinary => "RowBinary", + Self::RowBinaryWithNames => "RowBinaryWithNames", + Self::RowBinaryWithNamesAndTypes => "RowBinaryWithNamesAndTypes", + Self::RowBinaryWithDefaults => "RowBinaryWithDefaults", + Self::Native => "Native", + Self::CapnProto => "CapnProto", + Self::LineAsString => "LineAsString", + Self::Regexp => "Regexp", + Self::RawBLOB => "RawBLOB", + Self::MsgPack => "MsgPack", + Self::MySQLDump => "MySQLDump", + Self::DWARF => "DWARF", + Self::Form => "Form", + } + } +} + +impl OutputFormat { + pub const fn as_str(self) -> &'static str { + match self { + Self::TabSeparated => "TabSeparated", + Self::TabSeparatedRaw => "TabSeparatedRaw", + Self::TabSeparatedWithNames => "TabSeparatedWithNames", + Self::TabSeparatedWithNamesAndTypes => "TabSeparatedWithNamesAndTypes", + Self::TabSeparatedRawWithNames => "TabSeparatedRawWithNames", + Self::TabSeparatedRawWithNamesAndTypes => "TabSeparatedRawWithNamesAndTypes", + Self::Template => "Template", + Self::CSV => "CSV", + Self::CSVWithNames => "CSVWithNames", + Self::CSVWithNamesAndTypes => "CSVWithNamesAndTypes", + Self::CustomSeparated => "CustomSeparated", + Self::CustomSeparatedWithNames => "CustomSeparatedWithNames", + Self::CustomSeparatedWithNamesAndTypes => "CustomSeparatedWithNamesAndTypes", + Self::Values => "Values", + Self::JSON => "JSON", + Self::JSONStrings => "JSONStrings", + Self::JSONColumns => "JSONColumns", + Self::JSONColumnsWithMetadata => "JSONColumnsWithMetadata", + Self::JSONCompact => "JSONCompact", + Self::JSONCompactStrings => "JSONCompactStrings", + Self::JSONCompactColumns => "JSONCompactColumns", + Self::JSONEachRow => "JSONEachRow", + Self::PrettyJSONEachRow => "PrettyJSONEachRow", + Self::JSONEachRowWithProgress => "JSONEachRowWithProgress", + Self::JSONStringsEachRow => "JSONStringsEachRow", + Self::JSONStringsEachRowWithProgress => "JSONStringsEachRowWithProgress", + Self::JSONCompactEachRow => "JSONCompactEachRow", + Self::JSONCompactEachRowWithNames => "JSONCompactEachRowWithNames", + Self::JSONCompactEachRowWithNamesAndTypes => "JSONCompactEachRowWithNamesAndTypes", + Self::JSONCompactStringsEachRow => "JSONCompactStringsEachRow", + Self::JSONCompactStringsEachRowWithNames => "JSONCompactStringsEachRowWithNames", + Self::JSONCompactStringsEachRowWithNamesAndTypes => { + "JSONCompactStringsEachRowWithNamesAndTypes" + } + Self::JSONObjectEachRow => "JSONObjectEachRow", + Self::BSONEachRow => "BSONEachRow", + Self::TSKV => "TSKV", + Self::Pretty => "Pretty", + Self::PrettyNoEscapes => "PrettyNoEscapes", + Self::PrettyMonoBlock => "PrettyMonoBlock", + Self::PrettyNoEscapesMonoBlock => "PrettyNoEscapesMonoBlock", + Self::PrettyCompact => "PrettyCompact", + Self::PrettyCompactNoEscapes => "PrettyCompactNoEscapes", + Self::PrettyCompactMonoBlock => "PrettyCompactMonoBlock", + Self::PrettyCompactNoEscapesMonoBlock => "PrettyCompactNoEscapesMonoBlock", + Self::PrettySpace => "PrettySpace", + Self::PrettySpaceNoEscapes => "PrettySpaceNoEscapes", + Self::PrettySpaceMonoBlock => "PrettySpaceMonoBlock", + Self::PrettySpaceNoEscapesMonoBlock => "PrettySpaceNoEscapesMonoBlock", + Self::Prometheus => "Prometheus", + Self::Protobuf => "Protobuf", + Self::ProtobufSingle => "ProtobufSingle", + Self::ProtobufList => "ProtobufList", + Self::Avro => "Avro", + Self::Parquet => "Parquet", + Self::Arrow => "Arrow", + Self::ArrowStream => "ArrowStream", + Self::ORC => "ORC", + Self::Npy => "Npy", + Self::RowBinary => "RowBinary", + Self::RowBinaryWithNames => "RowBinaryWithNames", + Self::RowBinaryWithNamesAndTypes => "RowBinaryWithNamesAndTypes", + Self::Native => "Native", + Self::Null => "Null", + Self::XML => "XML", + Self::CapnProto => "CapnProto", + Self::LineAsString => "LineAsString", + Self::RawBLOB => "RawBLOB", + Self::MsgPack => "MsgPack", + Self::Markdown => "Markdown", + Self::Vertical => "Vertical", + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 23fbb29..2c3e606 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,25 +1,58 @@ - -mod basic; -#[allow(dead_code, unused, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod arg; +#[allow( + dead_code, + unused, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] mod bindings; -mod builder; -mod session; - -pub use basic::*; -pub use session::*; -pub use builder::*; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("An unknown error has occurred")] - Unknown, - #[error("Invalid data: {0}")] - InvalidData(String), - #[error("Invalid path")] - PathError, - #[error(transparent)] - Io(#[from] std::io::Error), - #[error("Insufficient dir permissions")] - InsufficientPermissions, - -} \ No newline at end of file +pub mod error; +pub mod format; +pub mod log_level; +pub mod query_result; +pub mod session; + +use std::ffi::{c_char, CString}; + +use crate::arg::Arg; +use crate::error::Error; +use crate::query_result::QueryResult; + +pub fn execute(query: &str, query_args: Option<&[Arg]>) -> Result, Error> { + let mut argv = Vec::with_capacity(query_args.as_ref().map_or(0, |v| v.len()) + 2); + argv.push(arg_clickhouse()?.into_raw()); + + if let Some(args) = query_args { + for arg in args { + argv.push(arg.to_cstring()?.into_raw()); + } + } + + argv.push(arg_query(query)?.into_raw()); + call_chdb(argv) +} + +fn call_chdb(mut argv: Vec<*mut c_char>) -> Result, Error> { + let argc = argv.len() as i32; + let argv = argv.as_mut_ptr(); + let result_ptr = unsafe { bindings::query_stable_v2(argc, argv) }; + + if result_ptr.is_null() { + return Ok(None); + } + + Ok(Some(QueryResult(result_ptr).check_error()?)) +} + +fn arg_clickhouse() -> Result { + Ok(CString::new("clickhouse")?) +} + +fn arg_data_path(value: &str) -> Result { + Ok(CString::new(format!("--path={}", value))?) +} + +fn arg_query(value: &str) -> Result { + Ok(CString::new(format!("--query={}", value))?) +} diff --git a/src/log_level.rs b/src/log_level.rs new file mode 100644 index 0000000..ebe8c09 --- /dev/null +++ b/src/log_level.rs @@ -0,0 +1,20 @@ +#[derive(Debug, Clone, Copy)] +pub enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, +} + +impl LogLevel { + pub const fn as_str(self) -> &'static str { + match self { + Self::Trace => "trace", + Self::Debug => "debug", + Self::Info => "information", + Self::Warn => "warning", + Self::Error => "error", + } + } +} diff --git a/src/query_result.rs b/src/query_result.rs new file mode 100644 index 0000000..0d1f331 --- /dev/null +++ b/src/query_result.rs @@ -0,0 +1,63 @@ +use core::slice; +use std::borrow::Cow; +use std::ffi::CStr; +use std::time::Duration; + +use crate::bindings; +use crate::error::Error; + +#[derive(Clone)] +pub struct QueryResult(pub(crate) *mut bindings::local_result_v2); + +impl QueryResult { + pub fn data_utf8(&self) -> Result { + String::from_utf8(self.data_ref().to_vec()) + .map_err(|e| Error::NonUtf8Sequence(e.to_string())) + } + + pub fn data_utf8_lossy<'a>(&'a self) -> Cow<'a, str> { + String::from_utf8_lossy(self.data_ref()) + } + + pub fn data_utf8_unchecked(&self) -> String { + unsafe { String::from_utf8_unchecked(self.data_ref().to_vec()) } + } + + pub fn data_ref(&self) -> &[u8] { + let buf = unsafe { (*self.0).buf }; + let len = unsafe { (*self.0).len }; + let bytes: &[u8] = unsafe { slice::from_raw_parts(buf as *const u8, len) }; + bytes + } + + pub fn rows_read(&self) -> u64 { + (unsafe { *self.0 }).rows_read + } + + pub fn bytes_read(&self) -> u64 { + unsafe { (*self.0).bytes_read } + } + + pub fn elapsed(&self) -> Duration { + let elapsed = unsafe { (*self.0).elapsed }; + Duration::from_secs_f64(elapsed) + } + + pub(crate) fn check_error(self) -> Result { + let err_ptr = unsafe { (*self.0).error_message }; + + if err_ptr.is_null() { + return Ok(self); + } + + Err(Error::QueryError(unsafe { + CStr::from_ptr(err_ptr).to_string_lossy().to_string() + })) + } +} + +impl Drop for QueryResult { + fn drop(&mut self) { + unsafe { bindings::free_result_v2(self.0) }; + } +} diff --git a/src/session.rs b/src/session.rs index 16e6a80..0c1309c 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,40 +1,115 @@ -use std::ffi::{c_char, CString}; +use std::ffi::CString; +use std::fs; +use std::path::PathBuf; -use crate::{LocalResult, bindings}; +use crate::arg::Arg; +use crate::arg_clickhouse; +use crate::arg_data_path; +use crate::arg_query; +use crate::call_chdb; +use crate::error::Error; +use crate::query_result::QueryResult; +pub struct SessionBuilder<'a> { + data_path: PathBuf, + default_args: Vec>, + auto_cleanup: bool, +} + +#[derive(Clone)] pub struct Session { - pub(crate) format: String, - pub(crate) data_path: String, - pub(crate) udf_path: String, - pub(crate) log_level: String, + default_args: Vec, + data_path: String, + auto_cleanup: bool, +} + +impl<'a> SessionBuilder<'a> { + pub fn new() -> Self { + let mut data_path = std::env::current_dir().unwrap(); + data_path.push("chdb"); + + Self { + data_path, + default_args: Vec::new(), + auto_cleanup: false, + } + } + + pub fn with_data_path(mut self, path: impl Into) -> Self { + self.data_path = path.into(); + self + } + + pub fn with_arg(mut self, arg: Arg<'a>) -> Self { + self.default_args.push(arg); + self + } + + /// If set Session will delete data directory before it is dropped. + pub fn with_auto_cleanup(mut self, value: bool) -> Self { + self.auto_cleanup = value; + self + } + + pub fn build(self) -> Result { + let data_path = self.data_path.to_str().ok_or(Error::PathError)?.to_string(); + + fs::create_dir_all(&self.data_path)?; + if fs::metadata(&self.data_path)?.permissions().readonly() { + return Err(Error::InsufficientPermissions); + } + + let mut default_args = Vec::with_capacity(self.default_args.len() + 2); + default_args.push(arg_clickhouse()?); + default_args.push(arg_data_path(&data_path)?); + + for default_arg in self.default_args { + default_args.push(default_arg.to_cstring()?); + } + + Ok(Session { + data_path, + default_args, + auto_cleanup: self.auto_cleanup, + }) + } +} + +impl<'a> Default for SessionBuilder<'a> { + fn default() -> Self { + Self::new() + } } impl Session { - pub fn execute(&self, query: impl Into) -> Option { - let argv = vec![ - "clickhouse".to_string(), - "--multiquery".to_string(), - format!("--output-format={}", self.format), - format!("--query={}", query.into()), - format!("--path={}", self.data_path), - format!("--log-level={}", self.log_level) -// format!("--user_scripts_path={}", self.udf_path), -// format!("--user_defined_executable_functions_config={}/*.xml", self.udf_path), - ]; - - let argc = argv.len() as i32; - - let mut argv: Vec<*mut c_char> = argv - .into_iter() - .map(|arg| CString::new(arg).unwrap().into_raw()) - .collect(); - - let argv = argv.as_mut_ptr(); - let local = unsafe { bindings::query_stable(argc, argv) }; - if local.is_null() { - return None + pub fn execute( + &self, + query: &str, + query_args: Option<&[Arg]>, + ) -> Result, Error> { + let mut argv = Vec::with_capacity( + self.default_args.len() + query_args.as_ref().map_or(0, |v| v.len()) + 1, + ); + + for arg in &self.default_args { + argv.push(arg.clone().into_raw()) + } + + if let Some(args) = query_args { + for arg in args { + argv.push(arg.to_cstring()?.into_raw()); + } + } + + argv.push(arg_query(query)?.into_raw()); + call_chdb(argv) + } +} + +impl Drop for Session { + fn drop(&mut self) { + if self.auto_cleanup { + fs::remove_dir_all(&self.data_path).ok(); } - - Some(LocalResult { local }) } } diff --git a/tests/examples.rs b/tests/examples.rs new file mode 100644 index 0000000..57b7252 --- /dev/null +++ b/tests/examples.rs @@ -0,0 +1,79 @@ +use chdb_rust::arg::Arg; +use chdb_rust::execute; +use chdb_rust::format::InputFormat; +use chdb_rust::format::OutputFormat; +use chdb_rust::log_level::LogLevel; +use chdb_rust::session::SessionBuilder; + +#[test] +fn stateful() { + // + // Create session. + // + + let session = SessionBuilder::new() + .with_data_path("/tmp/chdb") + .with_arg(Arg::LogLevel(LogLevel::Debug)) + .with_arg(Arg::Custom("priority".into(), Some("1".into()))) + .with_auto_cleanup(true) + .build() + .unwrap(); + + // + // Create database. + // + + session + .execute("CREATE DATABASE demo; USE demo", Some(&[Arg::MultiQuery])) + .unwrap(); + + // + // Create table. + // + + session + .execute( + "CREATE TABLE logs (id UInt64, msg String) ENGINE = MergeTree ORDER BY id", + None, + ) + .unwrap(); + + // + // Insert into table. + // + + session + .execute("INSERT INTO logs (id, msg) VALUES (1, 'test')", None) + .unwrap(); + + // + // Select from table. + // + + let result = session + .execute( + "SELECT * FROM logs", + Some(&[Arg::OutputFormat(OutputFormat::JSONEachRow)]), + ) + .unwrap() + .unwrap(); + + assert_eq!(result.data_utf8_lossy(), "{\"id\":1,\"msg\":\"test\"}\n"); +} + +#[test] +fn stateless() { + let query = format!( + "SELECT * FROM file('tests/logs.csv', {})", + InputFormat::CSV.as_str() + ); + + let result = execute( + &query, + Some(&[Arg::OutputFormat(OutputFormat::JSONEachRow)]), + ) + .unwrap() + .unwrap(); + + assert_eq!(result.data_utf8_lossy(), "{\"id\":1,\"msg\":\"test\"}\n"); +} diff --git a/tests/logs.csv b/tests/logs.csv new file mode 100644 index 0000000..ee08214 --- /dev/null +++ b/tests/logs.csv @@ -0,0 +1,2 @@ +id,msg +1,test \ No newline at end of file diff --git a/update_libchdb.sh b/update_libchdb.sh index fee5ce5..e23f39a 100755 --- a/update_libchdb.sh +++ b/update_libchdb.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e +cd $(dirname "${BASH_SOURCE[0]}") # Get the newest release version LATEST_RELEASE=$(curl --silent "https://api.github.com/repos/chdb-io/chdb/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')