diff --git a/Cargo.lock b/Cargo.lock index 782b2b643de..da1918faae4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,62 +202,32 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1bb018b6960c87fd9d025009820406f74e83281185a8bdcb44880d2aa5c9a87" dependencies = [ - "arrow-arith 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-cast 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", "arrow-csv", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-data", "arrow-ipc", "arrow-json", - "arrow-ord 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-row 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-string 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", "pyo3", ] -[[package]] -name = "arrow" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-arith 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-cast 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-ord 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-row 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-select 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-string 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", -] - [[package]] name = "arrow-arith" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44de76b51473aa888ecd6ad93ceb262fb8d40d1f1154a4df2f069b3590aa7575" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono", - "num", -] - -[[package]] -name = "arrow-arith" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", "chrono", "num", ] @@ -269,9 +239,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ed77e22744475a9a53d00026cf8e166fe73cf42d89c4c4ae63607ee1cfcc3f" dependencies = [ "ahash 0.8.12", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", + "arrow-data", + "arrow-schema", "chrono", "chrono-tz", "half", @@ -279,21 +249,6 @@ dependencies = [ "num", ] -[[package]] -name = "arrow-array" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "ahash 0.8.12", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "chrono", - "half", - "hashbrown 0.15.4", - "num", -] - [[package]] name = "arrow-buffer" version = "55.1.0" @@ -305,47 +260,17 @@ dependencies = [ "num", ] -[[package]] -name = "arrow-buffer" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "bytes", - "half", - "num", -] - [[package]] name = "arrow-cast" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f39e1d774ece9292697fcbe06b5584401b26bd34be1bec25c33edae65c2420ff" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atoi", - "base64", - "chrono", - "comfy-table", - "half", - "lexical-core", - "num", - "ryu", -] - -[[package]] -name = "arrow-cast" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-select 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", "atoi", "base64", "chrono", @@ -362,9 +287,9 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9055c972a07bf12c2a827debfd34f88d3b93da1941d36e1d9fee85eebe38a12a" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-cast 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-cast", + "arrow-schema", "chrono", "csv", "csv-core", @@ -378,19 +303,8 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf75ac27a08c7f48b88e5c923f267e980f27070147ab74615ad85b5c5f90473d" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "half", - "num", -] - -[[package]] -name = "arrow-data" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-buffer", + "arrow-schema", "half", "num", ] @@ -401,10 +315,10 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a222f0d93772bd058d1268f4c28ea421a603d66f7979479048c429292fac7b2e" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", "flatbuffers", "lz4_flex", ] @@ -415,11 +329,11 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9085342bbca0f75e8cb70513c0807cc7351f1fbf5cb98192a67d5e3044acb033" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-cast 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", "chrono", "half", "indexmap", @@ -437,23 +351,11 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2f1065a5cad7b9efa9e22ce5747ce826aa3855766755d4904535123ef431e7" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrow-ord" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-select 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", ] [[package]] @@ -462,22 +364,10 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3703a0e3e92d23c3f756df73d2dc9476873f873a76ae63ef9d3de17fda83b2d8" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "half", -] - -[[package]] -name = "arrow-row" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", "half", ] @@ -492,14 +382,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "arrow-schema" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "bitflags", -] - [[package]] name = "arrow-select" version = "55.1.0" @@ -507,23 +389,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24b7b85575702b23b85272b01bc1c25a01c9b9852305e5d0078c79ba25d995d4" dependencies = [ "ahash 0.8.12", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num", -] - -[[package]] -name = "arrow-select" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "ahash 0.8.12", - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", "num", ] @@ -533,27 +402,11 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9260fddf1cdf2799ace2b4c2fc0356a9789fa7551e0953e35435536fecefebbd" dependencies = [ - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr", - "num", - "regex", - "regex-syntax 0.8.5", -] - -[[package]] -name = "arrow-string" -version = "55.1.0" -source = "git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027#b5cde3ff972457fcf0d1b1b11a120af10bdaa027" -dependencies = [ - "arrow-array 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-buffer 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-data 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-schema 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "arrow-select 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", "memchr", "num", "regex", @@ -657,9 +510,9 @@ name = "bench-vortex" version = "0.1.0" dependencies = [ "anyhow", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-schema", + "arrow-select", "async-trait", "bytes", "bzip2", @@ -1701,9 +1554,9 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc6cb8c2c81eada072059983657d6c9caf3fddefc43b4a65551d243253254a96" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "arrow-ipc", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-schema", "async-trait", "bytes", "chrono", @@ -1750,7 +1603,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7be8d1b627843af62e447396db08fe1372d882c0eb8d0ea655fd1fbc33120ee" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "dashmap", "datafusion-common", @@ -1776,7 +1629,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38ab16c5ae43f65ee525fc493ceffbc41f40dee38b01f643dfcfc12959e92038" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "datafusion-catalog", "datafusion-common", @@ -1800,7 +1653,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3d56b2ac9f476b93ca82e4ef5fb00769c8a3f248d12b4965af7e27635fa7e12" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "arrow-ipc", "base64", "half", @@ -1833,7 +1686,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b77523c95c89d2a7eb99df14ed31390e04ab29b43ff793e562bdc1716b07e17b" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "bytes", "chrono", @@ -1863,7 +1716,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40d25c5e2c0ebe8434beeea997b8e88d55b3ccc0d19344293f2373f65bc524fc" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "bytes", "datafusion-catalog", @@ -1888,7 +1741,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dc6959e1155741ab35369e1dc7673ba30fc45ed568fad34c01b7cb1daeb4d4c" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "bytes", "datafusion-catalog", @@ -1913,7 +1766,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7a6afdfe358d70f4237f60eaef26ae5a1ce7cb2c469d02d5fc6c7fd5d84e58b" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "bytes", "datafusion-catalog", @@ -1950,7 +1803,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670da1d45d045eee4c2319b8c7ea57b26cf48ab77b630aaa50b779e406da476a" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "dashmap", "datafusion-common", "datafusion-expr", @@ -1969,7 +1822,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a577f64bdb7e2cc4043cd97f8901d8c504711fde2dbcb0887645b00d7c660b" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "chrono", "datafusion-common", "datafusion-doc", @@ -1989,7 +1842,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b7916806ace3e9f41884f230f7f38ebf0e955dfbd88266da1826f29a0b9a6a" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "indexmap", "itertools 0.14.0", @@ -2002,8 +1855,8 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb31c9dc73d3e0c365063f91139dc273308f8a8e124adda9898db8085d68357" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", + "arrow-buffer", "base64", "chrono", "datafusion-common", @@ -2028,7 +1881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebb72c6940697eaaba9bd1f746a697a07819de952b817e3fb841fb75331ad5d4" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-doc", "datafusion-execution", @@ -2049,7 +1902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7fdc54656659e5ecd49bf341061f4156ab230052611f4f3609612a0da259696" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-expr-common", "datafusion-physical-expr-common", @@ -2061,7 +1914,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de2fc6c2946da5cab8364fb28b5cac3115f0f3a87960b235ed031c3f7e2e639b" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "datafusion-catalog", "datafusion-common", @@ -2077,7 +1930,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5746548a8544870a119f556543adcd88fe0ba6b93723fe78ad0439e0fbb8b4" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-doc", "datafusion-expr", @@ -2116,7 +1969,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03cfaacf06445dc3bbc1e901242d2a44f2cae99a744f49f3fefddcee46240058" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "chrono", "datafusion-common", "datafusion-expr", @@ -2135,7 +1988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1908034a89d7b2630898e06863583ae4c00a0dd310c1589ca284195ee3f7f8a6" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-expr", "datafusion-expr-common", @@ -2157,7 +2010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b7a12dd59ea07614b67dbb01d85254fbd93df45bcffa63495e11d3bdf847df" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-expr-common", "hashbrown 0.14.5", @@ -2170,7 +2023,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4371cc4ad33978cc2a8be93bd54a232d3f2857b50401a14631c0705f3f910aae" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "datafusion-common", "datafusion-execution", "datafusion-expr", @@ -2189,9 +2042,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc47bc33025757a5c11f2cd094c5b6b5ed87f46fa33c023e6fdfa25fcbfade23" dependencies = [ "ahash 0.8.12", - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-ord 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", + "arrow-ord", + "arrow-schema", "async-trait", "chrono", "datafusion-common", @@ -2218,7 +2071,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7485da32283985d6b45bd7d13a65169dcbe8c869e25d01b2cfbc425254b4b49" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "async-trait", "dashmap", "datafusion-common", @@ -2242,7 +2095,7 @@ version = "48.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a466b15632befddfeac68c125f0260f569ff315c6831538cbb40db754134e0df" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "bigdecimal", "datafusion-common", "datafusion-expr", @@ -2321,13 +2174,13 @@ checksum = "d3a5ccdfd6c5e7e2fea9c5cf256f2a08216047fab19c621c3da64e9ae4a1462d" name = "duckdb" version = "1.2.2" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "calamine", "cast", "fallible-iterator", "fallible-streaming-iterator", "hashlink", - "libduckdb-sys 1.2.2", + "libduckdb-sys", "memchr", "num", "num-integer", @@ -2336,25 +2189,6 @@ dependencies = [ "strum 0.25.0", ] -[[package]] -name = "duckdb" -version = "1.3.0" -source = "git+https://github.com/vortex-data/duckdb-rs?rev=247ffb36c41bd44bb18e586bdd6640a95783bb5e#247ffb36c41bd44bb18e586bdd6640a95783bb5e" -dependencies = [ - "arrow 55.1.0 (git+https://github.com/vortex-data/arrow-rs.git?rev=b5cde3ff972457fcf0d1b1b11a120af10bdaa027)", - "calamine", - "cast", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libduckdb-sys 1.3.0", - "num", - "num-integer", - "rust_decimal", - "smallvec", - "strum 0.25.0", -] - [[package]] name = "dyn-hash" version = "0.2.2" @@ -3528,20 +3362,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libduckdb-sys" -version = "1.3.0" -source = "git+https://github.com/vortex-data/duckdb-rs?rev=247ffb36c41bd44bb18e586bdd6640a95783bb5e#247ffb36c41bd44bb18e586bdd6640a95783bb5e" -dependencies = [ - "autocfg", - "flate2", - "pkg-config", - "serde", - "serde_json", - "tar", - "vcpkg", -] - [[package]] name = "libfuzzer-sys" version = "0.4.9" @@ -4285,13 +4105,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be7b2d778f6b841d37083ebdf32e33a524acde1266b5884a8ca29bf00dfa1231" dependencies = [ "ahash 0.8.12", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-cast 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", "arrow-ipc", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-schema", + "arrow-select", "base64", "brotli", "bytes", @@ -6402,7 +6222,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" name = "vortex" version = "0.1.0" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "itertools 0.14.0", "parquet", "tokio", @@ -6464,15 +6284,15 @@ version = "0.1.0" dependencies = [ "arbitrary", "arcref", - "arrow-arith 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-cast 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-data 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-ord 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-select 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-string 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "arrow-string", "cfg-if", "codspeed-divan-compat", "enum-iterator", @@ -6511,7 +6331,7 @@ dependencies = [ name = "vortex-btrblocks" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "codspeed-divan-compat", "env_logger", "getrandom 0.3.3", @@ -6542,7 +6362,7 @@ dependencies = [ name = "vortex-buffer" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "bytes", "codspeed-divan-compat", "compio", @@ -6556,7 +6376,7 @@ dependencies = [ name = "vortex-bytebool" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "num-traits", "vortex-array", "vortex-buffer", @@ -6621,7 +6441,7 @@ dependencies = [ name = "vortex-dict" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "codspeed-divan-compat", "num-traits", "prost", @@ -6642,7 +6462,7 @@ name = "vortex-dtype" version = "0.1.0" dependencies = [ "arbitrary", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-schema", "flatbuffers", "half", "itertools 0.14.0", @@ -6664,7 +6484,7 @@ dependencies = [ name = "vortex-duckdb" version = "0.1.0" dependencies = [ - "duckdb 1.2.2", + "duckdb", "itertools 0.14.0", "num-traits", "vortex", @@ -6674,12 +6494,12 @@ dependencies = [ name = "vortex-duckdb-ext" version = "0.1.0" dependencies = [ + "anyhow", "bindgen", "bitvec", "cbindgen", "cc", "crossbeam-queue", - "duckdb 1.3.0", "glob", "itertools 0.14.0", "log", @@ -6697,7 +6517,7 @@ dependencies = [ name = "vortex-error" version = "0.1.0" dependencies = [ - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-schema", "flatbuffers", "jiff", "object_store", @@ -6736,7 +6556,7 @@ name = "vortex-fastlanes" version = "0.1.0" dependencies = [ "arrayref", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "codspeed-divan-compat", "fastlanes", "itertools 0.14.0", @@ -6758,7 +6578,7 @@ dependencies = [ name = "vortex-ffi" version = "0.1.0" dependencies = [ - "duckdb 1.2.2", + "duckdb", "futures", "itertools 0.14.0", "log", @@ -6848,8 +6668,8 @@ dependencies = [ name = "vortex-fuzz" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-ord 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", + "arrow-ord", "futures-util", "libfuzzer-sys", "strum 0.25.0", @@ -6910,7 +6730,7 @@ dependencies = [ name = "vortex-jni" version = "0.1.0" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "jni", "log", "object_store", @@ -6928,9 +6748,9 @@ name = "vortex-layout" version = "0.1.0" dependencies = [ "arcref", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-schema 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-buffer", + "arrow-schema", "async-stream", "async-trait", "bit-vec", @@ -6971,7 +6791,7 @@ dependencies = [ name = "vortex-mask" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "itertools 0.14.0", "vortex-error", ] @@ -7012,7 +6832,7 @@ dependencies = [ name = "vortex-python" version = "0.1.0" dependencies = [ - "arrow 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow", "futures", "itertools 0.14.0", "log", @@ -7030,7 +6850,7 @@ dependencies = [ name = "vortex-runend" version = "0.1.0" dependencies = [ - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-buffer", "codspeed-divan-compat", "itertools 0.14.0", "num-traits", @@ -7049,8 +6869,8 @@ name = "vortex-scalar" version = "0.1.0" dependencies = [ "arbitrary", - "arrow-array 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrow-buffer 55.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrow-array", + "arrow-buffer", "bytes", "itertools 0.14.0", "num-traits", diff --git a/bench-vortex/src/engines/ddb2/mod.rs b/bench-vortex/src/engines/ddb2/mod.rs index 6797130b238..375a763701f 100644 --- a/bench-vortex/src/engines/ddb2/mod.rs +++ b/bench-vortex/src/engines/ddb2/mod.rs @@ -43,7 +43,7 @@ impl DuckDBCtx { // TODO: handle multiple queries trace!("execute duckdb query: {}", query); let time_instant = Instant::now(); - self.connection.execute(query)?; + self.connection.query(query)?; let query_time = time_instant.elapsed(); trace!("query completed in {:.3}s", query_time.as_secs_f64()); diff --git a/vortex-duckdb-ext/Cargo.toml b/vortex-duckdb-ext/Cargo.toml index 5a71085f273..1861b7ed527 100644 --- a/vortex-duckdb-ext/Cargo.toml +++ b/vortex-duckdb-ext/Cargo.toml @@ -20,14 +20,9 @@ path = "src/lib.rs" crate-type = ["staticlib", "cdylib", "rlib"] [dependencies] +anyhow = { workspace = true } bitvec = { workspace = true } crossbeam-queue = { workspace = true } -# duckdb-rs using arrow-rs v55.1.0 with decimal32/64 types cherry-picked on top -# (https://github.com/apache/arrow-rs/pull/7098) this is will be removed once we -# hit 56 (hopefully in july). required since duckdb returns decimal32/64 from scans. -duckdb = { git = "https://github.com/vortex-data/duckdb-rs", rev = "247ffb36c41bd44bb18e586bdd6640a95783bb5e", features = [ - "vtab-full", -] } glob = { workspace = true } itertools = { workspace = true } log = { workspace = true } diff --git a/vortex-duckdb-ext/src/duckdb/connection.rs b/vortex-duckdb-ext/src/duckdb/connection.rs index 8c456ea17e7..ec0d213442b 100644 --- a/vortex-duckdb-ext/src/duckdb/connection.rs +++ b/vortex-duckdb-ext/src/duckdb/connection.rs @@ -1,8 +1,9 @@ +use std::ffi::CStr; use std::ptr; use vortex::error::{VortexResult, vortex_err}; -use crate::duckdb::Database; +use crate::duckdb::{Database, QueryResult}; use crate::{cpp, duckdb_try, wrapper}; wrapper!( @@ -22,8 +23,8 @@ impl Connection { Ok(unsafe { Self::own(ptr) }) } - /// Execute SQL query and return the row count. - pub fn execute_and_get_row_count(&self, query: &str) -> VortexResult { + /// Execute SQL query and return the result. + pub fn query(&self, query: &str) -> VortexResult { let mut result: cpp::duckdb_result = unsafe { std::mem::zeroed() }; let query_cstr = std::ffi::CString::new(query).map_err(|_| vortex_err!("Invalid query string"))?; @@ -36,9 +37,7 @@ impl Connection { if error_ptr.is_null() { "Unknown DuckDB error".to_string() } else { - std::ffi::CStr::from_ptr(error_ptr) - .to_string_lossy() - .into_owned() + CStr::from_ptr(error_ptr).to_string_lossy().into_owned() } }; @@ -46,38 +45,194 @@ impl Connection { return Err(vortex_err!("Failed to execute query: {}", error_msg)); } - let row_count = unsafe { cpp::duckdb_row_count(&mut result).try_into()? }; - unsafe { cpp::duckdb_destroy_result(&mut result) }; + Ok(unsafe { QueryResult::new(result) }) + } +} - Ok(row_count) +#[cfg(test)] +mod tests { + use super::*; + + fn test_connection() -> VortexResult { + let db = Database::open_in_memory()?; + db.connect() } - /// Execute SQL query. - pub fn execute(&self, query: &str) -> VortexResult<()> { - let mut result: cpp::duckdb_result = unsafe { std::mem::zeroed() }; - let query_cstr = - std::ffi::CString::new(query).map_err(|_| vortex_err!("Invalid query string"))?; + #[test] + fn test_connection_creation() { + let conn = test_connection(); + assert!(conn.is_ok()); + } - let status = unsafe { cpp::duckdb_query(self.as_ptr(), query_cstr.as_ptr(), &mut result) }; + #[test] + fn test_execute_success() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT 1"); + assert!(result.is_ok()); + } - if status != cpp::duckdb_state::DuckDBSuccess { - let error_msg = unsafe { - let error_ptr = cpp::duckdb_result_error(&mut result); - if error_ptr.is_null() { - "Unknown DuckDB error".to_string() - } else { - std::ffi::CStr::from_ptr(error_ptr) - .to_string_lossy() - .into_owned() - } - }; + #[test] + fn test_execute_invalid_sql() { + let conn = test_connection().unwrap(); + let result = conn.query("INVALID SQL STATEMENT"); + assert!(result.is_err()); + let error_msg = result.unwrap_err().to_string(); + assert!(error_msg.contains("Failed to execute query")); + } - unsafe { cpp::duckdb_destroy_result(&mut result) }; - return Err(vortex_err!("Failed to execute query: {}", error_msg)); - } + #[test] + fn test_execute_with_null_bytes() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT\0 1"); + assert!(result.is_err()); + let error_msg = result.unwrap_err().to_string(); + assert!(error_msg.contains("Invalid query string")); + } + + #[test] + fn test_query_and_get_row_count_select() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT 1, 2, 3").unwrap(); + assert_eq!(result.row_count().unwrap(), 1); + } + + #[test] + fn test_query_and_get_row_count_create_table() { + let conn = test_connection().unwrap(); + + // CREATE TABLE should return 0 rows + let result = conn + .query("CREATE TABLE test (id INTEGER, name VARCHAR)") + .unwrap(); + assert_eq!(result.row_count().unwrap(), 0); + } + + #[test] + fn test_query_and_get_row_count_insert() { + let conn = test_connection().unwrap(); + conn.query("CREATE TABLE test (id INTEGER, name VARCHAR)") + .unwrap(); + + let result = conn + .query("INSERT INTO test VALUES (1, 'Alice'), (2, 'Bob')") + .unwrap(); + + assert_eq!(result.row_count().unwrap(), 2); + } + + #[test] + fn test_query_invalid_sql() { + let conn = test_connection().unwrap(); + let result = conn.query("INVALID SQL"); + assert!(result.is_err()); + } + + #[test] + fn test_query_single_value() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT 42").unwrap(); + + assert_eq!(result.column_count().unwrap(), 1); + assert_eq!(result.row_count().unwrap(), 1); + assert_eq!(result.get::(0, 0).unwrap(), 42); + } + + #[test] + fn test_query_multiple_rows() { + let conn = test_connection().unwrap(); + conn.query("CREATE TABLE test (id INTEGER)").unwrap(); + conn.query("INSERT INTO test VALUES (1), (2), (3)").unwrap(); + + let result = conn.query("SELECT id FROM test ORDER BY id").unwrap(); + + assert_eq!(result.column_count().unwrap(), 1); + assert_eq!(result.row_count().unwrap(), 3); + assert_eq!(result.get::(0, 0).unwrap(), 1); + assert_eq!(result.get::(0, 1).unwrap(), 2); + assert_eq!(result.get::(0, 2).unwrap(), 3); + } + + #[test] + fn test_query_multiple_columns() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT 1 as num, 'hello' as text").unwrap(); + + assert_eq!(result.column_count().unwrap(), 2); + assert_eq!(result.row_count().unwrap(), 1); + assert_eq!(result.column_name(0).unwrap(), "num"); + assert_eq!(result.column_name(1).unwrap(), "text"); + assert_eq!(result.get::(0, 0).unwrap(), 1); + assert_eq!(result.get::(1, 0).unwrap(), "hello"); + } + + #[test] + fn test_query_bounds_checking() { + let conn = test_connection().unwrap(); + let result = conn.query("SELECT 1").unwrap(); + + // Test row bounds + assert!(result.get::(0, 1).is_err()); + + // Test column bounds + assert!(result.get::(1, 0).is_err()); + } + + #[test] + fn test_query_column_types() { + let conn = test_connection().unwrap(); + let result = conn + .query("SELECT 1 as int_col, 'text' as str_col") + .unwrap(); + + assert_eq!(result.column_type(0), cpp::DUCKDB_TYPE::DUCKDB_TYPE_INTEGER); + assert_eq!(result.column_type(1), cpp::DUCKDB_TYPE::DUCKDB_TYPE_VARCHAR); + } + + #[test] + fn test_null_handling() { + let conn = test_connection().unwrap(); + let result = conn + .query("SELECT NULL as null_col, 1 as not_null_col") + .unwrap(); + + assert!(result.is_null(0, 0).unwrap()); + assert!(!result.is_null(1, 0).unwrap()); + } + + #[test] + fn test_type_conversion() { + let conn = test_connection().unwrap(); + let result = conn + .query("SELECT 42::TINYINT, 42::SMALLINT, 42::INTEGER, 42::BIGINT") + .unwrap(); + + assert_eq!(result.get::(0, 0).unwrap(), 42); // TINYINT -> i64 + assert_eq!(result.get::(1, 0).unwrap(), 42); // SMALLINT -> i64 + assert_eq!(result.get::(2, 0).unwrap(), 42); // INTEGER -> i64 + assert_eq!(result.get::(3, 0).unwrap(), 42); // BIGINT -> i64 + } + + #[test] + fn test_query_and_get_row_count_update() { + let conn = test_connection().unwrap(); + conn.query("CREATE TABLE test (id INTEGER, name VARCHAR)") + .unwrap(); + conn.query("INSERT INTO test VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')") + .unwrap(); + + let result = conn + .query("UPDATE test SET name = 'Updated' WHERE id <= 2") + .unwrap(); + assert_eq!(result.row_count().unwrap(), 2); + } - unsafe { cpp::duckdb_destroy_result(&mut result) }; + #[test] + fn test_query_and_get_row_count_delete() { + let conn = test_connection().unwrap(); + conn.query("CREATE TABLE test (id INTEGER)").unwrap(); + conn.query("INSERT INTO test VALUES (1), (2), (3)").unwrap(); - Ok(()) + let result = conn.query("DELETE FROM test WHERE id > 1").unwrap(); + assert_eq!(result.row_count().unwrap(), 2); } } diff --git a/vortex-duckdb-ext/src/duckdb/mod.rs b/vortex-duckdb-ext/src/duckdb/mod.rs index c4b7b770e08..ecd6c400fa1 100644 --- a/vortex-duckdb-ext/src/duckdb/mod.rs +++ b/vortex-duckdb-ext/src/duckdb/mod.rs @@ -4,6 +4,7 @@ mod data_chunk; mod database; mod expr; mod logical_type; +mod query_result; mod scalar_function; mod selection_vector; mod table_filter; @@ -20,6 +21,7 @@ pub use data_chunk::*; pub use database::*; pub use expr::*; pub use logical_type::*; +pub use query_result::*; pub use scalar_function::*; pub use selection_vector::*; pub use table_filter::*; diff --git a/vortex-duckdb-ext/src/duckdb/query_result.rs b/vortex-duckdb-ext/src/duckdb/query_result.rs new file mode 100644 index 00000000000..879dc6b10d3 --- /dev/null +++ b/vortex-duckdb-ext/src/duckdb/query_result.rs @@ -0,0 +1,262 @@ +use std::ffi::CStr; + +use vortex::error::{VortexResult, vortex_err}; + +use crate::{cpp, wrapper}; + +wrapper! { + /// A wrapper around a DuckDB query result. + #[derive(Debug)] + QueryResult, + *mut cpp::duckdb_result, + |ptr: &mut *mut cpp::duckdb_result| { + if !ptr.is_null() { + unsafe { + cpp::duckdb_destroy_result(&mut **ptr); + drop(Box::from_raw(*ptr)); + } + } + } +} + +impl QueryResult { + /// Create a new `QueryResult` from a `duckdb_result`. + /// + /// Takes ownership of the result and will destroy it on drop. + pub unsafe fn new(result: cpp::duckdb_result) -> Self { + let boxed = Box::new(result); + unsafe { Self::own(Box::into_raw(boxed)) } + } + + /// Check bounds for row and column indices. + fn check_bounds(&self, col_idx: usize, row_idx: usize) -> VortexResult<()> { + if row_idx >= self.row_count()? { + return Err(vortex_err!("Row index {} out of bounds", row_idx)); + } + if col_idx >= self.column_count()? { + return Err(vortex_err!("Column index {} out of bounds", col_idx)); + } + Ok(()) + } + + /// Get the number of columns in the result. + pub fn column_count(&self) -> VortexResult { + unsafe { + usize::try_from(cpp::duckdb_column_count(self.as_ptr())) + .map_err(|_| vortex_err!("Column count too large to fit in usize")) + } + } + + /// Get the number of rows in the result for SELECT operations, + /// or the number of affected rows for (INSERT/UPDATE/DELETE) operations. + pub fn row_count(&self) -> VortexResult { + unsafe { + let rows_changed = cpp::duckdb_rows_changed(self.as_ptr()); + if rows_changed > 0 { + // (INSERT, UPDATE, DELETE) - return affected rows + usize::try_from(rows_changed) + .map_err(|_| vortex_err!("Rows changed count too large to fit in usize")) + } else { + // SELECT - return result row count + usize::try_from(cpp::duckdb_row_count(self.as_ptr())) + .map_err(|_| vortex_err!("Row count too large to fit in usize")) + } + } + } + + /// Get the name of a column by index. + pub fn column_name(&self, col_idx: usize) -> VortexResult<&str> { + unsafe { + let name_ptr = cpp::duckdb_column_name(self.as_ptr(), col_idx as u64); + if name_ptr.is_null() { + return Err(vortex_err!("Invalid column index: {}", col_idx)); + } + CStr::from_ptr(name_ptr) + .to_str() + .map_err(|_| vortex_err!("Invalid UTF-8 in column name")) + } + } + + /// Get the type of a column by index. + pub fn column_type(&self, col_idx: usize) -> cpp::DUCKDB_TYPE { + unsafe { cpp::duckdb_column_type(self.as_ptr(), col_idx as u64) } + } + + /// Try to get a value at the specified column and row index for the specified type. + pub fn get(&self, col_idx: usize, row_idx: usize) -> VortexResult + where + T: TryFrom, + { + self.check_bounds(col_idx, row_idx)?; + + let value = unsafe { QueryResultCell::new(self.as_ptr(), col_idx, row_idx) }; + + T::try_from(value) + } + + /// Check if a value is null. + pub fn is_null(&self, col_idx: usize, row_idx: usize) -> VortexResult { + self.check_bounds(col_idx, row_idx)?; + + // Get nullmask data for the column + unsafe { + let nullmask_ptr = cpp::duckdb_nullmask_data(self.as_ptr(), col_idx as u64); + if nullmask_ptr.is_null() { + // No nullmask means no nulls + return Ok(false); + } + + // Access the bool array directly + let is_null = *nullmask_ptr.add(row_idx); + Ok(is_null) + } + } +} + +/// A result cell returned by a DuckDB query. +pub struct QueryResultCell { + result_ptr: *mut cpp::duckdb_result, + col_idx: u64, + row_idx: u64, + column_type: cpp::DUCKDB_TYPE, +} + +impl QueryResultCell { + unsafe fn new(result_ptr: *mut cpp::duckdb_result, col_idx: usize, row_idx: usize) -> Self { + let column_type = unsafe { cpp::duckdb_column_type(result_ptr, col_idx as u64) }; + Self { + result_ptr, + col_idx: col_idx as u64, + row_idx: row_idx as u64, + column_type, + } + } + + pub fn column_type(&self) -> cpp::DUCKDB_TYPE { + self.column_type + } +} + +// TODO(Alex): Revisit the marshalling logic to consider going through arrow by +// calling `duckdb_query_arrow`. Most likely the marshalling code below will go away. + +impl TryFrom for i32 { + type Error = vortex::error::VortexError; + + fn try_from(entry: QueryResultCell) -> Result { + match entry.column_type { + cpp::DUCKDB_TYPE::DUCKDB_TYPE_INTEGER => Ok(unsafe { + cpp::duckdb_value_int32(entry.result_ptr, entry.col_idx, entry.row_idx) + }), + cpp::DUCKDB_TYPE::DUCKDB_TYPE_TINYINT => { + let val = unsafe { + cpp::duckdb_value_int8(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as i32) + } + cpp::DUCKDB_TYPE::DUCKDB_TYPE_SMALLINT => { + let val = unsafe { + cpp::duckdb_value_int16(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as i32) + } + _ => Err(vortex_err!("Cannot convert {:?} to i32", entry.column_type)), + } + } +} + +impl TryFrom for i64 { + type Error = vortex::error::VortexError; + + fn try_from(entry: QueryResultCell) -> Result { + match entry.column_type { + cpp::DUCKDB_TYPE::DUCKDB_TYPE_HUGEINT => unsafe { + let val = cpp::duckdb_value_hugeint(entry.result_ptr, entry.col_idx, entry.row_idx); + // Convert hugeint to i64 - use lower part if it fits, otherwise error. + if val.upper == 0 || (val.upper == -1 && (val.lower as i64) < 0) { + Ok(val.lower as i64) + } else { + Err(vortex_err!("HUGEINT value too large to fit in i64")) + } + }, + cpp::DUCKDB_TYPE::DUCKDB_TYPE_BIGINT => Ok(unsafe { + cpp::duckdb_value_int64(entry.result_ptr, entry.col_idx, entry.row_idx) + }), + cpp::DUCKDB_TYPE::DUCKDB_TYPE_INTEGER => { + let val = unsafe { + cpp::duckdb_value_int32(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as i64) + } + cpp::DUCKDB_TYPE::DUCKDB_TYPE_TINYINT => { + let val = unsafe { + cpp::duckdb_value_int8(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as i64) + } + cpp::DUCKDB_TYPE::DUCKDB_TYPE_SMALLINT => { + let val = unsafe { + cpp::duckdb_value_int16(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as i64) + } + _ => Err(vortex_err!("Cannot convert {:?} to i64", entry.column_type)), + } + } +} + +impl TryFrom for f32 { + type Error = vortex::error::VortexError; + + fn try_from(entry: QueryResultCell) -> Result { + match entry.column_type { + cpp::DUCKDB_TYPE::DUCKDB_TYPE_FLOAT => Ok(unsafe { + cpp::duckdb_value_float(entry.result_ptr, entry.col_idx, entry.row_idx) + }), + _ => Err(vortex_err!("Cannot convert {:?} to f32", entry.column_type)), + } + } +} + +impl TryFrom for f64 { + type Error = vortex::error::VortexError; + + fn try_from(entry: QueryResultCell) -> Result { + match entry.column_type { + cpp::DUCKDB_TYPE::DUCKDB_TYPE_DOUBLE => Ok(unsafe { + cpp::duckdb_value_double(entry.result_ptr, entry.col_idx, entry.row_idx) + }), + cpp::DUCKDB_TYPE::DUCKDB_TYPE_FLOAT => { + let val = unsafe { + cpp::duckdb_value_float(entry.result_ptr, entry.col_idx, entry.row_idx) + }; + Ok(val as f64) + } + _ => Err(vortex_err!("Cannot convert {:?} to f64", entry.column_type)), + } + } +} + +impl TryFrom for String { + type Error = vortex::error::VortexError; + + fn try_from(entry: QueryResultCell) -> Result { + match entry.column_type { + cpp::DUCKDB_TYPE::DUCKDB_TYPE_VARCHAR => unsafe { + let str_ptr = + cpp::duckdb_value_varchar(entry.result_ptr, entry.col_idx, entry.row_idx); + if str_ptr.is_null() { + return Ok(String::new()); + } + let c_str = CStr::from_ptr(str_ptr); + let result = c_str.to_string_lossy().into_owned(); + cpp::duckdb_free(str_ptr as *mut std::ffi::c_void); + Ok(result) + }, + _ => Err(vortex_err!( + "Cannot convert {:?} to String", + entry.column_type + )), + } + } +} diff --git a/vortex-duckdb-ext/src/lib.rs b/vortex-duckdb-ext/src/lib.rs index ffdafe66b1f..20af388d573 100644 --- a/vortex-duckdb-ext/src/lib.rs +++ b/vortex-duckdb-ext/src/lib.rs @@ -28,7 +28,7 @@ mod scan; /// cbindgen:ignore mod cpp; #[cfg(test)] -mod scan_tests; +mod vortex_scan_tests; /// Initialize the Vortex extension by registering the `vortex_scan` function. pub fn init(conn: &Connection) -> VortexResult<()> { diff --git a/vortex-duckdb-ext/src/scan_tests.rs b/vortex-duckdb-ext/src/scan_tests.rs deleted file mode 100644 index a74ed58727b..00000000000 --- a/vortex-duckdb-ext/src/scan_tests.rs +++ /dev/null @@ -1,243 +0,0 @@ -use std::path::Path; - -use duckdb::Connection; -use tempfile::NamedTempFile; -use vortex::IntoArray; -use vortex::arrays::{BoolArray, ConstantArray, PrimitiveArray, StructArray, VarBinArray}; -use vortex::file::VortexWriteOptions; -use vortex::scalar::Scalar; -use vortex::validity::Validity; - -use crate::duckdb::Database; - -fn database_connection() -> Connection { - let db = Database::open_in_memory().unwrap(); - let connection = db.connect().unwrap(); - crate::init(&connection).unwrap(); - unsafe { Connection::open_from_raw(db.as_ptr().cast()) }.unwrap() -} - -fn create_temp_file() -> NamedTempFile { - NamedTempFile::new().unwrap() -} - -async fn write_single_column_vortex_file(field_name: &str, array: impl IntoArray) -> NamedTempFile { - write_vortex_file([(field_name, array)].into_iter()).await -} - -async fn write_vortex_file( - iter: impl Iterator, impl IntoArray)>, -) -> NamedTempFile { - let temp_file_path = create_temp_file(); - - let struct_array = StructArray::try_from_iter(iter).unwrap(); - let file = tokio::fs::File::create(&temp_file_path).await.unwrap(); - VortexWriteOptions::default() - .write(file, struct_array.to_array_stream()) - .await - .unwrap(); - - temp_file_path -} - -fn scan_vortex_file_single_row(tmp_file: NamedTempFile, query: &str, col_idx: usize) -> T -where - T: duckdb::types::FromSql, -{ - let conn = database_connection(); - conn.prepare(query) - .unwrap() - .query_row([tmp_file.path().to_string_lossy()], |row| row.get(col_idx)) - .unwrap() -} - -fn scan_vortex_file( - tmp_file: NamedTempFile, - query: &str, - col_idx: usize, -) -> Result, String> -where - T: duckdb::types::FromSql, -{ - let conn = database_connection(); - conn.prepare(query) - .unwrap() - .query_and_then([tmp_file.path().to_string_lossy()], |row| row.get(col_idx)) - .unwrap() - .collect::, _>>() - .map_err(|e| e.to_string()) -} - -async fn write_vortex_file_to_dir( - dir: &Path, - field_name: &str, - array: impl IntoArray, -) -> NamedTempFile { - let struct_array = StructArray::from_fields(&[(field_name, array.into_array())]).unwrap(); - let temp_file_path = tempfile::Builder::new() - .suffix(".vortex") - .tempfile_in(dir) - .unwrap(); - - let file = tokio::fs::File::create(&temp_file_path).await.unwrap(); - VortexWriteOptions::default() - .write(file, struct_array.to_array_stream()) - .await - .unwrap(); - - temp_file_path -} - -#[test] -fn test_scan_function_registration() { - let conn = database_connection(); - let result: String = conn - .prepare("SELECT function_name FROM duckdb_functions() WHERE function_name = 'vortex_scan'") - .unwrap() - .query_row([], |row| row.get(0)) - .unwrap(); - assert_eq!(&result, "vortex_scan"); -} - -#[tokio::test] -async fn test_vortex_scan_strings() { - let strings = VarBinArray::from(vec!["Hello", "Hi", "Hey"]); - let file = write_single_column_vortex_file("strings", strings).await; - let result: String = scan_vortex_file_single_row( - file, - "SELECT string_agg(strings, ',') FROM vortex_scan(?)", - 0, - ); - assert_eq!(result, "Hello,Hi,Hey"); -} - -#[tokio::test] -async fn test_vortex_scan_strings_contains() { - let strings = VarBinArray::from(vec!["Hello", "Hi", "Hey"]); - let file = write_single_column_vortex_file("strings", strings).await; - let result: String = scan_vortex_file_single_row( - file, - "SELECT string_agg(strings, ',') FROM vortex_scan(?) WHERE strings LIKE '%He%'", - 0, - ); - assert_eq!(result, "Hello,Hey"); -} - -#[tokio::test] -async fn test_vortex_scan_integers() { - let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); - let file = write_single_column_vortex_file("number", numbers).await; - let sum: i64 = scan_vortex_file_single_row(file, "SELECT SUM(number) FROM vortex_scan(?)", 0); - assert_eq!(sum, 138); -} - -#[tokio::test] -async fn test_vortex_scan_integers_in_list() { - let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); - let file = write_single_column_vortex_file("number", numbers).await; - let sum: i64 = scan_vortex_file_single_row( - file, - "SELECT SUM(number) FROM vortex_scan(?) WHERE number in (1, 42, -5)", - 0, - ); - assert_eq!(sum, 38); -} - -#[tokio::test] -async fn test_vortex_scan_integers_between() { - let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); - let file = write_single_column_vortex_file("number", numbers).await; - let sum: i64 = scan_vortex_file_single_row( - file, - "SELECT SUM(number) FROM vortex_scan(?) WHERE number > 0 and number < 100", - 0, - ); - assert_eq!(sum, 43); -} - -#[tokio::test] -async fn test_vortex_scan_floats() { - let values = PrimitiveArray::from_iter([1.5f64, -2.5, 0.0, 42.42]); - let file = write_single_column_vortex_file("value", values).await; - let count: i64 = scan_vortex_file_single_row( - file, - "SELECT COUNT(*) FROM vortex_scan(?) WHERE value > 0", - 0, - ); - assert_eq!(count, 2); -} - -#[tokio::test] -async fn test_vortex_scan_constant() { - let constant = ConstantArray::new(Scalar::from(42i32), 100); - let file = write_single_column_vortex_file("constant", constant).await; - let value: i32 = - scan_vortex_file_single_row(file, "SELECT constant FROM vortex_scan(?) LIMIT 1", 0); - assert_eq!(value, 42); -} - -#[tokio::test] -async fn test_vortex_scan_booleans() { - let flags = vec![true, false, true, true, false]; - let flags_array = BoolArray::new(flags.into(), Validity::NonNullable); - let file = write_single_column_vortex_file("flag", flags_array).await; - let true_count: i64 = scan_vortex_file_single_row( - file, - "SELECT COUNT(*) FROM vortex_scan(?) WHERE flag = true", - 0, - ); - assert_eq!(true_count, 3); -} - -#[tokio::test] -async fn test_vortex_multi_column() { - let f1 = BoolArray::new( - vec![true, false, true, true, false].into(), - Validity::NonNullable, - ) - .to_array(); - let f2 = (0..5).collect::().to_array(); - let f3 = (100..105).collect::().to_array(); - let file = write_vortex_file([("f1", f1), ("f2", f2), ("f3", f3)].into_iter()).await; - - let result: Vec = scan_vortex_file( - file, - "SELECT f2 FROM vortex_scan(?) WHERE f1 = true and f2 >= 2", - 0, - ) - .unwrap(); - - assert_eq!(result, vec![2, 3]); -} - -#[tokio::test] -async fn test_vortex_scan_multiple_files() { - let tempdir = tempfile::tempdir().unwrap(); - - let _file1 = write_vortex_file_to_dir( - tempdir.path(), - "numbers", - PrimitiveArray::from_iter([1i32, 2, 3]), - ) - .await; - - let _file2 = write_vortex_file_to_dir( - tempdir.path(), - "numbers", - PrimitiveArray::from_iter([4i32, 5, 6]), - ) - .await; - - // Create glob pattern to match all .vortex files in the temp directory. - let glob_pattern = format!("{}/*.vortex", tempdir.path().display()); - - // Scan both Vortex files. - let conn = database_connection(); - let total_sum: i64 = conn - .prepare("SELECT SUM(numbers) FROM vortex_scan(?)") - .unwrap() - .query_row([&glob_pattern], |row| row.get(0)) - .unwrap(); - - assert_eq!(total_sum, 21); -} diff --git a/vortex-duckdb-ext/src/vortex_scan_tests.rs b/vortex-duckdb-ext/src/vortex_scan_tests.rs new file mode 100644 index 00000000000..c61ae724a2e --- /dev/null +++ b/vortex-duckdb-ext/src/vortex_scan_tests.rs @@ -0,0 +1,258 @@ +//! This module contains tests for the `vortex_scan` table function. + +#[cfg(test)] +mod tests { + use std::path::Path; + + use anyhow::Result; + use tempfile::NamedTempFile; + use vortex::IntoArray; + use vortex::arrays::{BoolArray, ConstantArray, PrimitiveArray, StructArray, VarBinArray}; + use vortex::file::VortexWriteOptions; + use vortex::scalar::Scalar; + use vortex::validity::Validity; + + use crate::duckdb::{Connection, Database, QueryResultCell}; + + fn database_connection() -> Connection { + let db = Database::open_in_memory().unwrap(); + let connection = db.connect().unwrap(); + crate::init(&connection).unwrap(); + connection + } + + fn create_temp_file() -> NamedTempFile { + NamedTempFile::new().unwrap() + } + + async fn write_single_column_vortex_file( + field_name: &str, + array: impl IntoArray, + ) -> NamedTempFile { + write_vortex_file([(field_name, array)].into_iter()).await + } + + async fn write_vortex_file( + iter: impl Iterator, impl IntoArray)>, + ) -> NamedTempFile { + let temp_file_path = create_temp_file(); + + let struct_array = StructArray::try_from_iter(iter).unwrap(); + let file = tokio::fs::File::create(&temp_file_path).await.unwrap(); + VortexWriteOptions::default() + .write(file, struct_array.to_array_stream()) + .await + .unwrap(); + + temp_file_path + } + + fn scan_vortex_file_single_row(tmp_file: NamedTempFile, query: &str, col_idx: usize) -> T + where + T: TryFrom, + { + let conn = database_connection(); + let file_path = tmp_file.path().to_string_lossy(); + let formatted_query = query.replace('?', &format!("'{}'", file_path)); + + let result = conn.query(&formatted_query).unwrap(); + result.get::(col_idx, 0).unwrap() + } + + fn scan_vortex_file(tmp_file: NamedTempFile, query: &str, col_idx: usize) -> Result> + where + T: TryFrom, + { + let conn = database_connection(); + let file_path = tmp_file.path().to_string_lossy(); + let formatted_query = query.replace('?', &format!("'{}'", file_path)); + + let result = conn.query(&formatted_query)?; + + let mut values = Vec::new(); + for row_idx in 0..result.row_count()? { + let value = result.get::(col_idx, row_idx)?; + values.push(value); + } + + Ok(values) + } + + async fn write_vortex_file_to_dir( + dir: &Path, + field_name: &str, + array: impl IntoArray, + ) -> NamedTempFile { + let struct_array = StructArray::from_fields(&[(field_name, array.into_array())]).unwrap(); + let temp_file_path = tempfile::Builder::new() + .suffix(".vortex") + .tempfile_in(dir) + .unwrap(); + + let file = tokio::fs::File::create(&temp_file_path).await.unwrap(); + VortexWriteOptions::default() + .write(file, struct_array.to_array_stream()) + .await + .unwrap(); + + temp_file_path + } + + #[test] + fn test_scan_function_registration() { + let conn = database_connection(); + let result = conn + .query( + "SELECT function_name FROM duckdb_functions() WHERE function_name = 'vortex_scan'", + ) + .unwrap(); + assert_eq!(&result.get::(0, 0).unwrap(), "vortex_scan"); + } + + #[tokio::test] + async fn test_vortex_scan_strings() { + let strings = VarBinArray::from(vec!["Hello", "Hi", "Hey"]); + let file = write_single_column_vortex_file("strings", strings).await; + let result: String = scan_vortex_file_single_row( + file, + "SELECT string_agg(strings, ',') FROM vortex_scan(?)", + 0, + ); + assert_eq!(result, "Hello,Hi,Hey"); + } + + #[tokio::test] + async fn test_vortex_scan_strings_contains() { + let strings = VarBinArray::from(vec!["Hello", "Hi", "Hey"]); + let file = write_single_column_vortex_file("strings", strings).await; + let result: String = scan_vortex_file_single_row( + file, + "SELECT string_agg(strings, ',') FROM vortex_scan(?) WHERE strings LIKE '%He%'", + 0, + ); + assert_eq!(result, "Hello,Hey"); + } + + #[tokio::test] + async fn test_vortex_scan_integers() { + let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); + let file = write_single_column_vortex_file("number", numbers).await; + let sum: i64 = + scan_vortex_file_single_row(file, "SELECT SUM(number) FROM vortex_scan(?)", 0); + assert_eq!(sum, 138); + } + + #[tokio::test] + async fn test_vortex_scan_integers_in_list() { + let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); + let file = write_single_column_vortex_file("number", numbers).await; + let sum: i64 = scan_vortex_file_single_row( + file, + "SELECT SUM(number) FROM vortex_scan(?) WHERE number in (1, 42, -5)", + 0, + ); + assert_eq!(sum, 38); + } + + #[tokio::test] + async fn test_vortex_scan_integers_between() { + let numbers = PrimitiveArray::from_iter([1i32, 42, 100, -5, 0]); + let file = write_single_column_vortex_file("number", numbers).await; + let sum: i64 = scan_vortex_file_single_row( + file, + "SELECT SUM(number) FROM vortex_scan(?) WHERE number > 0 and number < 100", + 0, + ); + assert_eq!(sum, 43); + } + + #[tokio::test] + async fn test_vortex_scan_floats() { + let values = PrimitiveArray::from_iter([1.5f64, -2.5, 0.0, 42.42]); + let file = write_single_column_vortex_file("value", values).await; + let count: i64 = scan_vortex_file_single_row( + file, + "SELECT COUNT(*) FROM vortex_scan(?) WHERE value > 0", + 0, + ); + assert_eq!(count, 2); + } + + #[tokio::test] + async fn test_vortex_scan_constant() { + let constant = ConstantArray::new(Scalar::from(42i32), 100); + let file = write_single_column_vortex_file("constant", constant).await; + let value: i32 = + scan_vortex_file_single_row(file, "SELECT constant FROM vortex_scan(?) LIMIT 1", 0); + assert_eq!(value, 42); + } + + #[tokio::test] + async fn test_vortex_scan_booleans() { + let flags = vec![true, false, true, true, false]; + let flags_array = BoolArray::new(flags.into(), Validity::NonNullable); + let file = write_single_column_vortex_file("flag", flags_array).await; + let true_count: i64 = scan_vortex_file_single_row( + file, + "SELECT COUNT(*) FROM vortex_scan(?) WHERE flag = true", + 0, + ); + assert_eq!(true_count, 3); + } + + #[tokio::test] + async fn test_vortex_multi_column() { + let f1 = BoolArray::new( + vec![true, false, true, true, false].into(), + Validity::NonNullable, + ) + .to_array(); + let f2 = (0..5).collect::().to_array(); + let f3 = (100..105).collect::().to_array(); + let file = write_vortex_file([("f1", f1), ("f2", f2), ("f3", f3)].into_iter()).await; + + let result: Vec = scan_vortex_file( + file, + "SELECT f2 FROM vortex_scan(?) WHERE f1 = true and f2 >= 2", + 0, + ) + .unwrap(); + + assert_eq!(result, vec![2, 3]); + } + + #[tokio::test] + async fn test_vortex_scan_multiple_files() { + let tempdir = tempfile::tempdir().unwrap(); + + let _file1 = write_vortex_file_to_dir( + tempdir.path(), + "numbers", + PrimitiveArray::from_iter([1i32, 2, 3]), + ) + .await; + + let _file2 = write_vortex_file_to_dir( + tempdir.path(), + "numbers", + PrimitiveArray::from_iter([4i32, 5, 6]), + ) + .await; + + // Create glob pattern to match all .vortex files in the temp directory. + let glob_pattern = format!("{}/*.vortex", tempdir.path().display()); + + // Scan both Vortex files. + let conn = database_connection(); + let result = conn + .query(&format!( + "SELECT SUM(numbers) FROM vortex_scan('{}')", + glob_pattern + )) + .unwrap(); + + let total_sum: i64 = result.get(0, 0).unwrap(); + + assert_eq!(total_sum, 21); + } +}