diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 33cf544..aced2f1 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -21,9 +21,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true -defaults: - run: - working-directory: ./optd-persistent name: check jobs: fmt: @@ -61,22 +58,6 @@ jobs: components: clippy - name: cargo clippy run: cargo clippy --locked --all-targets --all-features -- -D warnings - doc: - # run docs generation on nightly rather than stable. This enables features like - # https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html which allows an - # API be documented as only available in some specific platforms. - runs-on: ubuntu-latest - name: nightly / doc - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install nightly - uses: dtolnay/rust-toolchain@nightly - - name: Install cargo-docs-rs - uses: dtolnay/install@cargo-docs-rs - - name: cargo docs-rs - run: cargo docs-rs hack: # cargo-hack checks combinations of feature flags to ensure that features are all additive # which is required for feature unification diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d6253a0..565c9eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,9 +17,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true -defaults: - run: - working-directory: ./optd-persistent name: test jobs: required: diff --git a/.gitignore b/.gitignore index db6bb3a..86281ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,13 @@ -# Generated by Cargo -# will have compiled files and executables +# Contains compiled files and executables. debug/ target/ -# These are backup files generated by rustfmt +# These are backup files generated by rustfmt. **/*.rs.bk +# Ignore any database files. **/*.db -!init.db -.DS_Store - -optd-persistent/sql/ +# We will check in all code-generated entity files, as newer versions of `sea-orm-cli` might +# conflict with previous versions. +# **/entities diff --git a/Cargo.lock b/Cargo.lock index e81b740..8acb13b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,82 +1,45 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ "gimli", ] [[package]] -name = "adler2" -version = "2.0.0" +name = "adler" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "6aa100a6f6f525226719f8de3f70076be4f4191801ebd92621450d1c51e9053d" [[package]] name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", - "const-random", - "getrandom", "once_cell", "version_check", "zerocopy", ] -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "aliasable" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "d52f4a9cf8f3ff707b4eb1acd0136efd8b3bec6b345ed32fcab47c0a5c99b800" [[package]] name = "android-tzdata" @@ -95,340 +58,89 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is_terminal_polyfill", + "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - [[package]] name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "arrow" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fab9e93ba8ce88a37d5a30dce4b9913b75413dc1ac56cb5d72e5a840543f829" -dependencies = [ - "ahash 0.8.11", - "arrow-arith", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-csv", - "arrow-data", - "arrow-ipc", - "arrow-json", - "arrow-ord", - "arrow-row", - "arrow-schema 47.0.0", - "arrow-select", - "arrow-string", -] - -[[package]] -name = "arrow-arith" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc1d4e368e87ad9ee64f28b9577a3834ce10fe2703a26b28417d485bbbdff956" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "half", - "num", -] - -[[package]] -name = "arrow-array" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d02efa7253ede102d45a4e802a129e83bcc3f49884cab795b1ac223918e4318d" -dependencies = [ - "ahash 0.8.11", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "chrono-tz", - "half", - "hashbrown 0.14.5", - "num", -] - -[[package]] -name = "arrow-buffer" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda119225204141138cb0541c692fbfef0e875ba01bfdeaed09e9d354f9d6195" -dependencies = [ - "bytes", - "half", - "num", -] - -[[package]] -name = "arrow-cast" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d825d51b9968868d50bc5af92388754056796dbc62a4e25307d588a1fc84dee" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "chrono", - "comfy-table", - "half", - "lexical-core", - "num", -] - -[[package]] -name = "arrow-csv" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ef855dc6b126dc197f43e061d4de46b9d4c033aa51c2587657f7508242cef1" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "csv", - "csv-core", - "lazy_static", - "lexical-core", - "regex", -] - -[[package]] -name = "arrow-data" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475a4c3699c8b4095ca61cecf15da6f67841847a5f5aac983ccb9a377d02f73a" -dependencies = [ - "arrow-buffer", - "arrow-schema 47.0.0", - "half", - "num", -] - -[[package]] -name = "arrow-ipc" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1248005c8ac549f869b7a840859d942bf62471479c1a2d82659d453eebcd166a" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "flatbuffers", -] - -[[package]] -name = "arrow-json" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03d7e3b04dd688ccec354fe449aed56b831679f03e44ee2c1cfc4045067b69c" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "half", - "indexmap 2.6.0", - "lexical-core", - "num", - "serde", - "serde_json", -] - -[[package]] -name = "arrow-ord" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b87aa408ea6a6300e49eb2eba0c032c88ed9dc19e0a9948489c55efdca71f4" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "half", - "num", -] - -[[package]] -name = "arrow-row" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114a348ab581e7c9b6908fcab23cb39ff9f060eb19e72b13f8fb8eaa37f65d22" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "half", - "hashbrown 0.14.5", -] - -[[package]] -name = "arrow-schema" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d179c117b158853e0101bfbed5615e86fe97ee356b4af901f1c5001e1ce4b" - -[[package]] -name = "arrow-schema" -version = "53.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539ada65246b949bd99ffa0881a9a15a4a529448af1a07a9838dd78617dafab1" - -[[package]] -name = "arrow-select" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5c71e003202e67e9db139e5278c79f5520bb79922261dfe140e4637ee8b6108" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "num", -] - -[[package]] -name = "arrow-string" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cebbb282d6b9244895f4a9a912e55e57bce112554c7fa91fcec5459cb421ab" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "num", - "regex", - "regex-syntax 0.7.5", -] - -[[package]] -name = "assert_approx_eq" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c07dab4369547dbe5114677b33fbbf724971019f3818172d59a97a61c774ffd" - -[[package]] -name = "async-compression" -version = "0.4.17" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" -dependencies = [ - "bzip2", - "flate2", - "futures-core", - "futures-io", - "memchr", - "pin-project-lite", - "tokio", - "xz2", - "zstd 0.13.2", - "zstd-safe 7.2.1", -] +checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7" [[package]] name = "async-stream" -version = "0.3.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +checksum = "0a26cb53174ddd320edfff199a853f93d571f48eeb4dde75e67a9a3dbb7b7e5e" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +checksum = "db134ba52475c060f3329a8ef0f8786d6b872ed01515d4b79c162e5798da1340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "b6287685011f026b98d26afd53251ad0101e856531b423eb2384265f7d4f5b01" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", ] [[package]] @@ -442,50 +154,49 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "88fb5a785d6b44fd9d6700935608639af1b8356de1e55d5f7c2740f4faa15d82" dependencies = [ "addr2line", + "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", ] [[package]] name = "base64" -version = "0.21.7" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64" -version = "0.22.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "71acf5509fc522cce1b100ac0121c635129bfd4d91cdf036bcc9b9935f97ccf5" [[package]] name = "bigdecimal" -version = "0.4.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" +checksum = "5274a6b6e0ee020148397245b973e30163b7bffbc6d473613f850cb99888581e" dependencies = [ - "autocfg", "libm", "num-bigint", "num-integer", @@ -495,177 +206,51 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" dependencies = [ "serde", ] -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" dependencies = [ "generic-array", ] -[[package]] -name = "borsh" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "brotli" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" [[package]] name = "byteorder" -version = "1.5.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.2.1" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" -dependencies = [ - "jobserver", - "libc", - "shlex", -] +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" [[package]] name = "cfg-if" @@ -673,64 +258,35 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "chrono-tz" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", + "windows-targets 0.52.0", ] [[package]] name = "clap" -version = "4.5.21" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" dependencies = [ "clap_builder", "clap_derive", + "once_cell", ] [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" dependencies = [ "anstream", "anstyle", @@ -740,11 +296,11 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ - "heck 0.5.0", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.87", @@ -752,453 +308,184 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" - -[[package]] -name = "colorchoice" -version = "1.0.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] -name = "comfy-table" -version = "7.1.3" +name = "codespan-reporting" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" +checksum = "c6ce42b8998a383572e0a802d859b1f00c79b7b7474e62fff88ee5c2845d9c13" dependencies = [ - "strum 0.26.3", - "strum_macros 0.26.4", + "termcolor", "unicode-width", ] [[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const-random" -version = "0.1.18" +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] -name = "const-random-macro" -version = "0.1.16" +name = "concurrent-queue" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", + "crossbeam-utils", ] [[package]] -name = "constant_time_eq" -version = "0.3.1" +name = "const-oid" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "core-foundation-sys" -version = "0.8.7" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.2.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] +checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" dependencies = [ + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "csv" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" -dependencies = [ - "memchr", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.87", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "dashmap" -version = "5.5.3" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", - "hashbrown 0.14.5", - "lock_api", "once_cell", - "parking_lot_core", ] [[package]] -name = "datafusion" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7014432223f4d721cb9786cd88bb89e7464e0ba984d4a7f49db7787f5f268674" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-schema 47.0.0", - "async-compression", - "async-trait", - "bytes", - "bzip2", - "chrono", - "dashmap", - "datafusion-common", - "datafusion-execution", - "datafusion-expr", - "datafusion-optimizer", - "datafusion-physical-expr", - "datafusion-physical-plan", - "datafusion-sql", - "flate2", - "futures", - "glob", - "half", - "hashbrown 0.14.5", - "indexmap 2.6.0", - "itertools 0.11.0", - "log", - "num_cpus", - "object_store", - "parking_lot", - "parquet", - "percent-encoding", - "pin-project-lite", - "rand", - "sqlparser", - "tempfile", - "tokio", - "tokio-util", - "url", - "uuid", - "xz2", - "zstd 0.12.4", -] - -[[package]] -name = "datafusion-common" -version = "32.0.0" +name = "crypto-common" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3903ed8f102892f17b48efa437f3542159241d41c564f0d1e78efdc5e663aa" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "chrono", - "half", - "num_cpus", - "object_store", - "parquet", - "sqlparser", + "generic-array", + "typenum", ] [[package]] -name = "datafusion-execution" -version = "32.0.0" +name = "cxx" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780b73b2407050e53f51a9781868593f694102c59e622de9a8aafc0343c4f237" +checksum = "a4c53d75fe543215ca091d792e13351dcb940842dd2829b2a2dd43ab4bd1a015" dependencies = [ - "arrow", - "chrono", - "dashmap", - "datafusion-common", - "datafusion-expr", - "futures", - "hashbrown 0.14.5", - "log", - "object_store", - "parking_lot", - "rand", - "tempfile", - "url", + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", ] [[package]] -name = "datafusion-expr" -version = "32.0.0" +name = "cxx-build" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c382676338d8caba6c027ba0da47260f65ffedab38fda78f6d8043f607557c" +checksum = "618f85c8f132bd8912aab124e15a38adc762bb7e3cef84524adde1692ef3e8bc" dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "datafusion-common", - "sqlparser", - "strum 0.25.0", - "strum_macros 0.25.3", + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 1.0.98", ] [[package]] -name = "datafusion-optimizer" -version = "32.0.0" +name = "cxxbridge-flags" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2904a432f795484fd45e29ded4537152adb60f636c05691db34fcd94c92c96" +checksum = "ca21461be76a23df4f63a2107a0bb406ef41548e635ff7edcbd1ab5a6bb997e2" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8da0a2c0697647b5824844a5d2dedcd97a2d7b75e6e4d0b8dd183e4081e1cf" dependencies = [ - "arrow", - "async-trait", - "chrono", - "datafusion-common", - "datafusion-expr", - "datafusion-physical-expr", - "hashbrown 0.14.5", - "itertools 0.11.0", - "log", - "regex-syntax 0.7.5", + "proc-macro2", + "quote", + "syn 1.0.98", ] [[package]] -name = "datafusion-physical-expr" -version = "32.0.0" +name = "darling" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b4968e9a998dc0476c4db7a82f280e2026b25f464e4aa0c3bb9807ee63ddfd" +checksum = "e7c99d16b88c92aef47e58dadd53e87b4bd234c29934947a6cec8b466300f99b" dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "base64 0.21.7", - "blake2", - "blake3", - "chrono", - "datafusion-common", - "datafusion-expr", - "half", - "hashbrown 0.14.5", - "hex", - "indexmap 2.6.0", - "itertools 0.11.0", - "libc", - "log", - "md-5", - "paste", - "petgraph", - "rand", - "regex", - "sha2", - "unicode-segmentation", - "uuid", + "darling_core", + "darling_macro", ] [[package]] -name = "datafusion-physical-plan" -version = "32.0.0" +name = "darling_core" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd0d1fe54e37a47a2d58a1232c22786f2c28ad35805fdcd08f0253a8b0aaa90" +checksum = "2ea05d2fcb27b53f7a98faddaf5f2914760330ab7703adfc9df13332b42189f9" dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "async-trait", - "chrono", - "datafusion-common", - "datafusion-execution", - "datafusion-expr", - "datafusion-physical-expr", - "futures", - "half", - "hashbrown 0.14.5", - "indexmap 2.6.0", - "itertools 0.11.0", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "rand", - "tokio", - "uuid", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] -name = "datafusion-sql" -version = "32.0.0" +name = "darling_macro" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b568d44c87ead99604d704f942e257c8a236ee1bbf890ee3e034ad659dcb2c21" +checksum = "7bfb82b62b1b8a2a9808fb4caf844ede819a76cfc23b2827d7f94eefb49551eb" dependencies = [ - "arrow", - "arrow-schema 47.0.0", - "datafusion-common", - "datafusion-expr", - "log", - "sqlparser", + "darling_core", + "quote", + "syn 2.0.87", ] [[package]] name = "der" -version = "0.7.9" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "19c5cb402c5c958281c7c0702edea7b780d03b86b606497ca3a10fcd3fc393ac" dependencies = [ "const-oid", "pem-rfc7468", @@ -1207,9 +494,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" dependencies = [ "powerfmt", "serde", @@ -1228,48 +515,54 @@ dependencies = [ ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "dirs" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", + "dirs-sys", ] [[package]] -name = "doc-comment" -version = "0.3.3" +name = "dirs-sys" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] [[package]] name = "dotenvy" -version = "0.15.7" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +checksum = "ed9155c8f4dc55c7470ae9da3f63c6785245093b3f6aeb0f5bf2e968efbba314" +dependencies = [ + "dirs", +] [[package]] name = "either" -version = "1.13.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" dependencies = [ "serde", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1288,9 +581,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.3.1" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1299,45 +592,19 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flatbuffers" -version = "23.5.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" -dependencies = [ - "bitflags 1.3.2", - "rustc_version", -] - -[[package]] -name = "flate2" -version = "1.0.35" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "flume" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ "futures-core", "futures-sink", - "spin", + "spin 0.9.8", ] [[package]] @@ -1348,28 +615,22 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" dependencies = [ + "matches", "percent-encoding", ] -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" -version = "0.3.31" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "90fa4cc29d25b0687b8570b0da86eac698dcb525110ad8b938fe6712baa711ec" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1394,9 +655,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -1420,17 +681,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "futures-sink" version = "0.3.31" @@ -1452,7 +702,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1461,11 +710,20 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", "version_check", @@ -1473,9 +731,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -1484,35 +742,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", - "num-traits", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hashbrown" @@ -1520,23 +758,17 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash", "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" - [[package]] name = "hashlink" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" dependencies = [ - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -1553,9 +785,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -1565,176 +797,53 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "94f41e9c77b6fc05b57497b960aad55942a9bbc5b20e1e623cf7fb1868f695d1" dependencies = [ "hmac", ] [[package]] name = "hmac" -version = "0.12.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2" dependencies = [ "digest", ] [[package]] name = "home" -version = "0.5.9" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", + "cxx", + "cxx-build", ] [[package]] @@ -1745,205 +854,106 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "indexmap" -version = "2.6.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.15.1", - "serde", + "hashbrown", ] [[package]] name = "inherent" -version = "1.0.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" +checksum = "f3c05a410d53e44fc943a35a32ca27e32af2ea004d5107ccef685d022fc2b9fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", -] - -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", + "syn 1.0.98", ] [[package]] -name = "itertools" -version = "0.12.1" +name = "is-terminal" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "either", + "hermit-abi", + "rustix", + "windows-sys 0.48.0", ] [[package]] name = "itertools" -version = "0.13.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" dependencies = [ "either", ] [[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lexical-core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" -dependencies = [ - "lexical-parse-float", - "lexical-parse-integer", - "lexical-util", - "lexical-write-float", - "lexical-write-integer", -] - -[[package]] -name = "lexical-parse-float" -version = "0.8.5" +name = "itertools" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ - "lexical-parse-integer", - "lexical-util", - "static_assertions", + "either", ] [[package]] -name = "lexical-parse-integer" -version = "0.8.6" +name = "itoa" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" -dependencies = [ - "lexical-util", - "static_assertions", -] +checksum = "92a9df60778f789c37f76778ae8d0a2471c41baa8b059d98a5873c978f549587" [[package]] -name = "lexical-util" -version = "0.8.5" +name = "itoa" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" -dependencies = [ - "static_assertions", -] +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] -name = "lexical-write-float" -version = "0.8.5" +name = "js-sys" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" dependencies = [ - "lexical-util", - "lexical-write-integer", - "static_assertions", + "wasm-bindgen", ] [[package]] -name = "lexical-write-integer" -version = "0.8.5" +name = "lazy_static" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" dependencies = [ - "lexical-util", - "static_assertions", + "spin 0.4.10", ] [[package]] name = "libc" -version = "0.2.162" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libsqlite3-sys" @@ -1957,62 +967,34 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "link-cplusplus" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "4dfb9f65d9966f6ca6522043978030b564f3291af987fbf1dd55b6a064ba1b36" +dependencies = [ + "cc", +] [[package]] -name = "litemap" -version = "0.7.3" +name = "linux-raw-sys" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lz4" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" -dependencies = [ - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "matchers" @@ -2020,91 +1002,84 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] +[[package]] +name = "matches" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" + [[package]] name = "md-5" -version = "0.10.6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" dependencies = [ - "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "minimal-lexical" -version = "0.2.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "6595bb28ed34f43c3fe088e48f6cfb2e033cab45f25a5384d5fdf564fbc8c4b2" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" dependencies = [ - "adler2", + "adler", ] [[package]] name = "mio" -version = "1.0.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ - "hermit-abi", "libc", + "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.45.0", ] [[package]] name = "nom" -version = "7.1.3" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" dependencies = [ "memchr", "minimal-lexical", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", + "version_check", ] [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ + "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" dependencies = [ "byteorder", "lazy_static", @@ -2117,15 +1092,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -2134,40 +1100,29 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" dependencies = [ "autocfg", - "num-integer", "num-traits", ] [[package]] -name = "num-rational" -version = "0.4.2" +name = "num-iter" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +checksum = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" dependencies = [ - "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.19" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", "libm", @@ -2175,141 +1130,56 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" dependencies = [ - "hermit-abi", "libc", ] -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "object" -version = "0.36.5" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "object_store" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f930c88a43b1c3f6e776dfe495b4afab89882dbc81530c632db2ed65451ebcb4" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "futures", - "humantime", - "itertools 0.11.0", - "parking_lot", - "percent-encoding", - "snafu", - "tokio", - "tracing", - "url", - "walkdir", -] +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.20.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "optd-cost-model" -version = "0.1.0" -dependencies = [ - "arrow-schema 53.2.0", - "assert_approx_eq", - "async-trait", - "chrono", - "crossbeam", - "datafusion", - "datafusion-expr", - "itertools 0.13.0", - "optd-persistent", - "ordered-float 4.5.0", - "rand", - "serde", - "serde_json", - "serde_with", - "test-case", - "tokio", - "trait-variant", -] +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "optd-persistent" +name = "optd-mvp" version = "0.1.0" dependencies = [ "async-stream", "async-trait", - "num_enum", + "fxhash", "sea-orm", "sea-orm-migration", + "serde", "serde_json", - "strum 0.26.3", + "strum", + "thiserror 2.0.0", "tokio", "trait-variant", ] [[package]] name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "3.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "4.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65ee1f9701bf938026630b455d5315f490640234259037edb259798b3bcf85e" +checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf" dependencies = [ "num-traits", ] [[package]] name = "ouroboros" -version = "0.18.4" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" +checksum = "1c86de06555b970aec45229b27291b53154f21a5743a163419f4e4c0b065dcde" dependencies = [ "aliasable", "ouroboros_macro", @@ -2318,12 +1188,12 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.18.4" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" +checksum = "3633d65683f13b9bcfaa3150880b018899fb0e5d0542f4adaea4f503fdb5eabf" dependencies = [ "heck 0.4.1", - "itertools 0.12.1", + "itertools 0.12.0", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -2332,15 +1202,15 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", "parking_lot_core", @@ -2348,65 +1218,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "b2f4f894f3865f6c0e02810fc597300f34dc2510f66400da262d8ae10e75767d" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "parquet" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0463cc3b256d5f50408c49a4be3a16674f4c8ceef60941709620a062b1f6bf4d" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-ipc", - "arrow-schema 47.0.0", - "arrow-select", - "base64 0.21.7", - "brotli", - "bytes", - "chrono", - "flate2", - "futures", - "hashbrown 0.14.5", - "lz4", - "num", - "num-bigint", - "object_store", - "paste", - "seq-macro", - "snap", - "thrift", - "tokio", - "twox-hash", - "zstd 0.12.4", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", + "windows-sys 0.29.0", ] [[package]] name = "paste" -version = "1.0.15" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "pem-rfc7468" @@ -2419,63 +1246,15 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.6.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -2506,9 +1285,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "powerfmt" @@ -2518,58 +1297,50 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "proc-macro-error" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "2d259aa4825fa1a2371419d30a520219feff9fb3591550a209b4477d2ebaae4f" dependencies = [ + "proc-macro-error-attr", "proc-macro2", "quote", + "syn 1.0.98", + "version_check", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error-attr" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "dd21889899aa8e1ca2b924c1d3f08086631fc90768225b3268b5d5c3e806a503" dependencies = [ - "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", + "syn-mid", + "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] [[package]] name = "proc-macro2-diagnostics" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", @@ -2578,57 +1349,32 @@ dependencies = [ "yansi", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quote" -version = "1.0.37" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" -version = "0.8.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", @@ -2643,176 +1389,119 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ - "bitflags 2.6.0", + "bitflags 1.1.0", ] [[package]] -name = "regex" -version = "1.11.1" +name = "redox_users" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "getrandom", + "redox_syscall", ] [[package]] -name = "regex-automata" -version = "0.1.10" +name = "regex" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ - "regex-syntax 0.6.29", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "72457500f2cf948feb4efccaeb460570c8f66ee5ba33c936bb4bfaa628d71853" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", + "byteorder", + "regex-syntax", + "utf8-ranges", ] [[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.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rend" -version = "0.4.2" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "ring" -version = "0.17.8" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "fb9d44f9bf6b635117787f72416783eb7e4227aaf255e5ce739563d817176a7e" dependencies = [ "cc", - "cfg-if", "getrandom", "libc", - "spin", + "spin 0.9.8", "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "windows-sys 0.48.0", ] [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "3dd2017d3e6d67384f301f8b06fbf4567afc576430a61624d845eb04d2b30a72" dependencies = [ + "byteorder", "const-oid", "digest", "num-bigint-dig", "num-integer", + "num-iter", "num-traits", "pkcs1", "pkcs8", "rand_core", "signature", - "spki", "subtle", "zeroize", ] [[package]] name = "rust_decimal" -version = "1.36.0" +version = "1.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" dependencies = [ "arrayvec", - "borsh", - "bytes", "num-traits", - "rand", - "rkyv", "serde", - "serde_json", ] [[package]] name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] +checksum = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -2821,9 +1510,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" dependencies = [ "once_cell", "ring", @@ -2835,65 +1524,57 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" dependencies = [ + "base64 0.21.0", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.102.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" dependencies = [ "ring", "rustls-pki-types", "untrusted", ] -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" [[package]] -name = "same-file" -version = "1.0.6" +name = "scopeguard" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "scratch" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69" [[package]] name = "sea-bae" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" +checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" dependencies = [ "heck 0.4.1", - "proc-macro-error2", + "proc-macro-error", "proc-macro2", "quote", "syn 2.0.87", @@ -2919,8 +1600,8 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum 0.26.3", - "thiserror", + "strum", + "thiserror 1.0.35", "time", "tracing", "url", @@ -2929,9 +1610,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a157f42d291ccbd6e913b9d9b12dbe2ccbcf0472efc60c8715dd1254083aec" +checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" dependencies = [ "chrono", "clap", @@ -2960,9 +1641,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ba07e9f2479cc671758fcb1edee42ff2e32c34b3e67ab41d0af1e41f73c74e" +checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" dependencies = [ "async-trait", "clap", @@ -2984,7 +1665,7 @@ dependencies = [ "bigdecimal", "chrono", "inherent", - "ordered-float 3.9.2", + "ordered-float", "rust_decimal", "sea-query-derive", "serde_json", @@ -3019,14 +1700,14 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.87", - "thiserror", + "thiserror 1.0.35", ] [[package]] name = "sea-schema" -version = "0.16.0" +version = "0.16.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" +checksum = "a2a4ff9e87c4340affbec4f7790d724dcd87e71fcd0ffe2247481843380485aa" dependencies = [ "futures", "sea-query", @@ -3045,38 +1726,20 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "seq-macro" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" - [[package]] name = "serde" -version = "1.0.215" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", @@ -3085,63 +1748,32 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ - "itoa", - "memchr", + "itoa 1.0.1", "ryu", "serde", ] [[package]] name = "serde_urlencoded" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.0", "ryu", "serde", ] -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.6.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" dependencies = [ "cfg-if", "cpufeatures", @@ -3150,9 +1782,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if", "cpufeatures", @@ -3161,96 +1793,53 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.7" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signature" -version = "2.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" dependencies = [ "digest", "rand_core", ] -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "slab" -version = "0.4.9" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" dependencies = [ "serde", ] [[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" +name = "socket2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", + "libc", + "windows-sys 0.48.0", ] [[package]] -name = "snap" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" - -[[package]] -name = "socket2" -version = "0.5.7" +name = "spin" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" [[package]] name = "spin" @@ -3263,9 +1852,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" dependencies = [ "base64ct", "der", @@ -3273,35 +1862,15 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" dependencies = [ + "itertools 0.10.0", "nom", "unicode_categories", ] -[[package]] -name = "sqlparser" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0272b7bb0a225320170c99901b4b5fb3a4384e255a7f2cc228f61e2ba3893e75" -dependencies = [ - "log", - "sqlparser_derive", -] - -[[package]] -name = "sqlparser_derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55fe75cb4a364c7f7ae06c7dbbc8d84bddd85d6cdf9975963c3935bc1991761e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "sqlx" version = "0.8.2" @@ -3335,10 +1904,10 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.14.5", + "hashbrown", "hashlink", "hex", - "indexmap 2.6.0", + "indexmap", "log", "memchr", "once_cell", @@ -3352,7 +1921,7 @@ dependencies = [ "sha2", "smallvec", "sqlformat", - "thiserror", + "thiserror 1.0.35", "time", "tokio", "tokio-stream", @@ -3408,9 +1977,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", - "base64 0.22.1", + "base64 0.22.0", "bigdecimal", - "bitflags 2.6.0", + "bitflags 2.4.0", "byteorder", "bytes", "chrono", @@ -3426,7 +1995,7 @@ dependencies = [ "hex", "hkdf", "hmac", - "itoa", + "itoa 1.0.1", "log", "md-5", "memchr", @@ -3441,7 +2010,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.35", "time", "tracing", "uuid", @@ -3455,9 +2024,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", - "base64 0.22.1", + "base64 0.22.0", "bigdecimal", - "bitflags 2.6.0", + "bitflags 2.4.0", "byteorder", "chrono", "crc", @@ -3471,7 +2040,7 @@ dependencies = [ "hkdf", "hmac", "home", - "itoa", + "itoa 1.0.1", "log", "md-5", "memchr", @@ -3485,7 +2054,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.35", "time", "tracing", "uuid", @@ -3518,12 +2087,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" @@ -3532,73 +2095,37 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stringprep" -version = "0.1.5" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" dependencies = [ "unicode-bidi", "unicode-normalization", - "unicode-properties", ] [[package]] name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.25.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros 0.25.3", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.87", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.87", -] +checksum = "117c413ac8a6cc19c773939932477a341e416eff7f0e84db42f091d85d7c6e0e" [[package]] name = "subtle" -version = "2.6.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "1.0.109" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -3617,82 +2144,71 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.13.1" +name = "syn-mid" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" -version = "3.14.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] -name = "test-case" -version = "3.3.1" +name = "termcolor" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +checksum = "a52c023823933499250b43960b272e25336c6e2ab8684672edc34489f049ccdd" dependencies = [ - "test-case-macros", + "wincolor", ] [[package]] -name = "test-case-core" -version = "3.3.1" +name = "thiserror" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.87", + "thiserror-impl 1.0.35", ] [[package]] -name = "test-case-macros" -version = "3.3.1" +name = "thiserror" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +checksum = "15291287e9bff1bc6f9ff3409ed9af665bec7a5fc8ac079ea96be07bca0e2668" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "test-case-core", + "thiserror-impl 2.0.0", ] [[package]] -name = "thiserror" -version = "1.0.69" +name = "thiserror-impl" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 1.0.98", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "22efd00f33f93fa62848a7cab956c3d38c8d43095efda1decfc2b3a5dc0b8972" dependencies = [ "proc-macro2", "quote", @@ -3701,25 +2217,13 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "cfg-if", "once_cell", ] -[[package]] -name = "thrift" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" -dependencies = [ - "byteorder", - "integer-encoding", - "ordered-float 2.10.1", -] - [[package]] name = "time" version = "0.3.36" @@ -3727,86 +2231,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", - "itoa", + "itoa 1.0.1", "num-conv", "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", + "serde", + "time-core", + "time-macros", ] [[package]] -name = "tinystr" -version = "0.7.6" +name = "time-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] -name = "tinyvec" -version = "1.8.0" +name = "time-macros" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ - "tinyvec_macros", + "num-conv", + "time-core", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.41.1" +version = "1.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" dependencies = [ "backtrace", "bytes", "libc", "mio", - "parking_lot", + "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", @@ -3815,51 +2285,22 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.12" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ - "bytes", "futures-core", - "futures-sink", "pin-project-lite", "tokio", ] -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap 2.6.0", - "toml_datetime", - "winnow", -] - [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ + "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -3868,29 +2309,29 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "once_cell", @@ -3912,60 +2353,38 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - [[package]] name = "typenum" -version = "1.17.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "2560b941fdb9ea38301b9b708504d612fcdf9c91a8c31d82219bd74cb07d304d" dependencies = [ - "tinyvec", + "matches", ] [[package]] -name = "unicode-properties" -version = "0.1.3" +name = "unicode-ident" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] -name = "unicode-segmentation" -version = "1.12.0" +name = "unicode-normalization" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "bc85732b6d55a0d520aaf765536a188d9d993770c28633422f85bb646da61335" [[package]] name = "unicode_categories" @@ -3981,40 +2400,34 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", + "matches", "percent-encoding", ] [[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" +name = "utf8-ranges" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" [[package]] name = "utf8parse" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.11.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" dependencies = [ - "getrandom", "serde", ] @@ -4026,19 +2439,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -4046,43 +2449,36 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ "cfg-if", - "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" dependencies = [ "bumpalo", + "lazy_static", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4090,58 +2486,112 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" + +[[package]] +name = "web-sys" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.5.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" dependencies = [ - "redox_syscall", - "wasite", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "winapi-util" -version = "0.1.9" +name = "winapi" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "b3ad91d846a4a5342c1fb7008d26124ee6cf94a3953751618577295373b32117" dependencies = [ - "windows-sys 0.59.0", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a16a8e2ebfc883e2b1771c6482b1fb3c6831eab289ba391619a2d93a7356220f" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca29cb03c8ceaf20f8224a18a530938305e9872b1478ea24ff44b4f503a1d1d" + +[[package]] +name = "wincolor" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9dc3aa9dcda98b5a16150c54619c1ead22e3d3a5d458778ae914be760aa981a" +dependencies = [ + "winapi", +] + +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb069ac8b2117d36924190469735767f0990833935ab430155e71a44bafe148" +dependencies = [ + "windows_aarch64_msvc 0.29.0", + "windows_i686_gnu 0.29.0", + "windows_i686_msvc 0.29.0", + "windows_x86_64_gnu 0.29.0", + "windows_x86_64_msvc 0.29.0", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.42.2", ] [[package]] @@ -4150,7 +2600,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.48.0", ] [[package]] @@ -4159,272 +2609,230 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.52.0", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows-targets 0.52.6", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" [[package]] -name = "windows_i686_gnu" -version = "0.52.6" +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" +name = "windows_aarch64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_aarch64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] -name = "windows_i686_msvc" -version = "0.52.6" +name = "windows_i686_gnu" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "windows_i686_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "windows_i686_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows_i686_msvc" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows_i686_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] -name = "winnow" -version = "0.6.20" +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] -name = "write16" -version = "1.0.0" +name = "windows_x86_64_gnu" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" [[package]] -name = "writeable" -version = "0.5.5" +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] -name = "wyz" -version = "0.5.1" +name = "windows_x86_64_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] -name = "xz2" -version = "0.1.7" +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] -name = "yansi" -version = "1.0.1" +name = "windows_x86_64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] -name = "yoke" -version = "0.7.4" +name = "windows_x86_64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] -name = "yoke-derive" -version = "0.7.4" +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] -name = "zerocopy" -version = "0.7.35" +name = "windows_x86_64_msvc" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] +checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" [[package]] -name = "zerocopy-derive" -version = "0.7.35" +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] -name = "zerofrom" -version = "0.1.4" +name = "windows_x86_64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] -name = "zerofrom-derive" -version = "0.1.4" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "zeroize" -version = "1.8.1" +name = "yansi" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerocopy" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", + "zerocopy-derive", ] [[package]] -name = "zerovec-derive" -version = "0.10.3" +name = "zerocopy-derive" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", @@ -4432,48 +2840,7 @@ dependencies = [ ] [[package]] -name = "zstd" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" -dependencies = [ - "zstd-safe 6.0.6", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe 7.2.1", -] - -[[package]] -name = "zstd-safe" -version = "6.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 540b2a8..14d391c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["optd-cost-model", "optd-persistent"] +members = ["optd-mvp"] resolver = "2" diff --git a/optd-cost-model/Cargo.lock b/optd-cost-model/Cargo.lock deleted file mode 100644 index bf0b367..0000000 --- a/optd-cost-model/Cargo.lock +++ /dev/null @@ -1,4413 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "const-random", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "arrow" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fab9e93ba8ce88a37d5a30dce4b9913b75413dc1ac56cb5d72e5a840543f829" -dependencies = [ - "ahash 0.8.11", - "arrow-arith", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-csv", - "arrow-data", - "arrow-ipc", - "arrow-json", - "arrow-ord", - "arrow-row", - "arrow-schema 47.0.0", - "arrow-select", - "arrow-string", -] - -[[package]] -name = "arrow-arith" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc1d4e368e87ad9ee64f28b9577a3834ce10fe2703a26b28417d485bbbdff956" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "half", - "num", -] - -[[package]] -name = "arrow-array" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d02efa7253ede102d45a4e802a129e83bcc3f49884cab795b1ac223918e4318d" -dependencies = [ - "ahash 0.8.11", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "chrono-tz", - "half", - "hashbrown 0.14.5", - "num", -] - -[[package]] -name = "arrow-buffer" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda119225204141138cb0541c692fbfef0e875ba01bfdeaed09e9d354f9d6195" -dependencies = [ - "bytes", - "half", - "num", -] - -[[package]] -name = "arrow-cast" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d825d51b9968868d50bc5af92388754056796dbc62a4e25307d588a1fc84dee" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "chrono", - "comfy-table", - "half", - "lexical-core", - "num", -] - -[[package]] -name = "arrow-csv" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ef855dc6b126dc197f43e061d4de46b9d4c033aa51c2587657f7508242cef1" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "csv", - "csv-core", - "lazy_static", - "lexical-core", - "regex", -] - -[[package]] -name = "arrow-data" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475a4c3699c8b4095ca61cecf15da6f67841847a5f5aac983ccb9a377d02f73a" -dependencies = [ - "arrow-buffer", - "arrow-schema 47.0.0", - "half", - "num", -] - -[[package]] -name = "arrow-ipc" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1248005c8ac549f869b7a840859d942bf62471479c1a2d82659d453eebcd166a" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "flatbuffers", -] - -[[package]] -name = "arrow-json" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03d7e3b04dd688ccec354fe449aed56b831679f03e44ee2c1cfc4045067b69c" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema 47.0.0", - "chrono", - "half", - "indexmap 2.6.0", - "lexical-core", - "num", - "serde", - "serde_json", -] - -[[package]] -name = "arrow-ord" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b87aa408ea6a6300e49eb2eba0c032c88ed9dc19e0a9948489c55efdca71f4" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "half", - "num", -] - -[[package]] -name = "arrow-row" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114a348ab581e7c9b6908fcab23cb39ff9f060eb19e72b13f8fb8eaa37f65d22" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "half", - "hashbrown 0.14.5", -] - -[[package]] -name = "arrow-schema" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d179c117b158853e0101bfbed5615e86fe97ee356b4af901f1c5001e1ce4b" - -[[package]] -name = "arrow-schema" -version = "53.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539ada65246b949bd99ffa0881a9a15a4a529448af1a07a9838dd78617dafab1" - -[[package]] -name = "arrow-select" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5c71e003202e67e9db139e5278c79f5520bb79922261dfe140e4637ee8b6108" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "num", -] - -[[package]] -name = "arrow-string" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cebbb282d6b9244895f4a9a912e55e57bce112554c7fa91fcec5459cb421ab" -dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema 47.0.0", - "arrow-select", - "num", - "regex", - "regex-syntax 0.7.5", -] - -[[package]] -name = "async-compression" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" -dependencies = [ - "bzip2", - "flate2", - "futures-core", - "futures-io", - "memchr", - "pin-project-lite", - "tokio", - "xz2", - "zstd 0.13.2", - "zstd-safe 7.2.1", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "async-trait" -version = "0.1.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bigdecimal" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" -dependencies = [ - "autocfg", - "libm", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -dependencies = [ - "serde", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "borsh" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "brotli" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "chrono-tz" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - -[[package]] -name = "clap" -version = "4.5.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "clap_lex" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "comfy-table" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" -dependencies = [ - "strum 0.26.3", - "strum_macros 0.26.4", - "unicode-width", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "csv" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" -dependencies = [ - "memchr", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.87", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "datafusion" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7014432223f4d721cb9786cd88bb89e7464e0ba984d4a7f49db7787f5f268674" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-schema 47.0.0", - "async-compression", - "async-trait", - "bytes", - "bzip2", - "chrono", - "dashmap", - "datafusion-common", - "datafusion-execution", - "datafusion-expr", - "datafusion-optimizer", - "datafusion-physical-expr", - "datafusion-physical-plan", - "datafusion-sql", - "flate2", - "futures", - "glob", - "half", - "hashbrown 0.14.5", - "indexmap 2.6.0", - "itertools 0.11.0", - "log", - "num_cpus", - "object_store", - "parking_lot", - "parquet", - "percent-encoding", - "pin-project-lite", - "rand", - "sqlparser", - "tempfile", - "tokio", - "tokio-util", - "url", - "uuid", - "xz2", - "zstd 0.12.4", -] - -[[package]] -name = "datafusion-common" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3903ed8f102892f17b48efa437f3542159241d41c564f0d1e78efdc5e663aa" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "chrono", - "half", - "num_cpus", - "object_store", - "parquet", - "sqlparser", -] - -[[package]] -name = "datafusion-execution" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780b73b2407050e53f51a9781868593f694102c59e622de9a8aafc0343c4f237" -dependencies = [ - "arrow", - "chrono", - "dashmap", - "datafusion-common", - "datafusion-expr", - "futures", - "hashbrown 0.14.5", - "log", - "object_store", - "parking_lot", - "rand", - "tempfile", - "url", -] - -[[package]] -name = "datafusion-expr" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c382676338d8caba6c027ba0da47260f65ffedab38fda78f6d8043f607557c" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "datafusion-common", - "sqlparser", - "strum 0.25.0", - "strum_macros 0.25.3", -] - -[[package]] -name = "datafusion-optimizer" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2904a432f795484fd45e29ded4537152adb60f636c05691db34fcd94c92c96" -dependencies = [ - "arrow", - "async-trait", - "chrono", - "datafusion-common", - "datafusion-expr", - "datafusion-physical-expr", - "hashbrown 0.14.5", - "itertools 0.11.0", - "log", - "regex-syntax 0.7.5", -] - -[[package]] -name = "datafusion-physical-expr" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b4968e9a998dc0476c4db7a82f280e2026b25f464e4aa0c3bb9807ee63ddfd" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "base64 0.21.7", - "blake2", - "blake3", - "chrono", - "datafusion-common", - "datafusion-expr", - "half", - "hashbrown 0.14.5", - "hex", - "indexmap 2.6.0", - "itertools 0.11.0", - "libc", - "log", - "md-5", - "paste", - "petgraph", - "rand", - "regex", - "sha2", - "unicode-segmentation", - "uuid", -] - -[[package]] -name = "datafusion-physical-plan" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd0d1fe54e37a47a2d58a1232c22786f2c28ad35805fdcd08f0253a8b0aaa90" -dependencies = [ - "ahash 0.8.11", - "arrow", - "arrow-array", - "arrow-buffer", - "arrow-schema 47.0.0", - "async-trait", - "chrono", - "datafusion-common", - "datafusion-execution", - "datafusion-expr", - "datafusion-physical-expr", - "futures", - "half", - "hashbrown 0.14.5", - "indexmap 2.6.0", - "itertools 0.11.0", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "rand", - "tokio", - "uuid", -] - -[[package]] -name = "datafusion-sql" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b568d44c87ead99604d704f942e257c8a236ee1bbf890ee3e034ad659dcb2c21" -dependencies = [ - "arrow", - "arrow-schema 47.0.0", - "datafusion-common", - "datafusion-expr", - "log", - "sqlparser", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -dependencies = [ - "serde", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flatbuffers" -version = "23.5.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" -dependencies = [ - "bitflags 1.3.2", - "rustc_version", -] - -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", - "num-traits", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" -dependencies = [ - "equivalent", - "hashbrown 0.15.1", - "serde", -] - -[[package]] -name = "inherent" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lexical-core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" -dependencies = [ - "lexical-parse-float", - "lexical-parse-integer", - "lexical-util", - "lexical-write-float", - "lexical-write-integer", -] - -[[package]] -name = "lexical-parse-float" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" -dependencies = [ - "lexical-parse-integer", - "lexical-util", - "static_assertions", -] - -[[package]] -name = "lexical-parse-integer" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" -dependencies = [ - "lexical-util", - "static_assertions", -] - -[[package]] -name = "lexical-util" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" -dependencies = [ - "static_assertions", -] - -[[package]] -name = "lexical-write-float" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" -dependencies = [ - "lexical-util", - "lexical-write-integer", - "static_assertions", -] - -[[package]] -name = "lexical-write-integer" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" -dependencies = [ - "lexical-util", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.162" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" - -[[package]] -name = "libm" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - -[[package]] -name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litemap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lz4" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" -dependencies = [ - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[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 = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[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 = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "object_store" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f930c88a43b1c3f6e776dfe495b4afab89882dbc81530c632db2ed65451ebcb4" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "futures", - "humantime", - "itertools 0.11.0", - "parking_lot", - "percent-encoding", - "snafu", - "tokio", - "tracing", - "url", - "walkdir", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "optd-cost-model" -version = "0.1.0" -dependencies = [ - "arrow-schema 53.2.0", - "chrono", - "crossbeam", - "datafusion", - "datafusion-expr", - "itertools 0.13.0", - "optd-persistent", - "ordered-float 4.5.0", - "rand", - "serde", - "serde_json", - "serde_with", -] - -[[package]] -name = "optd-persistent" -version = "0.1.0" -dependencies = [ - "async-stream", - "async-trait", - "sea-orm", - "sea-orm-migration", - "serde_json", - "strum 0.26.3", - "tokio", - "trait-variant", -] - -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "3.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65ee1f9701bf938026630b455d5315f490640234259037edb259798b3bcf85e" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ouroboros" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" -dependencies = [ - "heck 0.4.1", - "itertools 0.12.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "parquet" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0463cc3b256d5f50408c49a4be3a16674f4c8ceef60941709620a062b1f6bf4d" -dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-ipc", - "arrow-schema 47.0.0", - "arrow-select", - "base64 0.21.7", - "brotli", - "bytes", - "chrono", - "flate2", - "futures", - "hashbrown 0.14.5", - "lz4", - "num", - "num-bigint", - "object_store", - "paste", - "seq-macro", - "snap", - "thrift", - "tokio", - "twox-hash", - "zstd 0.12.4", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.6.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "proc-macro2" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "version_check", - "yansi", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[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.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rsa" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rust_decimal" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.23.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sea-bae" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" -dependencies = [ - "heck 0.4.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "sea-orm" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5680a8b686985116607ef5f5af2b1f9e1cc2c228330e93101816a0baa279afa" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "futures", - "log", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum 0.26.3", - "thiserror", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sea-orm-cli" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a157f42d291ccbd6e913b9d9b12dbe2ccbcf0472efc60c8715dd1254083aec" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "tracing", - "tracing-subscriber", - "url", -] - -[[package]] -name = "sea-orm-macros" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a239e3bb1b566ad4ec2654d0d193d6ceddfd733487edc9c21a64d214c773910" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.87", - "unicode-ident", -] - -[[package]] -name = "sea-orm-migration" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ba07e9f2479cc671758fcb1edee42ff2e32c34b3e67ab41d0af1e41f73c74e" -dependencies = [ - "async-trait", - "clap", - "dotenvy", - "futures", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "sea-query" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" -dependencies = [ - "bigdecimal", - "chrono", - "inherent", - "ordered-float 3.9.2", - "rust_decimal", - "sea-query-derive", - "serde_json", - "time", - "uuid", -] - -[[package]] -name = "sea-query-binder" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" -dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time", - "uuid", -] - -[[package]] -name = "sea-query-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.87", - "thiserror", -] - -[[package]] -name = "sea-schema" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" -dependencies = [ - "futures", - "sea-query", - "sea-schema-derive", -] - -[[package]] -name = "sea-schema-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "seq-macro" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" - -[[package]] -name = "serde" -version = "1.0.215" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.215" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "serde_json" -version = "1.0.132" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.6.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[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.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] - -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "snap" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlparser" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0272b7bb0a225320170c99901b4b5fb3a4384e255a7f2cc228f61e2ba3893e75" -dependencies = [ - "log", - "sqlparser_derive", -] - -[[package]] -name = "sqlparser_derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55fe75cb4a364c7f7ae06c7dbbc8d84bddd85d6cdf9975963c3935bc1991761e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "sqlx" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" -dependencies = [ - "atoi", - "bigdecimal", - "byteorder", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.14.5", - "hashlink", - "hex", - "indexmap 2.6.0", - "log", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rust_decimal", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlformat", - "thiserror", - "time", - "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", - "webpki-roots", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.87", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.87", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags 2.6.0", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand", - "rsa", - "rust_decimal", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags 2.6.0", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "rand", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" -dependencies = [ - "atoi", - "chrono", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "serde_urlencoded", - "sqlx-core", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros 0.25.3", -] - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.87", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.87", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "thrift" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" -dependencies = [ - "byteorder", - "integer-encoding", - "ordered-float 2.10.1", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.41.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "tokio-stream" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap 2.6.0", - "toml_datetime", - "winnow", -] - -[[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 2.0.87", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "once_cell", - "regex", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.87", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" - -[[package]] -name = "webpki-roots" -version = "0.26.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "whoami" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" -dependencies = [ - "redox_syscall", - "wasite", -] - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] -name = "yoke" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "zerofrom" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "zstd" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" -dependencies = [ - "zstd-safe 6.0.6", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe 7.2.1", -] - -[[package]] -name = "zstd-safe" -version = "6.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/optd-cost-model/Cargo.toml b/optd-cost-model/Cargo.toml deleted file mode 100644 index 1812f8d..0000000 --- a/optd-cost-model/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "optd-cost-model" -version = "0.1.0" -edition = "2021" -authors = ["Yuanxin Cao", "Lan Lou", "Kunle Li"] - -[dependencies] -optd-persistent = { path = "../optd-persistent", version = "0.1" } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_with = { version = "3.7.0", features = ["json"] } -arrow-schema = "53.2.0" -datafusion-expr = "32.0.0" -datafusion = "32.0.0" -ordered-float = "4.0" -chrono = "0.4" -itertools = "0.13" -assert_approx_eq = "1.1.0" -trait-variant = "0.1.2" -tokio = { version = "1.0.1", features = ["macros", "rt-multi-thread"] } -async-trait = "0.1" - -[dev-dependencies] -crossbeam = "0.8" -rand = "0.8" -test-case = "3.3" diff --git a/optd-cost-model/src/common/mod.rs b/optd-cost-model/src/common/mod.rs deleted file mode 100644 index ca5eb7e..0000000 --- a/optd-cost-model/src/common/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod nodes; -pub mod predicates; -pub mod properties; -pub mod types; -pub mod values; diff --git a/optd-cost-model/src/common/nodes.rs b/optd-cost-model/src/common/nodes.rs deleted file mode 100644 index 79a47f7..0000000 --- a/optd-cost-model/src/common/nodes.rs +++ /dev/null @@ -1,127 +0,0 @@ -use core::fmt; -use std::{fmt::Display, sync::Arc}; - -use arrow_schema::DataType; - -use super::{ - predicates::{ - bin_op_pred::BinOpType, constant_pred::ConstantType, func_pred::FuncType, - log_op_pred::LogOpType, sort_order_pred::SortOrderType, un_op_pred::UnOpType, - }, - values::Value, -}; - -/// TODO: documentation -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum JoinType { - Inner = 1, - FullOuter, - LeftOuter, - RightOuter, - Cross, - LeftSemi, - RightSemi, - LeftAnti, - RightAnti, -} - -impl Display for JoinType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -/// TODO: documentation -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum PhysicalNodeType { - PhysicalProjection, - PhysicalFilter, - PhysicalScan, - PhysicalSort, - PhysicalAgg, - PhysicalHashJoin(JoinType), - PhysicalNestedLoopJoin(JoinType), - PhysicalEmptyRelation, - PhysicalLimit, -} - -impl std::fmt::Display for PhysicalNodeType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -/// TODO: documentation -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum PredicateType { - List, - Constant(ConstantType), - AttrIndex, - UnOp(UnOpType), - BinOp(BinOpType), - LogOp(LogOpType), - Func(FuncType), - SortOrder(SortOrderType), - Between, - Cast, - Like, - DataType(DataType), - InList, -} - -impl std::fmt::Display for PredicateType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -pub type ArcPredicateNode = Arc; - -/// TODO: documentation -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct PredicateNode { - /// A generic predicate node type - pub typ: PredicateType, - /// Child predicate nodes, always materialized - pub children: Vec, - /// Data associated with the predicate, if any - pub data: Option, -} - -impl std::fmt::Display for PredicateNode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({}", self.typ)?; - for child in &self.children { - write!(f, " {}", child)?; - } - if let Some(data) = &self.data { - write!(f, " {}", data)?; - } - write!(f, ")") - } -} - -impl PredicateNode { - pub fn child(&self, idx: usize) -> ArcPredicateNode { - self.children[idx].clone() - } - - pub fn unwrap_data(&self) -> Value { - self.data.clone().unwrap() - } -} -pub trait ReprPredicateNode: 'static + Clone { - fn into_pred_node(self) -> ArcPredicateNode; - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option; -} - -impl ReprPredicateNode for ArcPredicateNode { - fn into_pred_node(self) -> ArcPredicateNode { - self - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - Some(pred_node) - } -} diff --git a/optd-cost-model/src/common/predicates/attr_index_pred.rs b/optd-cost-model/src/common/predicates/attr_index_pred.rs deleted file mode 100644 index 412c7a3..0000000 --- a/optd-cost-model/src/common/predicates/attr_index_pred.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::common::{ - nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}, - values::Value, -}; - -/// [`AttributeIndexPred`] represents the position of an attribute in a schema or -/// [`GroupAttrRefs`]. -/// -/// The `data` field holds the index of the attribute in the schema or [`GroupAttrRefs`]. -#[derive(Clone, Debug)] -pub struct AttrIndexPred(pub ArcPredicateNode); - -impl AttrIndexPred { - pub fn new(attr_idx: u64) -> AttrIndexPred { - AttrIndexPred( - PredicateNode { - typ: PredicateType::AttrIndex, - children: vec![], - data: Some(Value::UInt64(attr_idx)), - } - .into(), - ) - } - - /// Gets the attribute index. - pub fn attr_index(&self) -> u64 { - self.0.data.as_ref().unwrap().as_u64() - } -} - -impl ReprPredicateNode for AttrIndexPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if pred_node.typ != PredicateType::AttrIndex { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/bin_op_pred.rs b/optd-cost-model/src/common/predicates/bin_op_pred.rs deleted file mode 100644 index 5c48688..0000000 --- a/optd-cost-model/src/common/predicates/bin_op_pred.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -/// TODO: documentation -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum BinOpType { - // numerical - Add, - Sub, - Mul, - Div, - Mod, - - // comparison - Eq, - Neq, - Gt, - Lt, - Geq, - Leq, -} - -impl std::fmt::Display for BinOpType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl BinOpType { - pub fn is_numerical(&self) -> bool { - matches!( - self, - Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Mod - ) - } - - pub fn is_comparison(&self) -> bool { - matches!( - self, - Self::Eq | Self::Neq | Self::Gt | Self::Lt | Self::Geq | Self::Leq - ) - } -} - -#[derive(Clone, Debug)] -pub struct BinOpPred(pub ArcPredicateNode); - -impl BinOpPred { - pub fn new(left: ArcPredicateNode, right: ArcPredicateNode, op_type: BinOpType) -> Self { - BinOpPred( - PredicateNode { - typ: PredicateType::BinOp(op_type), - children: vec![left, right], - data: None, - } - .into(), - ) - } - - pub fn left_child(&self) -> ArcPredicateNode { - self.0.child(0) - } - - pub fn right_child(&self) -> ArcPredicateNode { - self.0.child(1) - } - - pub fn op_type(&self) -> BinOpType { - if let PredicateType::BinOp(op_type) = self.0.typ { - op_type - } else { - panic!("not a bin op") - } - } -} - -impl ReprPredicateNode for BinOpPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::BinOp(_)) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/cast_pred.rs b/optd-cost-model/src/common/predicates/cast_pred.rs deleted file mode 100644 index 2e1ef54..0000000 --- a/optd-cost-model/src/common/predicates/cast_pred.rs +++ /dev/null @@ -1,49 +0,0 @@ -use arrow_schema::DataType; - -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -use super::data_type_pred::DataTypePred; - -/// [`CastPred`] casts a column from one data type to another. -/// -/// A [`CastPred`] has two children: -/// 1. The original data to cast -/// 2. The target data type to cast to -#[derive(Clone, Debug)] -pub struct CastPred(pub ArcPredicateNode); - -impl CastPred { - pub fn new(child: ArcPredicateNode, cast_to: DataType) -> Self { - CastPred( - PredicateNode { - typ: PredicateType::Cast, - children: vec![child, DataTypePred::new(cast_to).into_pred_node()], - data: None, - } - .into(), - ) - } - - pub fn child(&self) -> ArcPredicateNode { - self.0.child(0) - } - - pub fn cast_to(&self) -> DataType { - DataTypePred::from_pred_node(self.0.child(1)) - .unwrap() - .data_type() - } -} - -impl ReprPredicateNode for CastPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::Cast) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/constant_pred.rs b/optd-cost-model/src/common/predicates/constant_pred.rs deleted file mode 100644 index 61285f7..0000000 --- a/optd-cost-model/src/common/predicates/constant_pred.rs +++ /dev/null @@ -1,220 +0,0 @@ -use std::sync::Arc; - -use arrow_schema::{DataType, IntervalUnit}; -use optd_persistent::cost_model::interface::AttrType; -use serde::{Deserialize, Serialize}; - -use crate::common::{ - nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}, - values::{SerializableOrderedF64, Value}, -}; - -/// TODO: documentation -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub enum ConstantType { - Bool, - Utf8String, - UInt8, - UInt16, - UInt32, - UInt64, - Int8, - Int16, - Int32, - Int64, - Float64, - Date, - IntervalMonthDateNano, - Decimal, - Binary, -} - -impl ConstantType { - pub fn get_data_type_from_value(value: &Value) -> Self { - match value { - Value::Bool(_) => ConstantType::Bool, - Value::String(_) => ConstantType::Utf8String, - Value::UInt8(_) => ConstantType::UInt8, - Value::UInt16(_) => ConstantType::UInt16, - Value::UInt32(_) => ConstantType::UInt32, - Value::UInt64(_) => ConstantType::UInt64, - Value::Int8(_) => ConstantType::Int8, - Value::Int16(_) => ConstantType::Int16, - Value::Int32(_) => ConstantType::Int32, - Value::Int64(_) => ConstantType::Int64, - Value::Float(_) => ConstantType::Float64, - Value::Date32(_) => ConstantType::Date, - _ => unimplemented!("get_data_type_from_value() not implemented for value {value}"), - } - } - - // TODO: current DataType and ConstantType are not 1 to 1 mapping - // optd schema stores constantType from data type in catalog.get - // for decimal128, the precision is lost - pub fn from_data_type(data_type: DataType) -> Self { - match data_type { - DataType::Binary => ConstantType::Binary, - DataType::Boolean => ConstantType::Bool, - DataType::UInt8 => ConstantType::UInt8, - DataType::UInt16 => ConstantType::UInt16, - DataType::UInt32 => ConstantType::UInt32, - DataType::UInt64 => ConstantType::UInt64, - DataType::Int8 => ConstantType::Int8, - DataType::Int16 => ConstantType::Int16, - DataType::Int32 => ConstantType::Int32, - DataType::Int64 => ConstantType::Int64, - DataType::Float64 => ConstantType::Float64, - DataType::Date32 => ConstantType::Date, - DataType::Interval(IntervalUnit::MonthDayNano) => ConstantType::IntervalMonthDateNano, - DataType::Utf8 => ConstantType::Utf8String, - DataType::Decimal128(_, _) => ConstantType::Decimal, - _ => unimplemented!("no conversion to ConstantType for DataType {data_type}"), - } - } - - pub fn into_data_type(&self) -> DataType { - match self { - ConstantType::Binary => DataType::Binary, - ConstantType::Bool => DataType::Boolean, - ConstantType::UInt8 => DataType::UInt8, - ConstantType::UInt16 => DataType::UInt16, - ConstantType::UInt32 => DataType::UInt32, - ConstantType::UInt64 => DataType::UInt64, - ConstantType::Int8 => DataType::Int8, - ConstantType::Int16 => DataType::Int16, - ConstantType::Int32 => DataType::Int32, - ConstantType::Int64 => DataType::Int64, - ConstantType::Float64 => DataType::Float64, - ConstantType::Date => DataType::Date32, - ConstantType::IntervalMonthDateNano => DataType::Interval(IntervalUnit::MonthDayNano), - ConstantType::Decimal => DataType::Float64, - ConstantType::Utf8String => DataType::Utf8, - } - } - - pub fn from_persistent_attr_type(attr_type: AttrType) -> Self { - match attr_type { - AttrType::Integer => ConstantType::Int32, - AttrType::Float => ConstantType::Float64, - AttrType::Varchar => ConstantType::Utf8String, - AttrType::Boolean => ConstantType::Bool, - } - } -} - -#[derive(Clone, Debug)] -pub struct ConstantPred(pub ArcPredicateNode); - -impl ConstantPred { - pub fn new(value: Value) -> Self { - let typ = ConstantType::get_data_type_from_value(&value); - Self::new_with_type(value, typ) - } - - pub fn new_with_type(value: Value, typ: ConstantType) -> Self { - ConstantPred( - PredicateNode { - typ: PredicateType::Constant(typ), - children: vec![], - data: Some(value), - } - .into(), - ) - } - - pub fn bool(value: bool) -> Self { - Self::new_with_type(Value::Bool(value), ConstantType::Bool) - } - - pub fn string(value: impl AsRef) -> Self { - Self::new_with_type( - Value::String(value.as_ref().into()), - ConstantType::Utf8String, - ) - } - - pub fn uint8(value: u8) -> Self { - Self::new_with_type(Value::UInt8(value), ConstantType::UInt8) - } - - pub fn uint16(value: u16) -> Self { - Self::new_with_type(Value::UInt16(value), ConstantType::UInt16) - } - - pub fn uint32(value: u32) -> Self { - Self::new_with_type(Value::UInt32(value), ConstantType::UInt32) - } - - pub fn uint64(value: u64) -> Self { - Self::new_with_type(Value::UInt64(value), ConstantType::UInt64) - } - - pub fn int8(value: i8) -> Self { - Self::new_with_type(Value::Int8(value), ConstantType::Int8) - } - - pub fn int16(value: i16) -> Self { - Self::new_with_type(Value::Int16(value), ConstantType::Int16) - } - - pub fn int32(value: i32) -> Self { - Self::new_with_type(Value::Int32(value), ConstantType::Int32) - } - - pub fn int64(value: i64) -> Self { - Self::new_with_type(Value::Int64(value), ConstantType::Int64) - } - - pub fn interval_month_day_nano(value: i128) -> Self { - Self::new_with_type(Value::Int128(value), ConstantType::IntervalMonthDateNano) - } - - pub fn float64(value: f64) -> Self { - Self::new_with_type( - Value::Float(SerializableOrderedF64(value.into())), - ConstantType::Float64, - ) - } - - pub fn date(value: i64) -> Self { - Self::new_with_type(Value::Int64(value), ConstantType::Date) - } - - pub fn decimal(value: f64) -> Self { - Self::new_with_type( - Value::Float(SerializableOrderedF64(value.into())), - ConstantType::Decimal, - ) - } - - pub fn serialized(value: Arc<[u8]>) -> Self { - Self::new_with_type(Value::Serialized(value), ConstantType::Binary) - } - - /// Gets the constant value. - pub fn value(&self) -> Value { - self.0.data.clone().unwrap() - } - - pub fn constant_type(&self) -> ConstantType { - if let PredicateType::Constant(typ) = self.0.typ { - typ - } else { - panic!("not a constant") - } - } -} - -impl ReprPredicateNode for ConstantPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(rel_node: ArcPredicateNode) -> Option { - if let PredicateType::Constant(_) = rel_node.typ { - Some(Self(rel_node)) - } else { - None - } - } -} diff --git a/optd-cost-model/src/common/predicates/data_type_pred.rs b/optd-cost-model/src/common/predicates/data_type_pred.rs deleted file mode 100644 index fe29336..0000000 --- a/optd-cost-model/src/common/predicates/data_type_pred.rs +++ /dev/null @@ -1,40 +0,0 @@ -use arrow_schema::DataType; - -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -#[derive(Clone, Debug)] -pub struct DataTypePred(pub ArcPredicateNode); - -impl DataTypePred { - pub fn new(typ: DataType) -> Self { - DataTypePred( - PredicateNode { - typ: PredicateType::DataType(typ), - children: vec![], - data: None, - } - .into(), - ) - } - - pub fn data_type(&self) -> DataType { - if let PredicateType::DataType(ref data_type) = self.0.typ { - data_type.clone() - } else { - panic!("not a data type") - } - } -} - -impl ReprPredicateNode for DataTypePred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::DataType(_)) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/func_pred.rs b/optd-cost-model/src/common/predicates/func_pred.rs deleted file mode 100644 index 7a5b84f..0000000 --- a/optd-cost-model/src/common/predicates/func_pred.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// TODO: documentation -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum FuncType { - Scalar(datafusion_expr::BuiltinScalarFunction), - Agg(datafusion_expr::AggregateFunction), - Case, -} - -impl std::fmt::Display for FuncType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl FuncType { - pub fn new_scalar(func_id: datafusion_expr::BuiltinScalarFunction) -> Self { - FuncType::Scalar(func_id) - } - - pub fn new_agg(func_id: datafusion_expr::AggregateFunction) -> Self { - FuncType::Agg(func_id) - } -} diff --git a/optd-cost-model/src/common/predicates/in_list_pred.rs b/optd-cost-model/src/common/predicates/in_list_pred.rs deleted file mode 100644 index 8d3b511..0000000 --- a/optd-cost-model/src/common/predicates/in_list_pred.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::common::{ - nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}, - values::Value, -}; - -use super::list_pred::ListPred; - -#[derive(Clone, Debug)] -pub struct InListPred(pub ArcPredicateNode); - -impl InListPred { - pub fn new(child: ArcPredicateNode, list: ListPred, negated: bool) -> Self { - InListPred( - PredicateNode { - typ: PredicateType::InList, - children: vec![child, list.into_pred_node()], - data: Some(Value::Bool(negated)), - } - .into(), - ) - } - - pub fn child(&self) -> ArcPredicateNode { - self.0.child(0) - } - - pub fn list(&self) -> ListPred { - ListPred::from_pred_node(self.0.child(1)).unwrap() - } - - /// `true` for `NOT IN`. - pub fn negated(&self) -> bool { - self.0.data.as_ref().unwrap().as_bool() - } -} - -impl ReprPredicateNode for InListPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::InList) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/like_pred.rs b/optd-cost-model/src/common/predicates/like_pred.rs deleted file mode 100644 index bf9fe31..0000000 --- a/optd-cost-model/src/common/predicates/like_pred.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::sync::Arc; - -use crate::common::{ - nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}, - values::Value, -}; - -#[derive(Clone, Debug)] -pub struct LikePred(pub ArcPredicateNode); - -impl LikePred { - pub fn new( - negated: bool, - case_insensitive: bool, - child: ArcPredicateNode, - pattern: ArcPredicateNode, - ) -> Self { - // TODO: support multiple values in data. - let negated = if negated { 1 } else { 0 }; - let case_insensitive = if case_insensitive { 1 } else { 0 }; - LikePred( - PredicateNode { - typ: PredicateType::Like, - children: vec![child.into_pred_node(), pattern.into_pred_node()], - data: Some(Value::Serialized(Arc::new([negated, case_insensitive]))), - } - .into(), - ) - } - - pub fn child(&self) -> ArcPredicateNode { - self.0.child(0) - } - - pub fn pattern(&self) -> ArcPredicateNode { - self.0.child(1) - } - - /// `true` for `NOT LIKE`. - pub fn negated(&self) -> bool { - match self.0.data.as_ref().unwrap() { - Value::Serialized(data) => data[0] != 0, - _ => panic!("not a serialized value"), - } - } - - pub fn case_insensitive(&self) -> bool { - match self.0.data.as_ref().unwrap() { - Value::Serialized(data) => data[1] != 0, - _ => panic!("not a serialized value"), - } - } -} - -impl ReprPredicateNode for LikePred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::Like) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/list_pred.rs b/optd-cost-model/src/common/predicates/list_pred.rs deleted file mode 100644 index 972598d..0000000 --- a/optd-cost-model/src/common/predicates/list_pred.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -#[derive(Clone, Debug)] -pub struct ListPred(pub ArcPredicateNode); - -impl ListPred { - pub fn new(preds: Vec) -> Self { - ListPred( - PredicateNode { - typ: PredicateType::List, - children: preds, - data: None, - } - .into(), - ) - } - - /// Gets number of expressions in the list - pub fn len(&self) -> usize { - self.0.children.len() - } - - pub fn is_empty(&self) -> bool { - self.0.children.is_empty() - } - - pub fn child(&self, idx: usize) -> ArcPredicateNode { - self.0.child(idx) - } - - pub fn to_vec(&self) -> Vec { - self.0.children.clone() - } -} - -impl ReprPredicateNode for ListPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if pred_node.typ != PredicateType::List { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/log_op_pred.rs b/optd-cost-model/src/common/predicates/log_op_pred.rs deleted file mode 100644 index 1899cb1..0000000 --- a/optd-cost-model/src/common/predicates/log_op_pred.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt::Display; - -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -use super::list_pred::ListPred; - -/// TODO: documentation -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum LogOpType { - And, - Or, -} - -impl Display for LogOpType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Clone, Debug)] -pub struct LogOpPred(pub ArcPredicateNode); - -impl LogOpPred { - pub fn new(op_type: LogOpType, preds: Vec) -> Self { - LogOpPred( - PredicateNode { - typ: PredicateType::LogOp(op_type), - children: preds, - data: None, - } - .into(), - ) - } - - /// flatten_nested_logical is a helper function to flatten nested logical operators with same op - /// type eg. (a AND (b AND c)) => ExprList([a, b, c]) - /// (a OR (b OR c)) => ExprList([a, b, c]) - /// It assume the children of the input expr_list are already flattened - /// and can only be used in bottom up manner - pub fn new_flattened_nested_logical(op: LogOpType, expr_list: ListPred) -> Self { - // Since we assume that we are building the children bottom up, - // there is no need to call flatten_nested_logical recursively - let mut new_expr_list = Vec::new(); - for child in expr_list.to_vec() { - if let PredicateType::LogOp(child_op) = child.typ { - if child_op == op { - let child_log_op_expr = LogOpPred::from_pred_node(child).unwrap(); - new_expr_list.extend(child_log_op_expr.children().to_vec()); - continue; - } - } - new_expr_list.push(child.clone()); - } - LogOpPred::new(op, new_expr_list) - } - - pub fn children(&self) -> Vec { - self.0.children.clone() - } - - pub fn child(&self, idx: usize) -> ArcPredicateNode { - self.0.child(idx) - } - - pub fn op_type(&self) -> LogOpType { - if let PredicateType::LogOp(op_type) = self.0.typ { - op_type - } else { - panic!("not a log op") - } - } -} - -impl ReprPredicateNode for LogOpPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::LogOp(_)) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/predicates/mod.rs b/optd-cost-model/src/common/predicates/mod.rs deleted file mode 100644 index 40c64cf..0000000 --- a/optd-cost-model/src/common/predicates/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod attr_index_pred; -pub mod bin_op_pred; -pub mod cast_pred; -pub mod constant_pred; -pub mod data_type_pred; -pub mod func_pred; -pub mod in_list_pred; -pub mod like_pred; -pub mod list_pred; -pub mod log_op_pred; -pub mod sort_order_pred; -pub mod un_op_pred; diff --git a/optd-cost-model/src/common/predicates/sort_order_pred.rs b/optd-cost-model/src/common/predicates/sort_order_pred.rs deleted file mode 100644 index 46111f8..0000000 --- a/optd-cost-model/src/common/predicates/sort_order_pred.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::fmt::Display; - -/// TODO: documentation -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum SortOrderType { - Asc, - Desc, -} - -impl Display for SortOrderType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} diff --git a/optd-cost-model/src/common/predicates/un_op_pred.rs b/optd-cost-model/src/common/predicates/un_op_pred.rs deleted file mode 100644 index a3fc270..0000000 --- a/optd-cost-model/src/common/predicates/un_op_pred.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::fmt::Display; - -use crate::common::nodes::{ArcPredicateNode, PredicateNode, PredicateType, ReprPredicateNode}; - -/// TODO: documentation -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum UnOpType { - Neg = 1, - Not, -} - -impl Display for UnOpType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Clone, Debug)] -pub struct UnOpPred(pub ArcPredicateNode); - -impl UnOpPred { - pub fn new(child: ArcPredicateNode, op_type: UnOpType) -> Self { - UnOpPred( - PredicateNode { - typ: PredicateType::UnOp(op_type), - children: vec![child], - data: None, - } - .into(), - ) - } - - pub fn child(&self) -> ArcPredicateNode { - self.0.child(0) - } - - pub fn op_type(&self) -> UnOpType { - if let PredicateType::UnOp(op_type) = self.0.typ { - op_type - } else { - panic!("not a un op") - } - } -} - -impl ReprPredicateNode for UnOpPred { - fn into_pred_node(self) -> ArcPredicateNode { - self.0 - } - - fn from_pred_node(pred_node: ArcPredicateNode) -> Option { - if !matches!(pred_node.typ, PredicateType::UnOp(_)) { - return None; - } - Some(Self(pred_node)) - } -} diff --git a/optd-cost-model/src/common/properties/attr_ref.rs b/optd-cost-model/src/common/properties/attr_ref.rs deleted file mode 100644 index d6105b6..0000000 --- a/optd-cost-model/src/common/properties/attr_ref.rs +++ /dev/null @@ -1,249 +0,0 @@ -use std::collections::HashSet; - -use crate::{common::types::TableId, utils::DisjointSets}; - -pub type AttrRefs = Vec; - -/// [`BaseTableAttrRef`] represents a reference to an attribute in a base table, -/// i.e. a table existing in the catalog. -#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] -pub struct BaseTableAttrRef { - pub table_id: TableId, - pub attr_idx: u64, -} - -/// [`AttrRef`] represents a reference to an attribute in a query. -#[derive(Clone, Debug)] -pub enum AttrRef { - /// Reference to a base table attribute. - BaseTableAttrRef(BaseTableAttrRef), - /// Reference to a derived attribute (e.g. t.v1 + t.v2). - /// TODO: Better representation of derived attributes. - Derived, -} - -impl AttrRef { - pub fn new_base_table_attr_ref(table_id: TableId, attr_idx: u64) -> Self { - AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) - } - - pub fn base_table_attr_ref(table_id: TableId, attr_idx: u64) -> Self { - AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) - } -} - -impl From for AttrRef { - fn from(attr: BaseTableAttrRef) -> Self { - AttrRef::BaseTableAttrRef(attr) - } -} - -/// [`EqPredicate`] represents an equality predicate between two attributes. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct EqPredicate { - pub left: BaseTableAttrRef, - pub right: BaseTableAttrRef, -} - -impl EqPredicate { - pub fn new(left: BaseTableAttrRef, right: BaseTableAttrRef) -> Self { - Self { left, right } - } -} - -/// [`SemanticCorrelation`] represents the semantic correlation between attributes in a -/// query. "Semantic" means that the attributes are correlated based on the -/// semantics of the query, not the statistics. -/// -/// [`SemanticCorrelation`] contains equal attributes denoted by disjoint sets of base -/// table attributes, e.g. {{ t1.c1 = t2.c1 = t3.c1 }, { t1.c2 = t2.c2 }}. -#[derive(Clone, Debug, Default)] -pub struct SemanticCorrelation { - /// A disjoint set of base table attributes with equal values in the same row. - disjoint_eq_attr_sets: DisjointSets, - /// The predicates that define the equalities. - eq_predicates: HashSet, -} - -impl SemanticCorrelation { - pub fn new() -> Self { - Self { - disjoint_eq_attr_sets: DisjointSets::new(), - eq_predicates: HashSet::new(), - } - } - - pub fn add_predicate(&mut self, predicate: EqPredicate) { - let left = &predicate.left; - let right = &predicate.right; - - // Add the indices to the set if they do not exist. - if !self.disjoint_eq_attr_sets.contains(left) { - self.disjoint_eq_attr_sets - .make_set(left.clone()) - .expect("just checked left attribute index does not exist"); - } - if !self.disjoint_eq_attr_sets.contains(right) { - self.disjoint_eq_attr_sets - .make_set(right.clone()) - .expect("just checked right attribute index does not exist"); - } - // Union the attributes. - self.disjoint_eq_attr_sets - .union(left, right) - .expect("both attribute indices should exist"); - - // Keep track of the predicate. - self.eq_predicates.insert(predicate); - } - - /// Determine if two attributes are in the same set. - pub fn is_eq(&mut self, left: &BaseTableAttrRef, right: &BaseTableAttrRef) -> bool { - self.disjoint_eq_attr_sets - .same_set(left, right) - .unwrap_or(false) - } - - pub fn contains(&self, base_attr_ref: &BaseTableAttrRef) -> bool { - self.disjoint_eq_attr_sets.contains(base_attr_ref) - } - - /// Get the number of attributes that are equal to `attr`, including `attr` itself. - pub fn num_eq_attributes(&mut self, attr: &BaseTableAttrRef) -> usize { - self.disjoint_eq_attr_sets.set_size(attr).unwrap() - } - - /// Find the set of predicates that define the equality of the set of attributes `attr` belongs to. - pub fn find_predicates_for_eq_attr_set(&mut self, attr: &BaseTableAttrRef) -> Vec { - let mut predicates = Vec::new(); - for predicate in &self.eq_predicates { - let left = &predicate.left; - let right = &predicate.right; - if (left != attr && self.disjoint_eq_attr_sets.same_set(attr, left).unwrap()) - || (right != attr && self.disjoint_eq_attr_sets.same_set(attr, right).unwrap()) - { - predicates.push(predicate.clone()); - } - } - predicates - } - - /// Find the set of attributes that define the equality of the set of attributes `attr` belongs to. - pub fn find_attrs_for_eq_attribute_set( - &mut self, - attr: &BaseTableAttrRef, - ) -> HashSet { - let predicates = self.find_predicates_for_eq_attr_set(attr); - predicates - .into_iter() - .flat_map(|predicate| vec![predicate.left, predicate.right]) - .collect() - } - - /// Union two `EqBaseTableattributesets` to produce a new disjoint sets. - pub fn union(x: Self, y: Self) -> Self { - let mut eq_attr_sets = Self::new(); - for predicate in x - .eq_predicates - .into_iter() - .chain(y.eq_predicates.into_iter()) - { - eq_attr_sets.add_predicate(predicate); - } - eq_attr_sets - } - - pub fn merge(x: Option, y: Option) -> Option { - let eq_attr_sets = match (x, y) { - (Some(x), Some(y)) => Self::union(x, y), - (Some(x), None) => x.clone(), - (None, Some(y)) => y.clone(), - _ => return None, - }; - Some(eq_attr_sets) - } -} - -/// [`GroupAttrRefs`] represents the attributes of a group in a query. -#[derive(Clone, Debug, Default)] -pub struct GroupAttrRefs { - attr_refs: AttrRefs, - /// Correlation of the output attributes of the group. - output_correlation: Option, -} - -impl GroupAttrRefs { - pub fn new(attribute_refs: AttrRefs, output_correlation: Option) -> Self { - Self { - attr_refs: attribute_refs, - output_correlation, - } - } - - pub fn attr_refs(&self) -> &AttrRefs { - &self.attr_refs - } - - pub fn output_correlation(&self) -> Option<&SemanticCorrelation> { - self.output_correlation.as_ref() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_eq_base_table_attribute_sets() { - let attr1 = BaseTableAttrRef { - table_id: TableId(1), - attr_idx: 1, - }; - let attr2 = BaseTableAttrRef { - table_id: TableId(2), - attr_idx: 2, - }; - let attr3 = BaseTableAttrRef { - table_id: TableId(3), - attr_idx: 3, - }; - let attr4 = BaseTableAttrRef { - table_id: TableId(4), - attr_idx: 4, - }; - let pred1 = EqPredicate::new(attr1.clone(), attr2.clone()); - let pred2 = EqPredicate::new(attr3.clone(), attr4.clone()); - let pred3 = EqPredicate::new(attr1.clone(), attr3.clone()); - - let mut eq_attr_sets = SemanticCorrelation::new(); - - // (1, 2) - eq_attr_sets.add_predicate(pred1.clone()); - assert!(eq_attr_sets.is_eq(&attr1, &attr2)); - - // (1, 2), (3, 4) - eq_attr_sets.add_predicate(pred2.clone()); - assert!(eq_attr_sets.is_eq(&attr3, &attr4)); - assert!(!eq_attr_sets.is_eq(&attr2, &attr3)); - - let predicates = eq_attr_sets.find_predicates_for_eq_attr_set(&attr1); - assert_eq!(predicates.len(), 1); - assert!(predicates.contains(&pred1)); - - let predicates = eq_attr_sets.find_predicates_for_eq_attr_set(&attr3); - assert_eq!(predicates.len(), 1); - assert!(predicates.contains(&pred2)); - - // (1, 2, 3, 4) - eq_attr_sets.add_predicate(pred3.clone()); - assert!(eq_attr_sets.is_eq(&attr1, &attr3)); - assert!(eq_attr_sets.is_eq(&attr2, &attr4)); - assert!(eq_attr_sets.is_eq(&attr1, &attr4)); - - let predicates = eq_attr_sets.find_predicates_for_eq_attr_set(&attr1); - assert_eq!(predicates.len(), 3); - assert!(predicates.contains(&pred1)); - assert!(predicates.contains(&pred2)); - assert!(predicates.contains(&pred3)); - } -} diff --git a/optd-cost-model/src/common/properties/mod.rs b/optd-cost-model/src/common/properties/mod.rs deleted file mode 100644 index a90d634..0000000 --- a/optd-cost-model/src/common/properties/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use super::predicates::constant_pred::ConstantType; - -pub mod attr_ref; -pub mod schema; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Attribute { - pub name: String, - pub typ: ConstantType, - pub nullable: bool, -} - -impl std::fmt::Display for Attribute { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.nullable { - write!(f, "{}:{:?}", self.name, self.typ) - } else { - write!(f, "{}:{:?}(non-null)", self.name, self.typ) - } - } -} - -impl Attribute { - pub fn new(name: String, typ: ConstantType, nullable: bool) -> Self { - Self { - name, - typ, - nullable, - } - } - - pub fn new_non_null_int64(name: String) -> Self { - Self { - name, - typ: ConstantType::Int64, - nullable: false, - } - } -} diff --git a/optd-cost-model/src/common/properties/schema.rs b/optd-cost-model/src/common/properties/schema.rs deleted file mode 100644 index d25a23a..0000000 --- a/optd-cost-model/src/common/properties/schema.rs +++ /dev/null @@ -1,41 +0,0 @@ -use itertools::Itertools; - -use serde::{Deserialize, Serialize}; - -use super::Attribute; - -/// [`Schema`] represents the schema of a group in the memo. It contains a list of attributes. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Schema { - pub attributes: Vec, -} - -impl std::fmt::Display for Schema { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "[{}]", - self.attributes.iter().map(|x| x.to_string()).join(", ") - ) - } -} - -impl Schema { - pub fn new(attributes: Vec) -> Self { - Self { attributes } - } - - pub fn len(&self) -> usize { - self.attributes.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl From> for Schema { - fn from(attributes: Vec) -> Self { - Self::new(attributes) - } -} diff --git a/optd-cost-model/src/common/types.rs b/optd-cost-model/src/common/types.rs deleted file mode 100644 index fecd143..0000000 --- a/optd-cost-model/src/common/types.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::fmt::Display; - -/// TODO: Implement from and to methods for the following types to enable conversion -/// to and from their persistent counterparts. - -/// TODO: documentation -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct GroupId(pub u64); - -/// TODO: documentation -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct ExprId(pub u64); - -/// TODO: documentation -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct TableId(pub u64); - -/// TODO: documentation -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct AttrId(pub u64); - -/// TODO: documentation -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct EpochId(pub u64); - -impl Display for GroupId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "!{}", self.0) - } -} - -impl Display for ExprId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl Display for TableId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Table#{}", self.0) - } -} - -impl Display for AttrId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Attr#{}", self.0) - } -} - -impl Display for EpochId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Epoch#{}", self.0) - } -} - -impl From for i32 { - fn from(id: GroupId) -> i32 { - id.0 as i32 - } -} - -impl From for i32 { - fn from(id: ExprId) -> i32 { - id.0 as i32 - } -} - -impl From for i32 { - fn from(id: TableId) -> i32 { - id.0 as i32 - } -} - -impl From for i32 { - fn from(id: AttrId) -> i32 { - id.0 as i32 - } -} - -impl From for i32 { - fn from(id: EpochId) -> i32 { - id.0 as i32 - } -} diff --git a/optd-cost-model/src/common/values.rs b/optd-cost-model/src/common/values.rs deleted file mode 100644 index 7561f0b..0000000 --- a/optd-cost-model/src/common/values.rs +++ /dev/null @@ -1,205 +0,0 @@ -use arrow_schema::DataType; -use chrono::NaiveDate; -use ordered_float::OrderedFloat; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::sync::Arc; - -/// TODO: documentation -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct SerializableOrderedF64(pub OrderedFloat); - -/// TODO: documentation -impl Serialize for SerializableOrderedF64 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // Directly serialize the inner f64 value of the OrderedFloat - self.0 .0.serialize(serializer) - } -} - -/// TODO: documentation -impl<'de> Deserialize<'de> for SerializableOrderedF64 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // Deserialize an f64 and wrap it in an OrderedFloat - let float = f64::deserialize(deserializer)?; - Ok(SerializableOrderedF64(OrderedFloat(float))) - } -} - -/// TODO: documentation -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub enum Value { - UInt8(u8), - UInt16(u16), - UInt32(u32), - UInt64(u64), - Int8(i8), - Int16(i16), - Int32(i32), - Int64(i64), - Int128(i128), - Float(SerializableOrderedF64), - String(Arc), - Bool(bool), - Date32(i32), - Decimal128(i128), - Serialized(Arc<[u8]>), -} - -impl std::fmt::Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::UInt8(x) => write!(f, "{x}(u8)"), - Self::UInt16(x) => write!(f, "{x}(u16)"), - Self::UInt32(x) => write!(f, "{x}(u32)"), - Self::UInt64(x) => write!(f, "{x}(u64)"), - Self::Int8(x) => write!(f, "{x}(i8)"), - Self::Int16(x) => write!(f, "{x}(i16)"), - Self::Int32(x) => write!(f, "{x}(i32)"), - Self::Int64(x) => write!(f, "{x}(i64)"), - Self::Int128(x) => write!(f, "{x}(i128)"), - Self::Float(x) => write!(f, "{}(float)", x.0), - Self::String(x) => write!(f, "\"{x}\""), - Self::Bool(x) => write!(f, "{x}"), - Self::Date32(x) => write!(f, "{x}(date32)"), - Self::Decimal128(x) => write!(f, "{x}(decimal128)"), - Self::Serialized(x) => write!(f, "", x.len()), - } - } -} - -/// TODO: documentation -/// The `as_*()` functions do not perform conversions. This is *unlike* the `as` -/// keyword in rust. -/// -/// If you want to perform conversions, use the `to_*()` functions. -impl Value { - pub fn as_u8(&self) -> u8 { - match self { - Value::UInt8(i) => *i, - _ => panic!("Value is not an u8"), - } - } - - pub fn as_u16(&self) -> u16 { - match self { - Value::UInt16(i) => *i, - _ => panic!("Value is not an u16"), - } - } - - pub fn as_u32(&self) -> u32 { - match self { - Value::UInt32(i) => *i, - _ => panic!("Value is not an u32"), - } - } - - pub fn as_u64(&self) -> u64 { - match self { - Value::UInt64(i) => *i, - _ => panic!("Value is not an u64"), - } - } - - pub fn as_i8(&self) -> i8 { - match self { - Value::Int8(i) => *i, - _ => panic!("Value is not an i8"), - } - } - - pub fn as_i16(&self) -> i16 { - match self { - Value::Int16(i) => *i, - _ => panic!("Value is not an i16"), - } - } - - pub fn as_i32(&self) -> i32 { - match self { - Value::Int32(i) => *i, - _ => panic!("Value is not an i32"), - } - } - - pub fn as_i64(&self) -> i64 { - match self { - Value::Int64(i) => *i, - _ => panic!("Value is not an i64"), - } - } - - pub fn as_i128(&self) -> i128 { - match self { - Value::Int128(i) => *i, - _ => panic!("Value is not an i128"), - } - } - - pub fn as_f64(&self) -> f64 { - match self { - Value::Float(i) => *i.0, - _ => panic!("Value is not an f64"), - } - } - - pub fn as_bool(&self) -> bool { - match self { - Value::Bool(i) => *i, - _ => panic!("Value is not a bool"), - } - } - - pub fn as_str(&self) -> Arc { - match self { - Value::String(i) => i.clone(), - _ => panic!("Value is not a string"), - } - } - - pub fn as_slice(&self) -> Arc<[u8]> { - match self { - Value::Serialized(i) => i.clone(), - _ => panic!("Value is not a serialized"), - } - } - - pub fn convert_to_type(&self, typ: DataType) -> Value { - match typ { - DataType::Int32 => Value::Int32(match self { - Value::Int32(i32) => *i32, - Value::Int64(i64) => (*i64).try_into().unwrap(), - _ => panic!("{self} could not be converted into an Int32"), - }), - DataType::Int64 => Value::Int64(match self { - Value::Int64(i64) => *i64, - Value::Int32(i32) => (*i32).into(), - _ => panic!("{self} could not be converted into an Int64"), - }), - DataType::UInt64 => Value::UInt64(match self { - Value::Int64(i64) => (*i64).try_into().unwrap(), - Value::UInt64(i64) => *i64, - Value::UInt32(i32) => (*i32).into(), - _ => panic!("{self} could not be converted into an UInt64"), - }), - DataType::Date32 => Value::Date32(match self { - Value::Date32(date32) => *date32, - Value::String(str) => { - let date = NaiveDate::parse_from_str(str, "%Y-%m-%d").unwrap(); - let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(); - let duration_since_epoch = date.signed_duration_since(epoch); - let days_since_epoch: i32 = duration_since_epoch.num_days() as i32; - days_since_epoch - } - _ => panic!("{self} could not be converted into an Date32"), - }), - _ => unimplemented!("Have not implemented convert_to_type for DataType {typ}"), - } - } -} diff --git a/optd-cost-model/src/cost/agg.rs b/optd-cost-model/src/cost/agg.rs deleted file mode 100644 index 62c88d3..0000000 --- a/optd-cost-model/src/cost/agg.rs +++ /dev/null @@ -1,198 +0,0 @@ -use crate::{ - common::{ - nodes::{ArcPredicateNode, PredicateType, ReprPredicateNode}, - predicates::{attr_index_pred::AttrIndexPred, list_pred::ListPred}, - properties::attr_ref::{AttrRef, BaseTableAttrRef}, - types::GroupId, - }, - cost_model::CostModelImpl, - stats::DEFAULT_NUM_DISTINCT, - storage::CostModelStorageManager, - CostModelResult, EstimatedStatistic, SemanticError, -}; - -impl CostModelImpl { - pub async fn get_agg_row_cnt( - &self, - group_id: GroupId, - group_by: ArcPredicateNode, - ) -> CostModelResult { - let group_by = ListPred::from_pred_node(group_by).unwrap(); - if group_by.is_empty() { - Ok(EstimatedStatistic(1.0)) - } else { - // Multiply the n-distinct of all the group by columns. - // TODO: improve with multi-dimensional n-distinct - let mut row_cnt = 1; - - for node in &group_by.0.children { - match node.typ { - PredicateType::AttrIndex => { - let attr_ref = - AttrIndexPred::from_pred_node(node.clone()).ok_or_else(|| { - SemanticError::InvalidPredicate( - "Expected AttributeRef predicate".to_string(), - ) - })?; - if let AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) = - self.memo.get_attribute_ref(group_id, attr_ref.attr_index()) - { - // TODO: Only query ndistinct instead of all kinds of stats. - let stats_option = - self.get_attribute_comb_stats(table_id, &[attr_idx]).await?; - - let ndistinct = match stats_option { - Some(stats) => stats.ndistinct, - None => { - // The column type is not supported or stats are missing. - DEFAULT_NUM_DISTINCT - } - }; - row_cnt *= ndistinct; - } else { - // TOOD: Handle derived attributes. - row_cnt *= DEFAULT_NUM_DISTINCT; - } - } - _ => { - // TODO: Consider the case where `GROUP BY 1`. - panic!("GROUP BY must have attribute ref predicate"); - } - } - } - Ok(EstimatedStatistic(row_cnt as f64)) - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::{ - common::predicates::constant_pred::ConstantType, - stats::{utilities::simple_map::SimpleMap, MostCommonValues, DEFAULT_NUM_DISTINCT}, - test_utils::tests::{ - attr_index, create_mock_cost_model_with_attr_types, empty_list, list, - TestPerAttributeStats, TEST_ATTR1_BASE_INDEX, TEST_ATTR2_BASE_INDEX, - TEST_ATTR3_BASE_INDEX, TEST_GROUP1_ID, TEST_TABLE1_ID, - }, - EstimatedStatistic, - }; - - #[tokio::test] - async fn test_agg_no_stats() { - let cost_model = create_mock_cost_model_with_attr_types( - vec![TEST_TABLE1_ID], - vec![], - vec![HashMap::from([ - (TEST_ATTR1_BASE_INDEX, ConstantType::Int32), - (TEST_ATTR2_BASE_INDEX, ConstantType::Int32), - ])], - vec![None], - ); - - // Group by empty list should return 1. - let group_bys = empty_list(); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic(1.0) - ); - - // Group by single column should return the default value since there are no stats. - let group_bys = list(vec![attr_index(0)]); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic(DEFAULT_NUM_DISTINCT as f64) - ); - - // Group by two columns should return the default value squared since there are no stats. - let group_bys = list(vec![attr_index(0), attr_index(1)]); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic((DEFAULT_NUM_DISTINCT * DEFAULT_NUM_DISTINCT) as f64) - ); - } - - #[tokio::test] - async fn test_agg_with_stats() { - let attr1_ndistinct = 12; - let attr2_ndistinct = 645; - let attr1_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - None, - attr1_ndistinct, - 0.0, - ); - let attr2_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - None, - attr2_ndistinct, - 0.0, - ); - - let cost_model = create_mock_cost_model_with_attr_types( - vec![TEST_TABLE1_ID], - vec![HashMap::from([ - (TEST_ATTR1_BASE_INDEX, attr1_stats), - (TEST_ATTR2_BASE_INDEX, attr2_stats), - ])], - vec![HashMap::from([ - (TEST_ATTR1_BASE_INDEX, ConstantType::Int32), - (TEST_ATTR2_BASE_INDEX, ConstantType::Int32), - (TEST_ATTR3_BASE_INDEX, ConstantType::Int32), - ])], - vec![None], - ); - - // Group by empty list should return 1. - let group_bys = empty_list(); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic(1.0) - ); - - // Group by single column should return the n-distinct of the column. - let group_bys = list(vec![attr_index(0)]); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic(attr1_ndistinct as f64) - ); - - // Group by two columns should return the product of the n-distinct of the columns. - let group_bys = list(vec![attr_index(0), attr_index(1)]); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic((attr1_ndistinct * attr2_ndistinct) as f64) - ); - - // Group by multiple columns should return the product of the n-distinct of the columns. If one of the columns - // does not have stats, it should use the default value instead. - let group_bys = list(vec![attr_index(0), attr_index(1), attr_index(2)]); - assert_eq!( - cost_model - .get_agg_row_cnt(TEST_GROUP1_ID, group_bys) - .await - .unwrap(), - EstimatedStatistic((attr1_ndistinct * attr2_ndistinct * DEFAULT_NUM_DISTINCT) as f64) - ); - } -} diff --git a/optd-cost-model/src/cost/filter/attribute.rs b/optd-cost-model/src/cost/filter/attribute.rs deleted file mode 100644 index 68dd9a1..0000000 --- a/optd-cost-model/src/cost/filter/attribute.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::ops::Bound; - -use crate::{ - common::{types::TableId, values::Value}, - cost_model::CostModelImpl, - stats::{AttributeCombValue, AttributeCombValueStats, DEFAULT_EQ_SEL, DEFAULT_INEQ_SEL}, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - /// Get the selectivity of an expression of the form "attribute equals value" (or "value equals - /// attribute") Will handle the case of statistics missing - /// Equality predicates are handled entirely differently from range predicates so this is its - /// own function - /// Also, get_attribute_equality_selectivity is a subroutine when computing range selectivity, - /// which is another reason for separating these into two functions is_eq means whether it's == or != - /// - /// Currently, we only support calculating the equality selectivity for an existed attribute, - /// not a derived attribute. - /// TODO: Support derived attributes. - pub(crate) async fn get_attribute_equality_selectivity( - &self, - table_id: TableId, - attr_base_index: u64, - value: &Value, - is_eq: bool, - ) -> CostModelResult { - let ret_sel = { - if let Some(attribute_stats) = self - .get_attribute_comb_stats(table_id, &[attr_base_index]) - .await? - { - let eq_freq = - if let Some(freq) = attribute_stats.mcvs.freq(&vec![Some(value.clone())]) { - freq - } else { - let non_mcv_freq = 1.0 - attribute_stats.mcvs.total_freq(); - // always safe because usize is at least as large as i32 - let ndistinct_as_usize = attribute_stats.ndistinct as usize; - let non_mcv_cnt = ndistinct_as_usize - attribute_stats.mcvs.cnt(); - if non_mcv_cnt == 0 { - return Ok(0.0); - } - // note that nulls are not included in ndistinct so we don't need to do non_mcv_cnt - // - 1 if null_frac > 0 - (non_mcv_freq - attribute_stats.null_frac) / (non_mcv_cnt as f64) - }; - if is_eq { - eq_freq - } else { - 1.0 - eq_freq - attribute_stats.null_frac - } - } else { - #[allow(clippy::collapsible_else_if)] - if is_eq { - DEFAULT_EQ_SEL - } else { - 1.0 - DEFAULT_EQ_SEL - } - } - }; - - assert!( - (0.0..=1.0).contains(&ret_sel), - "ret_sel ({}) should be in [0, 1]", - ret_sel - ); - Ok(ret_sel) - } - - /// Compute the frequency of values in a attribute less than or equal to the given value. - fn get_attribute_leq_value_freq( - per_attribute_stats: &AttributeCombValueStats, - value: &Value, - ) -> f64 { - // because distr does not include the values in MCVs, we need to compute the CDFs there as - // well because nulls return false in any comparison, they are never included when - // computing range selectivity - let distr_leq_freq = per_attribute_stats.distr.as_ref().unwrap().cdf(value); - let value = value.clone(); - let pred = Box::new(move |val: &AttributeCombValue| *val[0].as_ref().unwrap() <= value); - let mcvs_leq_freq = per_attribute_stats.mcvs.freq_over_pred(pred); - let ret_freq = distr_leq_freq + mcvs_leq_freq; - assert!( - (0.0..=1.0).contains(&ret_freq), - "ret_freq ({}) should be in [0, 1]", - ret_freq - ); - ret_freq - } - - /// Compute the frequency of values in a attribute less than the given value. - /// - /// Currently, we only support calculating the equality selectivity for an existed attribute, - /// not a derived attribute. - /// TODO: Support derived attributes. - async fn get_attribute_lt_value_freq( - &self, - attribute_stats: &AttributeCombValueStats, - table_id: TableId, - attr_base_index: u64, - value: &Value, - ) -> CostModelResult { - // depending on whether value is in mcvs or not, we use different logic to turn total_lt_cdf - // into total_leq_cdf this logic just so happens to be the exact same logic as - // get_attribute_equality_selectivity implements - let ret_freq = Self::get_attribute_leq_value_freq(attribute_stats, value) - - self - .get_attribute_equality_selectivity(table_id, attr_base_index, value, true) - .await?; - assert!( - (0.0..=1.0).contains(&ret_freq), - "ret_freq ({}) should be in [0, 1]", - ret_freq - ); - Ok(ret_freq) - } - - /// Get the selectivity of an expression of the form "attribute =/> value" (or "value - /// =/> attribute"). Computes selectivity based off of statistics. - /// Range predicates are handled entirely differently from equality predicates so this is its - /// own function. If it is unable to find the statistics, it returns DEFAULT_INEQ_SEL. - /// The selectivity is computed as quantile of the right bound minus quantile of the left bound. - /// - /// Currently, we only support calculating the equality selectivity for an existed attribute, - /// not a derived attribute. - /// TODO: Support derived attributes. - pub(crate) async fn get_attribute_range_selectivity( - &self, - table_id: TableId, - attr_base_index: u64, - start: Bound<&Value>, - end: Bound<&Value>, - ) -> CostModelResult { - // TODO: Consider attribute is a derived attribute - if let Some(attribute_stats) = self - .get_attribute_comb_stats(table_id, &[attr_base_index]) - .await? - { - let left_quantile = match start { - Bound::Unbounded => 0.0, - Bound::Included(value) => { - self.get_attribute_lt_value_freq( - &attribute_stats, - table_id, - attr_base_index, - value, - ) - .await? - } - Bound::Excluded(value) => { - Self::get_attribute_leq_value_freq(&attribute_stats, value) - } - }; - let right_quantile = match end { - Bound::Unbounded => 1.0, - Bound::Included(value) => { - Self::get_attribute_leq_value_freq(&attribute_stats, value) - } - Bound::Excluded(value) => { - self.get_attribute_lt_value_freq( - &attribute_stats, - table_id, - attr_base_index, - value, - ) - .await? - } - }; - assert!( - left_quantile <= right_quantile, - "left_quantile ({}) should be <= right_quantile ({})", - left_quantile, - right_quantile - ); - Ok(right_quantile - left_quantile) - } else { - Ok(DEFAULT_INEQ_SEL) - } - } -} diff --git a/optd-cost-model/src/cost/filter/comp_op.rs b/optd-cost-model/src/cost/filter/comp_op.rs deleted file mode 100644 index 526c901..0000000 --- a/optd-cost-model/src/cost/filter/comp_op.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::ops::Bound; - -use crate::{ - common::{ - nodes::{ArcPredicateNode, PredicateType, ReprPredicateNode}, - predicates::{ - attr_index_pred::AttrIndexPred, bin_op_pred::BinOpType, cast_pred::CastPred, - constant_pred::ConstantPred, - }, - properties::attr_ref::{AttrRef, BaseTableAttrRef}, - types::GroupId, - values::Value, - }, - cost_model::CostModelImpl, - stats::{DEFAULT_EQ_SEL, DEFAULT_INEQ_SEL, UNIMPLEMENTED_SEL}, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - /// Comparison operators are the base case for recursion in get_filter_selectivity() - pub(crate) async fn get_comp_op_selectivity( - &self, - group_id: GroupId, - comp_bin_op_typ: BinOpType, - left: ArcPredicateNode, - right: ArcPredicateNode, - ) -> CostModelResult { - assert!(comp_bin_op_typ.is_comparison()); - - // I intentionally performed moves on left and right. This way, we don't accidentally use - // them after this block - let semantic_res = self.get_semantic_nodes(group_id, left, right).await; - if semantic_res.is_err() { - return Ok(Self::get_default_comparison_op_selectivity(comp_bin_op_typ)); - } - let (attr_ref_exprs, values, non_attr_ref_exprs, is_left_attr_ref) = semantic_res.unwrap(); - - // Handle the different cases of semantic nodes. - if attr_ref_exprs.is_empty() { - Ok(UNIMPLEMENTED_SEL) - } else if attr_ref_exprs.len() == 1 { - let attr_ref_expr = attr_ref_exprs - .first() - .expect("we just checked that attr_ref_exprs.len() == 1"); - let attr_ref_idx = attr_ref_expr.attr_index(); - - if let AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) = - self.memo.get_attribute_ref(group_id, attr_ref_idx) - { - if values.len() == 1 { - let value = values - .first() - .expect("we just checked that values.len() == 1"); - match comp_bin_op_typ { - BinOpType::Eq => { - self.get_attribute_equality_selectivity(table_id, attr_idx, value, true) - .await - } - BinOpType::Neq => { - self.get_attribute_equality_selectivity( - table_id, - attr_ref_idx, - value, - false, - ) - .await - } - BinOpType::Lt | BinOpType::Leq | BinOpType::Gt | BinOpType::Geq => { - let start = match (comp_bin_op_typ, is_left_attr_ref) { - (BinOpType::Lt, true) | (BinOpType::Geq, false) => Bound::Unbounded, - (BinOpType::Leq, true) | (BinOpType::Gt, false) => Bound::Unbounded, - (BinOpType::Gt, true) | (BinOpType::Leq, false) => Bound::Excluded(value), - (BinOpType::Geq, true) | (BinOpType::Lt, false) => Bound::Included(value), - _ => unreachable!("all comparison BinOpTypes were enumerated. this should be unreachable"), - }; - let end = match (comp_bin_op_typ, is_left_attr_ref) { - (BinOpType::Lt, true) | (BinOpType::Geq, false) => Bound::Excluded(value), - (BinOpType::Leq, true) | (BinOpType::Gt, false) => Bound::Included(value), - (BinOpType::Gt, true) | (BinOpType::Leq, false) => Bound::Unbounded, - (BinOpType::Geq, true) | (BinOpType::Lt, false) => Bound::Unbounded, - _ => unreachable!("all comparison BinOpTypes were enumerated. this should be unreachable"), - }; - self.get_attribute_range_selectivity(table_id, attr_ref_idx, start, end) - .await - } - _ => unreachable!( - "all comparison BinOpTypes were enumerated. this should be unreachable" - ), - } - } else { - let non_attr_ref_expr = non_attr_ref_exprs.first().expect( - "non_attr_ref_exprs should have a value since attr_ref_exprs.len() == 1", - ); - - match non_attr_ref_expr.as_ref().typ { - PredicateType::BinOp(_) => { - Ok(Self::get_default_comparison_op_selectivity(comp_bin_op_typ)) - } - PredicateType::Cast => Ok(UNIMPLEMENTED_SEL), - PredicateType::Constant(_) => { - unreachable!( - "we should have handled this in the values.len() == 1 branch" - ) - } - _ => unimplemented!( - "unhandled case of comparing a attribute ref node to {}", - non_attr_ref_expr.as_ref().typ - ), - } - } - } else { - // TODO: attribute is derived - Ok(Self::get_default_comparison_op_selectivity(comp_bin_op_typ)) - } - } else if attr_ref_exprs.len() == 2 { - Ok(Self::get_default_comparison_op_selectivity(comp_bin_op_typ)) - } else { - unreachable!("we could have at most pushed left and right into attr_ref_exprs") - } - } - - /// Convert the left and right child nodes of some operation to what they semantically are. - /// This is convenient to avoid repeating the same logic just with "left" and "right" swapped. - /// The last return value is true when the input node (left) is a AttributeRefPred. - #[allow(clippy::type_complexity)] - async fn get_semantic_nodes( - &self, - group_id: GroupId, - left: ArcPredicateNode, - right: ArcPredicateNode, - ) -> CostModelResult<(Vec, Vec, Vec, bool)> { - let mut attr_ref_exprs = vec![]; - let mut values = vec![]; - let mut non_attr_ref_exprs = vec![]; - let is_left_attr_ref; - - // Recursively unwrap casts as much as we can. - let mut uncasted_left = left; - let mut uncasted_right = right; - loop { - // println!("loop {}, uncasted_left={:?}, uncasted_right={:?}", Local::now(), - // uncasted_left, uncasted_right); - if uncasted_left.as_ref().typ == PredicateType::Cast - && uncasted_right.as_ref().typ == PredicateType::Cast - { - let left_cast_expr = CastPred::from_pred_node(uncasted_left) - .expect("we already checked that the type is Cast"); - let right_cast_expr = CastPred::from_pred_node(uncasted_right) - .expect("we already checked that the type is Cast"); - assert!(left_cast_expr.cast_to() == right_cast_expr.cast_to()); - uncasted_left = left_cast_expr.child().into_pred_node(); - uncasted_right = right_cast_expr.child().into_pred_node(); - } else if uncasted_left.as_ref().typ == PredicateType::Cast - || uncasted_right.as_ref().typ == PredicateType::Cast - { - let is_left_cast = uncasted_left.as_ref().typ == PredicateType::Cast; - let (mut cast_node, mut non_cast_node) = if is_left_cast { - (uncasted_left, uncasted_right) - } else { - (uncasted_right, uncasted_left) - }; - - let cast_expr = CastPred::from_pred_node(cast_node) - .expect("we already checked that the type is Cast"); - let cast_expr_child = cast_expr.child().into_pred_node(); - let cast_expr_cast_to = cast_expr.cast_to(); - - let should_break = match cast_expr_child.typ { - PredicateType::Constant(_) => { - cast_node = ConstantPred::new( - ConstantPred::from_pred_node(cast_expr_child) - .expect("we already checked that the type is Constant") - .value() - .convert_to_type(cast_expr_cast_to), - ) - .into_pred_node(); - false - } - PredicateType::AttrIndex => { - let attr_ref_expr = AttrIndexPred::from_pred_node(cast_expr_child) - .expect("we already checked that the type is AttributeRef"); - let attr_ref_idx = attr_ref_expr.attr_index(); - cast_node = attr_ref_expr.into_pred_node(); - // The "invert" cast is to invert the cast so that we're casting the - // non_cast_node to the attribute's original type. - let attribute_info = self.memo.get_attribute_info(group_id, attr_ref_idx); - let invert_cast_data_type = &attribute_info.typ.into_data_type(); - - match non_cast_node.typ { - PredicateType::AttrIndex => { - // In general, there's no way to remove the Cast here. We can't move - // the Cast to the other AttributeRef - // because that would lead to an infinite loop. Thus, we just leave - // the cast where it is and break. - true - } - _ => { - non_cast_node = - CastPred::new(non_cast_node, invert_cast_data_type.clone()) - .into_pred_node(); - false - } - } - } - _ => todo!(), - }; - - (uncasted_left, uncasted_right) = if is_left_cast { - (cast_node, non_cast_node) - } else { - (non_cast_node, cast_node) - }; - - if should_break { - break; - } - } else { - break; - } - } - - // Sort nodes into attr_ref_exprs, values, and non_attr_ref_exprs - match uncasted_left.as_ref().typ { - PredicateType::AttrIndex => { - is_left_attr_ref = true; - attr_ref_exprs.push( - AttrIndexPred::from_pred_node(uncasted_left) - .expect("we already checked that the type is AttributeRef"), - ); - } - PredicateType::Constant(_) => { - is_left_attr_ref = false; - values.push( - ConstantPred::from_pred_node(uncasted_left) - .expect("we already checked that the type is Constant") - .value(), - ) - } - _ => { - is_left_attr_ref = false; - non_attr_ref_exprs.push(uncasted_left); - } - } - match uncasted_right.as_ref().typ { - PredicateType::AttrIndex => { - attr_ref_exprs.push( - AttrIndexPred::from_pred_node(uncasted_right) - .expect("we already checked that the type is AttributeRef"), - ); - } - PredicateType::Constant(_) => values.push( - ConstantPred::from_pred_node(uncasted_right) - .expect("we already checked that the type is Constant") - .value(), - ), - _ => { - non_attr_ref_exprs.push(uncasted_right); - } - } - - assert!(attr_ref_exprs.len() + values.len() + non_attr_ref_exprs.len() == 2); - Ok((attr_ref_exprs, values, non_attr_ref_exprs, is_left_attr_ref)) - } - - /// The default selectivity of a comparison expression - /// Used when one side of the comparison is a attribute while the other side is something too - /// complex/impossible to evaluate (subquery, UDF, another attribute, we have no stats, etc.) - fn get_default_comparison_op_selectivity(comp_bin_op_typ: BinOpType) -> f64 { - assert!(comp_bin_op_typ.is_comparison()); - match comp_bin_op_typ { - BinOpType::Eq => DEFAULT_EQ_SEL, - BinOpType::Neq => 1.0 - DEFAULT_EQ_SEL, - BinOpType::Lt | BinOpType::Leq | BinOpType::Gt | BinOpType::Geq => DEFAULT_INEQ_SEL, - _ => unreachable!( - "all comparison BinOpTypes were enumerated. this should be unreachable" - ), - } - } -} diff --git a/optd-cost-model/src/cost/filter/constant.rs b/optd-cost-model/src/cost/filter/constant.rs deleted file mode 100644 index e131bde..0000000 --- a/optd-cost-model/src/cost/filter/constant.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::{ - common::{ - nodes::{ArcPredicateNode, PredicateType}, - predicates::constant_pred::ConstantType, - values::Value, - }, - cost_model::CostModelImpl, - storage::CostModelStorageManager, -}; - -impl CostModelImpl { - pub(crate) fn get_constant_selectivity(const_node: ArcPredicateNode) -> f64 { - if let PredicateType::Constant(const_typ) = const_node.typ { - if matches!(const_typ, ConstantType::Bool) { - let value = const_node - .as_ref() - .data - .as_ref() - .expect("constants should have data"); - if let Value::Bool(bool_value) = value { - if *bool_value { - 1.0 - } else { - 0.0 - } - } else { - unreachable!( - "if the typ is ConstantType::Bool, the value should be a Value::Bool" - ) - } - } else { - panic!("selectivity is not defined on constants which are not bools") - } - } else { - panic!("get_constant_selectivity must be called on a constant") - } - } -} diff --git a/optd-cost-model/src/cost/filter/core.rs b/optd-cost-model/src/cost/filter/core.rs deleted file mode 100644 index 44651ed..0000000 --- a/optd-cost-model/src/cost/filter/core.rs +++ /dev/null @@ -1,872 +0,0 @@ -use crate::{ - common::{ - nodes::{ArcPredicateNode, PredicateType, ReprPredicateNode}, - predicates::{in_list_pred::InListPred, like_pred::LikePred, un_op_pred::UnOpType}, - types::GroupId, - }, - cost_model::CostModelImpl, - stats::UNIMPLEMENTED_SEL, - storage::CostModelStorageManager, - CostModelResult, EstimatedStatistic, -}; - -impl CostModelImpl { - // TODO: is it a good design to pass table_id here? I think it needs to be refactored. - // Consider to remove table_id. - pub async fn get_filter_row_cnt( - &self, - child_row_cnt: EstimatedStatistic, - group_id: GroupId, - cond: ArcPredicateNode, - ) -> CostModelResult { - let selectivity = { self.get_filter_selectivity(group_id, cond).await? }; - Ok(EstimatedStatistic((child_row_cnt.0 * selectivity).max(1.0))) - } - - pub async fn get_filter_selectivity( - &self, - group_id: GroupId, - expr_tree: ArcPredicateNode, - ) -> CostModelResult { - Box::pin(async move { - match &expr_tree.typ { - PredicateType::Constant(_) => Ok(Self::get_constant_selectivity(expr_tree)), - PredicateType::AttrIndex => unimplemented!("check bool type or else panic"), - PredicateType::UnOp(un_op_typ) => { - assert!(expr_tree.children.len() == 1); - let child = expr_tree.child(0); - match un_op_typ { - // not doesn't care about nulls so there's no complex logic. it just reverses - // the selectivity for instance, != _will not_ include nulls - // but "NOT ==" _will_ include nulls - UnOpType::Not => Ok(1.0 - self.get_filter_selectivity(group_id, child).await?), - UnOpType::Neg => panic!( - "the selectivity of operations that return numerical values is undefined" - ), - } - } - PredicateType::BinOp(bin_op_typ) => { - assert!(expr_tree.children.len() == 2); - let left_child = expr_tree.child(0); - let right_child = expr_tree.child(1); - - if bin_op_typ.is_comparison() { - self.get_comp_op_selectivity(group_id, *bin_op_typ, left_child, right_child).await - } else if bin_op_typ.is_numerical() { - panic!( - "the selectivity of operations that return numerical values is undefined" - ) - } else { - unreachable!("all BinOpTypes should be true for at least one is_*() function") - } - } - PredicateType::LogOp(log_op_typ) => { - self.get_log_op_selectivity(group_id, *log_op_typ, &expr_tree.children).await - } - PredicateType::Func(_) => unimplemented!("check bool type or else panic"), - PredicateType::SortOrder(_) => { - panic!("the selectivity of sort order expressions is undefined") - } - PredicateType::Between => Ok(UNIMPLEMENTED_SEL), - PredicateType::Cast => unimplemented!("check bool type or else panic"), - PredicateType::Like => { - let like_expr = LikePred::from_pred_node(expr_tree).unwrap(); - self.get_like_selectivity(group_id, &like_expr).await - } - PredicateType::DataType(_) => { - panic!("the selectivity of a data type is not defined") - } - PredicateType::InList => { - let in_list_expr = InListPred::from_pred_node(expr_tree).unwrap(); - self.get_in_list_selectivity(group_id, &in_list_expr).await - } - _ => unreachable!( - "all expression DfPredType were enumerated. this should be unreachable" - ), - } - }).await - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::{ - common::{ - predicates::{ - bin_op_pred::BinOpType, constant_pred::ConstantType, log_op_pred::LogOpType, - un_op_pred::UnOpType, - }, - types::TableId, - values::Value, - }, - stats::{utilities::simple_map::SimpleMap, Distribution, MostCommonValues, DEFAULT_EQ_SEL}, - test_utils::tests::*, - }; - use arrow_schema::DataType; - - #[tokio::test] - async fn test_const() { - let cost_model = create_mock_cost_model( - vec![TableId(0)], - vec![HashMap::from([(0, empty_per_attr_stats())])], - vec![None], - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, cnst(Value::Bool(true))) - .await - .unwrap(), - 1.0 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, cnst(Value::Bool(false))) - .await - .unwrap(), - 0.0 - ); - } - - #[tokio::test] - async fn test_attr_ref_eq_constint_in_mcv() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![( - vec![Some(Value::Int32(1))], - 0.3, - )])), - None, - 0, - 0.0, - ); - let table_id = TableId(0); - let cost_model = create_mock_cost_model( - vec![table_id], - vec![HashMap::from([(0, per_attribute_stats)])], - vec![None], - ); - - let expr_tree = bin_op( - BinOpType::Eq, - attr_index(0), // TODO: Fix this - cnst(Value::Int32(1)), - ); - let expr_tree_rev = bin_op( - BinOpType::Eq, - cnst(Value::Int32(1)), - attr_index(0), // TODO: Fix this - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.3 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.3 - ); - } - - #[tokio::test] - async fn test_attr_ref_eq_constint_not_in_mcv() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(1))], 0.2), - (vec![Some(Value::Int32(3))], 0.44), - ])), - None, - 5, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(2))); - let expr_tree_rev = bin_op(BinOpType::Eq, cnst(Value::Int32(2)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.12 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.12 - ); - } - - /// I only have one test for NEQ since I'll assume that it uses the same underlying logic as EQ - #[tokio::test] - async fn test_attr_ref_neq_constint_in_mcv() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![( - vec![Some(Value::Int32(1))], - 0.3, - )])), - None, - 0, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Neq, attr_index(0), cnst(Value::Int32(1))); - let expr_tree_rev = bin_op(BinOpType::Neq, cnst(Value::Int32(1)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 1.0 - 0.3 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 1.0 - 0.3 - ); - } - - #[tokio::test] - async fn test_attr_ref_leq_constint_no_mcvs_in_range() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Leq, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Gt, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.7 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.7 - ); - } - - #[tokio::test] - async fn test_attr_ref_leq_constint_with_mcvs_in_range_not_at_border() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(6))], 0.05), - (vec![Some(Value::Int32(10))], 0.1), - (vec![Some(Value::Int32(17))], 0.08), - (vec![Some(Value::Int32(25))], 0.07), - ])), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Leq, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Gt, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.85 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.85 - ); - } - - #[tokio::test] - async fn test_attr_ref_leq_constint_with_mcv_at_border() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(6))], 0.05), - (vec![Some(Value::Int32(10))], 0.1), - (vec![Some(Value::Int32(15))], 0.08), - (vec![Some(Value::Int32(25))], 0.07), - ])), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Leq, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Gt, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.93 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.93 - ); - } - - #[tokio::test] - async fn test_attr_ref_lt_constint_no_mcvs_in_range() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Lt, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Geq, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.6 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.6 - ); - } - - #[tokio::test] - async fn test_attr_ef_lt_constint_with_mcvs_in_range_not_at_border() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(6))], 0.05), - (vec![Some(Value::Int32(10))], 0.1), - (vec![Some(Value::Int32(17))], 0.08), - (vec![Some(Value::Int32(25))], 0.07), - ])), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 11, /* there are 4 MCVs which together add up to 0.3. With 11 total ndistinct, each - * remaining value has freq 0.1 */ - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Lt, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Geq, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.75 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.75 - ); - } - - #[tokio::test] - async fn test_attr_ref_lt_constint_with_mcv_at_border() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(6))], 0.05), - (vec![Some(Value::Int32(10))], 0.1), - (vec![Some(Value::Int32(15))], 0.08), - (vec![Some(Value::Int32(25))], 0.07), - ])), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 11, /* there are 4 MCVs which together add up to 0.3. With 11 total ndistinct, each - * remaining value has freq 0.1 */ - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Lt, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Geq, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.85 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.85 - ); - } - - /// I have fewer tests for GT since I'll assume that it uses the same underlying logic as LEQ - /// The only interesting thing to test is that if there are nulls, those aren't included in GT - #[tokio::test] - async fn test_attr_ref_gt_constint() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Gt, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Leq, cnst(Value::Int32(15)), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 1.0 - 0.7 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 1.0 - 0.7 - ); - } - - #[tokio::test] - async fn test_attr_ref_geq_constint() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - Some(Distribution::SimpleDistribution(SimpleMap::new(vec![( - Value::Int32(15), - 0.7, - )]))), - 10, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op(BinOpType::Geq, attr_index(0), cnst(Value::Int32(15))); - let expr_tree_rev = bin_op(BinOpType::Lt, cnst(Value::Int32(15)), attr_index(0)); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 1.0 - 0.6 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 1.0 - 0.6 - ); - } - - #[tokio::test] - async fn test_and() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(1))], 0.3), - (vec![Some(Value::Int32(5))], 0.5), - (vec![Some(Value::Int32(8))], 0.2), - ])), - None, - 0, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let eq1 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(1))); - let eq5 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(5))); - let eq8 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(8))); - let expr_tree = log_op(LogOpType::And, vec![eq1.clone(), eq5.clone(), eq8.clone()]); - let expr_tree_shift1 = log_op(LogOpType::And, vec![eq5.clone(), eq8.clone(), eq1.clone()]); - let expr_tree_shift2 = log_op(LogOpType::And, vec![eq8.clone(), eq1.clone(), eq5.clone()]); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.03 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_shift1) - .await - .unwrap(), - 0.03 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_shift2) - .await - .unwrap(), - 0.03 - ); - } - - #[tokio::test] - async fn test_or() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(1))], 0.3), - (vec![Some(Value::Int32(5))], 0.5), - (vec![Some(Value::Int32(8))], 0.2), - ])), - None, - 0, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let eq1 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(1))); - let eq5 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(5))); - let eq8 = bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(8))); - let expr_tree = log_op(LogOpType::Or, vec![eq1.clone(), eq5.clone(), eq8.clone()]); - let expr_tree_shift1 = log_op(LogOpType::Or, vec![eq5.clone(), eq8.clone(), eq1.clone()]); - let expr_tree_shift2 = log_op(LogOpType::Or, vec![eq8.clone(), eq1.clone(), eq5.clone()]); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.72 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_shift1) - .await - .unwrap(), - 0.72 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_shift2) - .await - .unwrap(), - 0.72 - ); - } - - #[tokio::test] - async fn test_not() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![( - vec![Some(Value::Int32(1))], - 0.3, - )])), - None, - 0, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = un_op( - UnOpType::Not, - bin_op(BinOpType::Eq, attr_index(0), cnst(Value::Int32(1))), - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.7 - ); - } - - // I didn't test any non-unique cases with filter. The non-unique tests without filter should - // cover that - - #[tokio::test] - async fn test_attr_ref_eq_cast_value() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![( - vec![Some(Value::Int32(1))], - 0.3, - )])), - None, - 0, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - let expr_tree = bin_op( - BinOpType::Eq, - attr_index(0), - cast(cnst(Value::Int64(1)), DataType::Int32), - ); - let expr_tree_rev = bin_op( - BinOpType::Eq, - cast(cnst(Value::Int64(1)), DataType::Int32), - attr_index(0), - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.3 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.3 - ); - } - - #[tokio::test] - async fn test_cast_attr_ref_eq_value() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![( - vec![Some(Value::Int32(1))], - 0.3, - )])), - None, - 0, - 0.1, - ); - let cost_model = create_mock_cost_model_with_attr_types( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - ConstantType::Int32, - )])], - vec![None], - ); - - let expr_tree = bin_op( - BinOpType::Eq, - cast(attr_index(0), DataType::Int64), // TODO: Fix this - cnst(Value::Int64(1)), - ); - let expr_tree_rev = bin_op( - BinOpType::Eq, - cnst(Value::Int64(1)), - cast(attr_index(0), DataType::Int64), // TODO: Fix this - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - 0.3 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - 0.3 - ); - } - - /// In this case, we should leave the Cast as is. - /// - /// Note that the test only checks the selectivity and thus doesn't explicitly test that the - /// Cast is indeed left as is. However, if get_filter_selectivity() doesn't crash, that's a - /// pretty good signal that the Cast was left as is. - #[tokio::test] - async fn test_cast_attr_ref_eq_attr_ref() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::default()), - None, - 0, - 0.0, - ); - - let cost_model = create_mock_cost_model_with_attr_types( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![HashMap::from([ - (TEST_ATTR1_BASE_INDEX, ConstantType::Int32), - (TEST_ATTR2_BASE_INDEX, ConstantType::Int64), - ])], - vec![None], - ); - - let expr_tree = bin_op( - BinOpType::Eq, - cast(attr_index(0), DataType::Int64), - attr_index(1), - ); - let expr_tree_rev = bin_op( - BinOpType::Eq, - attr_index(1), - cast(attr_index(0), DataType::Int64), - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree) - .await - .unwrap(), - DEFAULT_EQ_SEL - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_filter_selectivity(TEST_GROUP1_ID, expr_tree_rev) - .await - .unwrap(), - DEFAULT_EQ_SEL - ); - } -} diff --git a/optd-cost-model/src/cost/filter/in_list.rs b/optd-cost-model/src/cost/filter/in_list.rs deleted file mode 100644 index d8838a8..0000000 --- a/optd-cost-model/src/cost/filter/in_list.rs +++ /dev/null @@ -1,160 +0,0 @@ -use crate::{ - common::{ - nodes::{PredicateType, ReprPredicateNode}, - predicates::{ - attr_index_pred::AttrIndexPred, constant_pred::ConstantPred, in_list_pred::InListPred, - }, - properties::attr_ref::{AttrRef, BaseTableAttrRef}, - types::GroupId, - }, - cost_model::CostModelImpl, - stats::UNIMPLEMENTED_SEL, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - /// Only support attrA in (val1, val2, val3) where attrA is a attribute ref and - /// val1, val2, val3 are constants. - pub(crate) async fn get_in_list_selectivity( - &self, - group_id: GroupId, - expr: &InListPred, - ) -> CostModelResult { - let child = expr.child(); - - // Check child is a attribute ref. - if !matches!(child.typ, PredicateType::AttrIndex) { - return Ok(UNIMPLEMENTED_SEL); - } - - // Check all expressions in the list are constants. - let list_exprs = expr.list().to_vec(); - if list_exprs - .iter() - .any(|expr| !matches!(expr.typ, PredicateType::Constant(_))) - { - return Ok(UNIMPLEMENTED_SEL); - } - - // Convert child and const expressions to concrete types. - let attr_ref_pred = AttrIndexPred::from_pred_node(child).unwrap(); - let attr_ref_idx = attr_ref_pred.attr_index(); - - let list_exprs = list_exprs - .into_iter() - .map(|expr| { - ConstantPred::from_pred_node(expr) - .expect("we already checked all list elements are constants") - }) - .collect::>(); - let negated = expr.negated(); - - if let AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) = - self.memo.get_attribute_ref(group_id, attr_ref_idx) - { - let mut in_sel = 0.0; - for expr in &list_exprs { - let selectivity = self - .get_attribute_equality_selectivity( - table_id, - attr_idx, - &expr.value(), - /* is_equality */ true, - ) - .await?; - in_sel += selectivity; - } - in_sel = in_sel.min(1.0); - if negated { - Ok(1.0 - in_sel) - } else { - Ok(in_sel) - } - } else { - // TODO: Child is a derived attribute. - Ok(UNIMPLEMENTED_SEL) - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::{ - common::values::Value, - stats::{utilities::simple_map::SimpleMap, MostCommonValues}, - test_utils::tests::*, - }; - - #[tokio::test] - async fn test_in_list() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::Int32(1))], 0.8), - (vec![Some(Value::Int32(2))], 0.2), - ])), - None, - 2, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity(TEST_GROUP1_ID, &in_list(0, vec![Value::Int32(1)], false)) - .await - .unwrap(), - 0.8 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity( - TEST_GROUP1_ID, - &in_list(0, vec![Value::Int32(1), Value::Int32(2)], false) - ) - .await - .unwrap(), - 1.0 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity(TEST_GROUP1_ID, &in_list(0, vec![Value::Int32(3)], false)) - .await - .unwrap(), - 0.0 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity(TEST_GROUP1_ID, &in_list(0, vec![Value::Int32(1)], true)) - .await - .unwrap(), - 0.2 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity( - TEST_GROUP1_ID, - &in_list(0, vec![Value::Int32(1), Value::Int32(2)], true) - ) - .await - .unwrap(), - 0.0 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_in_list_selectivity(TEST_GROUP1_ID, &in_list(0, vec![Value::Int32(3)], true)) // TODO: Fix this - .await - .unwrap(), - 1.0 - ); - } -} diff --git a/optd-cost-model/src/cost/filter/like.rs b/optd-cost-model/src/cost/filter/like.rs deleted file mode 100644 index ff56f44..0000000 --- a/optd-cost-model/src/cost/filter/like.rs +++ /dev/null @@ -1,207 +0,0 @@ -use datafusion::arrow::{array::StringArray, compute::like}; - -use crate::{ - common::{ - nodes::{PredicateType, ReprPredicateNode}, - predicates::{ - attr_index_pred::AttrIndexPred, constant_pred::ConstantPred, like_pred::LikePred, - }, - properties::attr_ref::{AttrRef, BaseTableAttrRef}, - types::GroupId, - }, - cost_model::CostModelImpl, - stats::{ - AttributeCombValue, FIXED_CHAR_SEL_FACTOR, FULL_WILDCARD_SEL_FACTOR, UNIMPLEMENTED_SEL, - }, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - /// Compute the selectivity of a (NOT) LIKE expression. - /// - /// The logic is somewhat similar to Postgres but different. Postgres first estimates the - /// histogram part of the population and then add up data for any MCV values. If the - /// histogram is large enough, it just uses the number of matches in the histogram, - /// otherwise it estimates the fixed prefix and remainder of pattern separately and - /// combine them. - /// - /// Our approach is simpler and less selective. Firstly, we don't use histogram. The selectivity - /// is composed of MCV frequency and non-MCV selectivity. MCV frequency is computed by - /// adding up frequencies of MCVs that match the pattern. Non-MCV selectivity is computed - /// in the same way that Postgres computes selectivity for the wildcard part of the pattern. - pub(crate) async fn get_like_selectivity( - &self, - group_id: GroupId, - like_expr: &LikePred, - ) -> CostModelResult { - let child = like_expr.child(); - - // Check child is a attribute ref. - if !matches!(child.typ, PredicateType::AttrIndex) { - return Ok(UNIMPLEMENTED_SEL); - } - - // Check pattern is a constant. - let pattern = like_expr.pattern(); - if !matches!(pattern.typ, PredicateType::Constant(_)) { - return Ok(UNIMPLEMENTED_SEL); - } - - let attr_ref_pred = AttrIndexPred::from_pred_node(child).unwrap(); - let attr_ref_idx = attr_ref_pred.attr_index(); - - if let AttrRef::BaseTableAttrRef(BaseTableAttrRef { table_id, attr_idx }) = - self.memo.get_attribute_ref(group_id, attr_ref_idx) - { - let pattern = ConstantPred::from_pred_node(pattern) - .expect("we already checked pattern is a constant") - .value() - .as_str(); - - // Compute the selectivity exculuding MCVs. - // See Postgres `like_selectivity`. - let non_mcv_sel = pattern - .chars() - .fold(1.0, |acc, c| { - if c == '%' { - acc * FULL_WILDCARD_SEL_FACTOR - } else { - acc * FIXED_CHAR_SEL_FACTOR - } - }) - .min(1.0); - - // Compute the selectivity in MCVs. - // TODO: Handle the case where `attribute_stats` is None. - let (mut mcv_freq, mut null_frac) = (0.0, 0.0); - if let Some(attribute_stats) = - self.get_attribute_comb_stats(table_id, &[attr_idx]).await? - { - (mcv_freq, null_frac) = { - let pred = Box::new(move |val: &AttributeCombValue| { - let string = - StringArray::from(vec![val[0].as_ref().unwrap().as_str().as_ref()]); - let pattern = StringArray::from(vec![pattern.as_ref()]); - like(&string, &pattern).unwrap().value(0) - }); - ( - attribute_stats.mcvs.freq_over_pred(pred), - attribute_stats.null_frac, - ) - }; - } - let result = non_mcv_sel + mcv_freq; - - Ok(if like_expr.negated() { - 1.0 - result - null_frac - } else { - result - } - // Postgres clamps the result after histogram and before MCV. See Postgres - // `patternsel_common`. - .clamp(0.0001, 0.9999)) - } else { - // TOOD: derived attribute - Ok(UNIMPLEMENTED_SEL) - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::{ - common::values::Value, - stats::{ - utilities::{counter::Counter, simple_map::SimpleMap}, - MostCommonValues, FIXED_CHAR_SEL_FACTOR, FULL_WILDCARD_SEL_FACTOR, - }, - test_utils::tests::*, - }; - - #[tokio::test] - async fn test_like_no_nulls() { - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![ - (vec![Some(Value::String("abcd".into()))], 0.1), - (vec![Some(Value::String("abc".into()))], 0.1), - ])), - None, - 2, - 0.0, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_like_selectivity( - TEST_GROUP1_ID, - &like(TEST_ATTR1_BASE_INDEX, "%abcd%", false) - ) // TODO: Fix this - .await - .unwrap(), - 0.1 + FULL_WILDCARD_SEL_FACTOR.powi(2) * FIXED_CHAR_SEL_FACTOR.powi(4) - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_like_selectivity(TEST_GROUP1_ID, &like(TEST_ATTR1_BASE_INDEX, "%abc%", false)) // TODO: Fix this - .await - .unwrap(), - 0.1 + 0.1 + FULL_WILDCARD_SEL_FACTOR.powi(2) * FIXED_CHAR_SEL_FACTOR.powi(3) - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_like_selectivity(TEST_GROUP1_ID, &like(TEST_ATTR1_BASE_INDEX, "%abc%", true)) // TODO: Fix this - .await - .unwrap(), - 1.0 - (0.1 + 0.1 + FULL_WILDCARD_SEL_FACTOR.powi(2) * FIXED_CHAR_SEL_FACTOR.powi(3)) - ); - } - - #[tokio::test] - async fn test_like_with_nulls() { - let null_frac = 0.5; - let mut mcvs_counts = HashMap::new(); - mcvs_counts.insert(vec![Some(Value::String("abcd".into()))], 1); - let mcvs_total_count = 10; - let per_attribute_stats = TestPerAttributeStats::new( - MostCommonValues::Counter(Counter::new_from_existing(mcvs_counts, mcvs_total_count)), - None, - 2, - null_frac, - ); - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([( - TEST_ATTR1_BASE_INDEX, - per_attribute_stats, - )])], - vec![None], - ); - - assert_approx_eq::assert_approx_eq!( - cost_model - .get_like_selectivity(TEST_GROUP1_ID, &like(0, "%abcd%", false)) // TODO: Fix this - .await - .unwrap(), - 0.1 + FULL_WILDCARD_SEL_FACTOR.powi(2) * FIXED_CHAR_SEL_FACTOR.powi(4) - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_like_selectivity(TEST_GROUP1_ID, &like(0, "%abcd%", true)) // TODO: Fix this - .await - .unwrap(), - 1.0 - (0.1 + FULL_WILDCARD_SEL_FACTOR.powi(2) * FIXED_CHAR_SEL_FACTOR.powi(4)) - - null_frac - ); - } -} diff --git a/optd-cost-model/src/cost/filter/log_op.rs b/optd-cost-model/src/cost/filter/log_op.rs deleted file mode 100644 index 381584d..0000000 --- a/optd-cost-model/src/cost/filter/log_op.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{ - common::{nodes::ArcPredicateNode, predicates::log_op_pred::LogOpType, types::GroupId}, - cost_model::CostModelImpl, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - pub(crate) async fn get_log_op_selectivity( - &self, - group_id: GroupId, - log_op_typ: LogOpType, - children: &[ArcPredicateNode], - ) -> CostModelResult { - match log_op_typ { - LogOpType::And => { - let mut and_sel = 1.0; - for child in children { - let selectivity = self.get_filter_selectivity(group_id, child.clone()).await?; - and_sel *= selectivity; - } - Ok(and_sel) - } - LogOpType::Or => { - let mut or_sel_neg = 1.0; - for child in children { - let selectivity = self.get_filter_selectivity(group_id, child.clone()).await?; - or_sel_neg *= 1.0 - selectivity; - } - Ok(1.0 - or_sel_neg) - } - } - } -} diff --git a/optd-cost-model/src/cost/filter/mod.rs b/optd-cost-model/src/cost/filter/mod.rs deleted file mode 100644 index 00ea653..0000000 --- a/optd-cost-model/src/cost/filter/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod attribute; -pub mod comp_op; -pub mod constant; -pub mod core; -pub mod in_list; -pub mod like; -pub mod log_op; diff --git a/optd-cost-model/src/cost/join/core.rs b/optd-cost-model/src/cost/join/core.rs deleted file mode 100644 index 6d10fb9..0000000 --- a/optd-cost-model/src/cost/join/core.rs +++ /dev/null @@ -1,1275 +0,0 @@ -use std::collections::HashSet; - -use itertools::Itertools; - -use crate::{ - common::{ - nodes::{ArcPredicateNode, JoinType, PredicateType, ReprPredicateNode}, - predicates::{ - attr_index_pred::AttrIndexPred, - list_pred::ListPred, - log_op_pred::{LogOpPred, LogOpType}, - }, - properties::attr_ref::{ - AttrRef, AttrRefs, BaseTableAttrRef, EqPredicate, SemanticCorrelation, - }, - types::GroupId, - }, - cost::join::get_on_attr_ref_pair, - cost_model::CostModelImpl, - stats::DEFAULT_NUM_DISTINCT, - storage::CostModelStorageManager, - CostModelResult, -}; - -impl CostModelImpl { - /// The expr_tree input must be a "mixed expression tree", just like with - /// `get_filter_selectivity`. - /// - /// This is a "wrapper" to separate the equality conditions from the filter conditions before - /// calling the "main" `get_join_selectivity_core` function. - #[allow(clippy::too_many_arguments)] - pub(crate) async fn get_join_selectivity_from_expr_tree( - &self, - join_typ: JoinType, - group_id: GroupId, - expr_tree: ArcPredicateNode, - attr_refs: &AttrRefs, - input_correlation: Option, - left_row_cnt: f64, - right_row_cnt: f64, - ) -> CostModelResult { - if expr_tree.typ == PredicateType::LogOp(LogOpType::And) { - let mut on_attr_ref_pairs = vec![]; - let mut filter_expr_trees = vec![]; - for child_expr_tree in &expr_tree.children { - if let Some(on_attr_ref_pair) = - get_on_attr_ref_pair(child_expr_tree.clone(), attr_refs) - { - on_attr_ref_pairs.push(on_attr_ref_pair) - } else { - let child_expr = child_expr_tree.clone(); - filter_expr_trees.push(child_expr); - } - } - assert!(on_attr_ref_pairs.len() + filter_expr_trees.len() == expr_tree.children.len()); - let filter_expr_tree = if filter_expr_trees.is_empty() { - None - } else { - Some(LogOpPred::new(LogOpType::And, filter_expr_trees).into_pred_node()) - }; - self.get_join_selectivity_core( - join_typ, - group_id, - on_attr_ref_pairs, - filter_expr_tree, - attr_refs, - input_correlation, - left_row_cnt, - right_row_cnt, - 0, - ) - .await - } else { - #[allow(clippy::collapsible_else_if)] - if let Some(on_attr_ref_pair) = get_on_attr_ref_pair(expr_tree.clone(), attr_refs) { - self.get_join_selectivity_core( - join_typ, - group_id, - vec![on_attr_ref_pair], - None, - attr_refs, - input_correlation, - left_row_cnt, - right_row_cnt, - 0, - ) - .await - } else { - self.get_join_selectivity_core( - join_typ, - group_id, - vec![], - Some(expr_tree), - attr_refs, - input_correlation, - left_row_cnt, - right_row_cnt, - 0, - ) - .await - } - } - } - - /// A wrapper to convert the join keys to the format expected by get_join_selectivity_core() - #[allow(clippy::too_many_arguments)] - pub(crate) async fn get_join_selectivity_from_keys( - &self, - join_typ: JoinType, - group_id: GroupId, - left_keys: ListPred, - right_keys: ListPred, - attr_refs: &AttrRefs, - input_correlation: Option, - left_row_cnt: f64, - right_row_cnt: f64, - left_attr_cnt: usize, - ) -> CostModelResult { - assert!(left_keys.len() == right_keys.len()); - // I assume that the keys are already in the right order - // s.t. the ith key of left_keys corresponds with the ith key of right_keys - let on_attr_ref_pairs = left_keys - .to_vec() - .into_iter() - .zip(right_keys.to_vec()) - .map(|(left_key, right_key)| { - ( - AttrIndexPred::from_pred_node(left_key).expect("keys should be AttrRefPreds"), - AttrIndexPred::from_pred_node(right_key).expect("keys should be AttrRefPreds"), - ) - }) - .collect_vec(); - self.get_join_selectivity_core( - join_typ, - group_id, - on_attr_ref_pairs, - None, - attr_refs, - input_correlation, - left_row_cnt, - right_row_cnt, - left_attr_cnt, - ) - .await - } - - /// The core logic of join selectivity which assumes we've already separated the expression - /// into the on conditions and the filters. - /// - /// Hash join and NLJ reference right table attributes differently, hence the - /// `right_attr_ref_offset` parameter. - /// - /// For hash join, the right table attributes indices are with respect to the right table, - /// which means #0 is the first attribute of the right table. - /// - /// For NLJ, the right table attributes indices are with respect to the output of the join. - /// For example, if the left table has 3 attributes, the first attribute of the right table - /// is #3 instead of #0. - #[allow(clippy::too_many_arguments)] - async fn get_join_selectivity_core( - &self, - join_typ: JoinType, - group_id: GroupId, - on_attr_ref_pairs: Vec<(AttrIndexPred, AttrIndexPred)>, - filter_expr_tree: Option, - attr_refs: &AttrRefs, - input_correlation: Option, - left_row_cnt: f64, - right_row_cnt: f64, - right_attr_ref_offset: usize, - ) -> CostModelResult { - let join_on_selectivity = self - .get_join_on_selectivity( - &on_attr_ref_pairs, - attr_refs, - input_correlation, - right_attr_ref_offset, - ) - .await?; - // Currently, there is no difference in how we handle a join filter and a select filter, - // so we use the same function. - // - // One difference (that we *don't* care about right now) is that join filters can contain - // expressions from multiple different tables. Currently, this doesn't affect the - // get_filter_selectivity() function, but this may change in the future. - let join_filter_selectivity = match filter_expr_tree { - Some(filter_expr_tree) => { - self.get_filter_selectivity(group_id, filter_expr_tree) - .await? - } - None => 1.0, - }; - let inner_join_selectivity = join_on_selectivity * join_filter_selectivity; - - Ok(match join_typ { - JoinType::Inner => inner_join_selectivity, - JoinType::LeftOuter => f64::max(inner_join_selectivity, 1.0 / right_row_cnt), - JoinType::RightOuter => f64::max(inner_join_selectivity, 1.0 / left_row_cnt), - JoinType::Cross => { - assert!( - on_attr_ref_pairs.is_empty(), - "Cross joins should not have on attributes" - ); - join_filter_selectivity - } - _ => unimplemented!("join_typ={} is not implemented", join_typ), - }) - } - - /// Get the selectivity of one attribute eq predicate, e.g. attrA = attrB. - async fn get_join_selectivity_from_on_attr_ref_pair( - &self, - left: &AttrRef, - right: &AttrRef, - ) -> CostModelResult { - // the formula for each pair is min(1 / ndistinct1, 1 / ndistinct2) - // (see https://postgrespro.com/blog/pgsql/5969618) - let mut ndistincts = vec![]; - for attr_ref in [left, right] { - let ndistinct = match attr_ref { - AttrRef::BaseTableAttrRef(base_attr_ref) => { - match self - .get_attribute_comb_stats(base_attr_ref.table_id, &[base_attr_ref.attr_idx]) - .await? - { - Some(per_attr_stats) => per_attr_stats.ndistinct, - None => DEFAULT_NUM_DISTINCT, - } - } - AttrRef::Derived => DEFAULT_NUM_DISTINCT, - }; - ndistincts.push(ndistinct); - } - - // using reduce(f64::min) is the idiomatic workaround to min() because - // f64 does not implement Ord due to NaN - let selectivity = ndistincts.into_iter().map(|ndistinct| 1.0 / ndistinct as f64).reduce(f64::min).expect("reduce() only returns None if the iterator is empty, which is impossible since attr_ref_exprs.len() == 2"); - assert!( - !selectivity.is_nan(), - "it should be impossible for selectivity to be NaN since n-distinct is never 0" - ); - Ok(selectivity) - } - - /// Given a set of N attributes involved in a multi-equality, find the total selectivity - /// of the multi-equality. - /// - /// This is a generalization of get_join_selectivity_from_on_attr_ref_pair(). - async fn get_join_selectivity_from_most_selective_attrs( - &self, - base_attr_refs: HashSet, - ) -> CostModelResult { - assert!(base_attr_refs.len() > 1); - let num_base_attr_refs = base_attr_refs.len(); - - let mut ndistincts = vec![]; - for base_attr_ref in base_attr_refs.iter() { - let ndistinct = match self - .get_attribute_comb_stats(base_attr_ref.table_id, &[base_attr_ref.attr_idx]) - .await? - { - Some(per_attr_stats) => per_attr_stats.ndistinct, - None => DEFAULT_NUM_DISTINCT, - }; - ndistincts.push(ndistinct); - } - - Ok(ndistincts - .into_iter() - .map(|ndistinct| 1.0 / ndistinct as f64) - .sorted_by(|a, b| { - a.partial_cmp(b) - .expect("No floats should be NaN since n-distinct is never 0") - }) - .take(num_base_attr_refs - 1) - .product()) - } - - /// A predicate set defines a "multi-equality graph", which is an unweighted undirected graph. - /// The nodes are attributes while edges are predicates. The old graph is defined by - /// `past_eq_attrs` while the `predicate` is the new addition to this graph. This - /// unweighted undirected graph consists of a number of connected components, where each - /// connected component represents attributes that are set to be equal to each other. Single - /// nodes not connected to anything are considered standalone connected components. - /// - /// The selectivity of each connected component of N nodes is equal to the product of - /// 1/ndistinct of the N-1 nodes with the highest ndistinct values. You can see this if you - /// imagine that all attributes being joined are unique attributes and that they follow the - /// inclusion principle (every element of the smaller tables is present in the larger - /// tables). When these assumptions are not true, the selectivity may not be completely - /// accurate. However, it is still fairly accurate. - /// - /// However, we cannot simply add `predicate` to the multi-equality graph and compute the - /// selectivity of the entire connected component, because this would be "double counting" a - /// lot of nodes. The join(s) before this join would already have a selectivity value. Thus, - /// we compute the selectivity of the join(s) before this join (the first block of the - /// function) and then the selectivity of the connected component after this join. The - /// quotient is the "adjustment" factor. - /// - /// NOTE: This function modifies `past_eq_attrs` by adding `predicate` to it. - async fn get_join_selectivity_adjustment_when_adding_to_multi_equality_graph( - &self, - predicate: &EqPredicate, - past_eq_attrs: &mut SemanticCorrelation, - ) -> CostModelResult { - if predicate.left == predicate.right { - // self-join, TODO: is this correct? - return Ok(1.0); - } - // To find the adjustment, we need to know the selectivity of the graph before `predicate` - // is added. - // - // There are two cases: (1) adding `predicate` does not change the # of connected - // components, and (2) adding `predicate` reduces the # of connected by 1. Note that - // attributes not involved in any predicates are considered a part of the graph and are - // a connected component on their own. - let children_pred_sel = { - if past_eq_attrs.is_eq(&predicate.left, &predicate.right) { - self.get_join_selectivity_from_most_selective_attrs( - past_eq_attrs.find_attrs_for_eq_attribute_set(&predicate.left), - ) - .await? - } else { - let left_sel = if past_eq_attrs.contains(&predicate.left) { - self.get_join_selectivity_from_most_selective_attrs( - past_eq_attrs.find_attrs_for_eq_attribute_set(&predicate.left), - ) - .await? - } else { - 1.0 - }; - let right_sel = if past_eq_attrs.contains(&predicate.right) { - self.get_join_selectivity_from_most_selective_attrs( - past_eq_attrs.find_attrs_for_eq_attribute_set(&predicate.right), - ) - .await? - } else { - 1.0 - }; - left_sel * right_sel - } - }; - - // Add predicate to past_eq_attrs and compute the selectivity of the connected component - // it creates. - past_eq_attrs.add_predicate(predicate.clone()); - let new_pred_sel = { - let attrs = past_eq_attrs.find_attrs_for_eq_attribute_set(&predicate.left); - self.get_join_selectivity_from_most_selective_attrs(attrs) - } - .await?; - - // Compute the adjustment factor. - Ok(new_pred_sel / children_pred_sel) - } - - /// Get the selectivity of the on conditions. - /// - /// Note that the selectivity of the on conditions does not depend on join type. - /// Join type is accounted for separately in get_join_selectivity_core(). - /// - /// We also check if each predicate is correlated with any of the previous predicates. - /// - /// More specifically, we are checking if the predicate can be expressed with other existing - /// predicates. E.g. if we have a predicate like A = B and B = C is equivalent to A = C. - // - /// However, we don't just throw away A = C, because we want to pick the most selective - /// predicates. For details on how we do this, see - /// `get_join_selectivity_from_redundant_predicates`. - async fn get_join_on_selectivity( - &self, - on_attr_ref_pairs: &[(AttrIndexPred, AttrIndexPred)], - attr_refs: &AttrRefs, - input_correlation: Option, - right_attr_ref_offset: usize, - ) -> CostModelResult { - let mut past_eq_attrs = input_correlation.unwrap_or_default(); - - // Multiply the selectivities of all individual conditions together - let mut selectivity = 1.0; - for on_attr_ref_pair in on_attr_ref_pairs { - let left_attr_ref = &attr_refs[on_attr_ref_pair.0.attr_index() as usize]; - let right_attr_ref = - &attr_refs[on_attr_ref_pair.1.attr_index() as usize + right_attr_ref_offset]; - - selectivity *= - if let (AttrRef::BaseTableAttrRef(left), AttrRef::BaseTableAttrRef(right)) = - (left_attr_ref, right_attr_ref) - { - let predicate = EqPredicate::new(left.clone(), right.clone()); - self.get_join_selectivity_adjustment_when_adding_to_multi_equality_graph( - &predicate, - &mut past_eq_attrs, - ) - .await? - } else { - self.get_join_selectivity_from_on_attr_ref_pair(left_attr_ref, right_attr_ref) - .await? - }; - } - - Ok(selectivity) - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use attr_ref::GroupAttrRefs; - - use crate::{ - common::{ - predicates::bin_op_pred::BinOpType, - properties::{attr_ref, Attribute}, - values::Value, - }, - stats::DEFAULT_EQ_SEL, - test_utils::tests::MemoGroupInfo, - test_utils::tests::{ - attr_index, bin_op, cnst, create_four_table_mock_cost_model, create_mock_cost_model, - create_three_table_mock_cost_model, create_two_table_mock_cost_model, - create_two_table_mock_cost_model_custom_row_cnts, empty_per_attr_stats, log_op, - per_attr_stats_with_dist_and_ndistinct, per_attr_stats_with_ndistinct, - TestOptCostModelMock, TEST_ATTR1_NAME, TEST_ATTR2_NAME, TEST_TABLE1_ID, TEST_TABLE2_ID, - TEST_TABLE3_ID, TEST_TABLE4_ID, - }, - }; - - use super::*; - - const JOIN_GROUP_ID: GroupId = GroupId(10); - - /// A wrapper around get_join_selectivity_from_expr_tree that extracts the - /// table row counts from the cost model. - async fn test_get_join_selectivity( - cost_model: &TestOptCostModelMock, - reverse_tables: bool, - join_typ: JoinType, - expr_tree: ArcPredicateNode, - attr_refs: &AttrRefs, - input_correlation: Option, - ) -> f64 { - let table1_row_cnt = cost_model.get_row_count(TEST_TABLE1_ID) as f64; - let table2_row_cnt = cost_model.get_row_count(TEST_TABLE2_ID) as f64; - - if !reverse_tables { - cost_model - .get_join_selectivity_from_expr_tree( - join_typ, - JOIN_GROUP_ID, - expr_tree, - attr_refs, - input_correlation, - table1_row_cnt, - table2_row_cnt, - ) - .await - .unwrap() - } else { - cost_model - .get_join_selectivity_from_expr_tree( - join_typ, - JOIN_GROUP_ID, - expr_tree, - attr_refs, - input_correlation, - table2_row_cnt, - table1_row_cnt, - ) - .await - .unwrap() - } - } - - #[tokio::test] - async fn test_inner_const() { - let cost_model = create_mock_cost_model( - vec![TEST_TABLE1_ID], - vec![HashMap::from([(0, empty_per_attr_stats())])], - vec![None], - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_join_selectivity_from_expr_tree( - JoinType::Inner, - JOIN_GROUP_ID, - cnst(Value::Bool(true)), - &vec![], - None, - f64::NAN, - f64::NAN - ) - .await - .unwrap(), - 1.0 - ); - assert_approx_eq::assert_approx_eq!( - cost_model - .get_join_selectivity_from_expr_tree( - JoinType::Inner, - JOIN_GROUP_ID, - cnst(Value::Bool(false)), - &vec![], - None, - f64::NAN, - f64::NAN - ) - .await - .unwrap(), - 0.0 - ); - } - - #[tokio::test] - async fn test_inner_oncond() { - let cost_model = create_two_table_mock_cost_model( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let expr_tree_rev = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree, - &attr_refs, - None, - ) - .await, - 0.2 - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev, - &attr_refs, - None, - ) - .await, - 0.2 - ); - } - - #[tokio::test] - async fn test_inner_and_of_onconds() { - let cost_model = create_two_table_mock_cost_model( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - let eq0and1 = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let eq1and0 = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - let expr_tree = log_op(LogOpType::And, vec![eq0and1.clone(), eq1and0.clone()]); - let expr_tree_rev = log_op(LogOpType::And, vec![eq1and0.clone(), eq0and1.clone()]); - - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree, - &attr_refs, - None, - ) - .await, - 0.2 - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev, - &attr_refs, - None - ) - .await, - 0.2 - ); - } - - #[tokio::test] - async fn test_inner_and_of_oncond_and_filter() { - let join_memo = HashMap::from([( - JOIN_GROUP_ID, - MemoGroupInfo::new( - vec![ - Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string()), - Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string()), - ] - .into(), - GroupAttrRefs::new( - vec![ - AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0), - ], - None, - ), - ), - )]); - let cost_model = create_two_table_mock_cost_model( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - Some(join_memo), - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - let eq0and1 = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let eq100 = bin_op(BinOpType::Eq, attr_index(1), cnst(Value::Int32(100))); - let expr_tree = log_op(LogOpType::And, vec![eq0and1.clone(), eq100.clone()]); - let expr_tree_rev = log_op(LogOpType::And, vec![eq100.clone(), eq0and1.clone()]); - - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree, - &attr_refs, - None - ) - .await, - 0.05 - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev, - &attr_refs, - None - ) - .await, - 0.05 - ); - } - - #[tokio::test] - async fn test_inner_and_of_filters() { - let join_memo = HashMap::from([( - JOIN_GROUP_ID, - MemoGroupInfo::new( - vec![ - Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string()), - Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string()), - ] - .into(), - GroupAttrRefs::new( - vec![ - AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0), - ], - None, - ), - ), - )]); - let cost_model = create_two_table_mock_cost_model( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - Some(join_memo), - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - let neq12 = bin_op(BinOpType::Neq, attr_index(0), cnst(Value::Int32(12))); - let eq100 = bin_op(BinOpType::Eq, attr_index(1), cnst(Value::Int32(100))); - let expr_tree = log_op(LogOpType::And, vec![neq12.clone(), eq100.clone()]); - let expr_tree_rev = log_op(LogOpType::And, vec![eq100.clone(), neq12.clone()]); - - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree, - &attr_refs, - None, - ) - .await, - 0.2 - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev, - &attr_refs, - None - ) - .await, - 0.2 - ); - } - - #[tokio::test] - async fn test_inner_colref_eq_colref_same_table_is_not_oncond() { - let cost_model = create_two_table_mock_cost_model( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), attr_index(0)); - - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree, - &attr_refs, - None - ) - .await, - DEFAULT_EQ_SEL - ); - } - - // We don't test joinsel or with oncond because if there is an oncond (on condition), the - // top-level operator must be an AND - - /// I made this helper function to avoid copying all eight lines over and over - async fn assert_outer_selectivities( - cost_model: &TestOptCostModelMock, - expr_tree: ArcPredicateNode, - expr_tree_rev: ArcPredicateNode, - attr_refs: &AttrRefs, - expected_table1_outer_sel: f64, - expected_table2_outer_sel: f64, - ) { - // all table 1 outer combinations - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - false, - JoinType::LeftOuter, - expr_tree.clone(), - attr_refs, - None - ) - .await, - expected_table1_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - false, - JoinType::LeftOuter, - expr_tree_rev.clone(), - attr_refs, - None - ) - .await, - expected_table1_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - true, - JoinType::RightOuter, - expr_tree.clone(), - attr_refs, - None - ) - .await, - expected_table1_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - true, - JoinType::RightOuter, - expr_tree_rev.clone(), - attr_refs, - None - ) - .await, - expected_table1_outer_sel - ); - // all table 2 outer combinations - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - true, - JoinType::LeftOuter, - expr_tree.clone(), - attr_refs, - None - ) - .await, - expected_table2_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - true, - JoinType::LeftOuter, - expr_tree_rev.clone(), - attr_refs, - None - ) - .await, - expected_table2_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - false, - JoinType::RightOuter, - expr_tree.clone(), - attr_refs, - None - ) - .await, - expected_table2_outer_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - cost_model, - false, - JoinType::RightOuter, - expr_tree_rev.clone(), - attr_refs, - None - ) - .await, - expected_table2_outer_sel - ); - } - - /// Unique oncond means an oncondition on columns which are unique in both tables - /// There's only one case if both columns are unique and have different row counts: the inner - /// will be < 1 / row count of one table and = 1 / row count of another - #[tokio::test] - async fn test_outer_unique_oncond() { - let cost_model = create_two_table_mock_cost_model_custom_row_cnts( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - 5, - 4, - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - // the left/right of the join refers to the tables, not the order of columns in the - // predicate - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let expr_tree_rev = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - - // sanity check the expected inner sel - let expected_inner_sel = 0.2; - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - // check the outer sels - assert_outer_selectivities(&cost_model, expr_tree, expr_tree_rev, &attr_refs, 0.25, 0.2) - .await; - } - - /// Non-unique oncond means the column is not unique in either table - /// Inner always >= row count means that the inner join result is >= 1 / the row count of both - /// tables - #[tokio::test] - async fn test_outer_nonunique_oncond_inner_always_geq_rowcnt() { - let cost_model = create_two_table_mock_cost_model_custom_row_cnts( - per_attr_stats_with_ndistinct(5), - per_attr_stats_with_ndistinct(4), - 10, - 8, - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - // the left/right of the join refers to the tables, not the order of columns in the - // predicate - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let expr_tree_rev = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - - // sanity check the expected inner sel - let expected_inner_sel = 0.2; - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - // check the outer sels - assert_outer_selectivities(&cost_model, expr_tree, expr_tree_rev, &attr_refs, 0.2, 0.2) - .await; - } - - /// Non-unique oncond means the column is not unique in either table - /// Inner sometimes < row count means that the inner join result < 1 / the row count of exactly - /// one table. Note that without a join filter, it's impossible to be less than the row - /// count of both tables - #[tokio::test] - async fn test_outer_nonunique_oncond_inner_sometimes_lt_rowcnt() { - let cost_model = create_two_table_mock_cost_model_custom_row_cnts( - per_attr_stats_with_ndistinct(10), - per_attr_stats_with_ndistinct(2), - 20, - 4, - None, - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - // the left/right of the join refers to the tables, not the order of columns in the - // predicate - let expr_tree = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let expr_tree_rev = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - - // sanity check the expected inner sel - let expected_inner_sel = 0.1; - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_rev.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - // check the outer sels - assert_outer_selectivities(&cost_model, expr_tree, expr_tree_rev, &attr_refs, 0.25, 0.1) - .await; - } - - /// Unique oncond means an oncondition on columns which are unique in both tables - /// Filter means we're adding a join filter - /// There's only one case if both columns are unique and there's a filter: - /// the inner will be < 1 / row count of both tables - #[tokio::test] - async fn test_outer_unique_oncond_filter() { - let join_memo = HashMap::from([( - JOIN_GROUP_ID, - MemoGroupInfo::new( - vec![ - Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string()), - Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string()), - ] - .into(), - GroupAttrRefs::new( - vec![ - AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0), - ], - None, - ), - ), - )]); - let cost_model = create_two_table_mock_cost_model_custom_row_cnts( - per_attr_stats_with_dist_and_ndistinct(vec![(Value::Int32(128), 0.4)], 50), - per_attr_stats_with_ndistinct(4), - 50, - 4, - Some(join_memo), - ); - - let attr_refs = vec![ - AttrRef::base_table_attr_ref(TEST_TABLE1_ID, 0), - AttrRef::base_table_attr_ref(TEST_TABLE2_ID, 0), - ]; - // the left/right of the join refers to the tables, not the order of columns in the - // predicate - let eq0and1 = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let eq1and0 = bin_op(BinOpType::Eq, attr_index(1), attr_index(0)); - let filter = bin_op(BinOpType::Leq, attr_index(0), cnst(Value::Int32(128))); - let expr_tree = log_op(LogOpType::And, vec![eq0and1, filter.clone()]); - // inner rev means its the inner expr (the eq op) whose children are being reversed, as - // opposed to the and op - let expr_tree_inner_rev = log_op(LogOpType::And, vec![eq1and0, filter.clone()]); - - // sanity check the expected inner sel - let expected_inner_sel = 0.008; - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - assert_approx_eq::assert_approx_eq!( - test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree_inner_rev.clone(), - &attr_refs, - None - ) - .await, - expected_inner_sel - ); - // check the outer sels - assert_outer_selectivities( - &cost_model, - expr_tree, - expr_tree_inner_rev, - &attr_refs, - 0.25, - 0.02, - ) - .await; - } - - /// Test all possible permutations of three-table joins. - /// A three-table join consists of at least two joins. `join1_on_cond` is the condition of the - /// first join. There can only be one condition because only two tables are involved at - /// the time of the first join. - #[tokio::test] - #[test_case::test_case(&[(0, 1)])] - #[test_case::test_case(&[(0, 2)])] - #[test_case::test_case(&[(1, 2)])] - #[test_case::test_case(&[(0, 1), (0, 2)])] - #[test_case::test_case(&[(0, 1), (1, 2)])] - #[test_case::test_case(&[(0, 2), (1, 2)])] - #[test_case::test_case(&[(0, 1), (0, 2), (1, 2)])] - async fn test_three_table_join_for_initial_join_on_conds( - initial_join_on_conds: &[(usize, usize)], - ) { - assert!( - !initial_join_on_conds.is_empty(), - "initial_join_on_conds should be non-empty" - ); - assert_eq!( - initial_join_on_conds.len(), - initial_join_on_conds.iter().collect::>().len(), - "initial_join_on_conds shouldn't contain duplicates" - ); - let cost_model = create_three_table_mock_cost_model( - per_attr_stats_with_ndistinct(2), - per_attr_stats_with_ndistinct(3), - per_attr_stats_with_ndistinct(4), - ); - - let base_attr_refs = vec![ - BaseTableAttrRef { - table_id: TEST_TABLE1_ID, - attr_idx: 0, - }, - BaseTableAttrRef { - table_id: TEST_TABLE2_ID, - attr_idx: 0, - }, - BaseTableAttrRef { - table_id: TEST_TABLE3_ID, - attr_idx: 0, - }, - ]; - let attr_refs = base_attr_refs - .clone() - .into_iter() - .map(AttrRef::BaseTableAttrRef) - .collect(); - - let mut eq_columns = SemanticCorrelation::new(); - for initial_join_on_cond in initial_join_on_conds { - eq_columns.add_predicate(EqPredicate::new( - base_attr_refs[initial_join_on_cond.0].clone(), - base_attr_refs[initial_join_on_cond.1].clone(), - )); - } - let initial_selectivity = { - if initial_join_on_conds.len() == 1 { - let initial_join_on_cond = initial_join_on_conds.first().unwrap(); - if initial_join_on_cond == &(0, 1) { - 1.0 / 3.0 - } else if initial_join_on_cond == &(0, 2) || initial_join_on_cond == &(1, 2) { - 1.0 / 4.0 - } else { - panic!(); - } - } else { - 1.0 / 12.0 - } - }; - - let input_correlation = Some(eq_columns); - - // Try all join conditions of the final join which would lead to all three tables being - // joined. - let eq0and1 = bin_op(BinOpType::Eq, attr_index(0), attr_index(1)); - let eq0and2 = bin_op(BinOpType::Eq, attr_index(0), attr_index(2)); - let eq1and2 = bin_op(BinOpType::Eq, attr_index(1), attr_index(2)); - let and_01_02 = log_op(LogOpType::And, vec![eq0and1.clone(), eq0and2.clone()]); - let and_01_12 = log_op(LogOpType::And, vec![eq0and1.clone(), eq1and2.clone()]); - let and_02_12 = log_op(LogOpType::And, vec![eq0and2.clone(), eq1and2.clone()]); - let and_01_02_12 = log_op( - LogOpType::And, - vec![eq0and1.clone(), eq0and2.clone(), eq1and2.clone()], - ); - let mut join2_expr_trees = vec![and_01_02, and_01_12, and_02_12, and_01_02_12]; - if initial_join_on_conds.len() == 1 { - let initial_join_on_cond = initial_join_on_conds.first().unwrap(); - if initial_join_on_cond == &(0, 1) { - join2_expr_trees.push(eq0and2); - join2_expr_trees.push(eq1and2); - } else if initial_join_on_cond == &(0, 2) { - join2_expr_trees.push(eq0and1); - join2_expr_trees.push(eq1and2); - } else if initial_join_on_cond == &(1, 2) { - join2_expr_trees.push(eq0and1); - join2_expr_trees.push(eq0and2); - } else { - panic!(); - } - } - for expr_tree in join2_expr_trees { - let overall_selectivity = initial_selectivity - * test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - expr_tree.clone(), - &attr_refs, - input_correlation.clone(), - ) - .await; - assert_approx_eq::assert_approx_eq!(overall_selectivity, 1.0 / 12.0); - } - } - - #[tokio::test] - async fn test_join_which_connects_two_components_together() { - let cost_model = create_four_table_mock_cost_model( - per_attr_stats_with_ndistinct(2), - per_attr_stats_with_ndistinct(3), - per_attr_stats_with_ndistinct(4), - per_attr_stats_with_ndistinct(5), - ); - let base_attr_refs = vec![ - BaseTableAttrRef { - table_id: TEST_TABLE1_ID, - attr_idx: 0, - }, - BaseTableAttrRef { - table_id: TEST_TABLE2_ID, - attr_idx: 0, - }, - BaseTableAttrRef { - table_id: TEST_TABLE3_ID, - attr_idx: 0, - }, - BaseTableAttrRef { - table_id: TEST_TABLE4_ID, - attr_idx: 0, - }, - ]; - let attr_refs = base_attr_refs - .clone() - .into_iter() - .map(AttrRef::BaseTableAttrRef) - .collect(); - - let mut eq_columns = SemanticCorrelation::new(); - eq_columns.add_predicate(EqPredicate::new( - base_attr_refs[0].clone(), - base_attr_refs[1].clone(), - )); - eq_columns.add_predicate(EqPredicate::new( - base_attr_refs[2].clone(), - base_attr_refs[3].clone(), - )); - let initial_selectivity = 1.0 / (3.0 * 5.0); - let input_correlation = Some(eq_columns); - - let eq1and2 = bin_op(BinOpType::Eq, attr_index(1), attr_index(2)); - let overall_selectivity = initial_selectivity - * test_get_join_selectivity( - &cost_model, - false, - JoinType::Inner, - eq1and2.clone(), - &attr_refs, - input_correlation, - ) - .await; - assert_approx_eq::assert_approx_eq!(overall_selectivity, 1.0 / (3.0 * 4.0 * 5.0)); - } -} diff --git a/optd-cost-model/src/cost/join/hash_join.rs b/optd-cost-model/src/cost/join/hash_join.rs deleted file mode 100644 index f92f247..0000000 --- a/optd-cost-model/src/cost/join/hash_join.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - common::{nodes::JoinType, predicates::list_pred::ListPred, types::GroupId}, - cost_model::CostModelImpl, - storage::CostModelStorageManager, - CostModelResult, EstimatedStatistic, -}; - -use super::get_input_correlation; - -impl CostModelImpl { - #[allow(clippy::too_many_arguments)] - pub async fn get_hash_join_row_cnt( - &self, - join_typ: JoinType, - group_id: GroupId, - left_row_cnt: EstimatedStatistic, - right_row_cnt: EstimatedStatistic, - left_group_id: GroupId, - right_group_id: GroupId, - left_keys: ListPred, - right_keys: ListPred, - ) -> CostModelResult { - let selectivity = { - let output_attr_refs = self.memo.get_attribute_refs(group_id); - let left_attr_refs = self.memo.get_attribute_refs(left_group_id); - let right_attr_refs = self.memo.get_attribute_refs(right_group_id); - let left_attr_cnt = left_attr_refs.attr_refs().len(); - // there may be more than one expression tree in a group. - // see comment in PredicateType::PhysicalFilter(_) for more information - let input_correlation = get_input_correlation(left_attr_refs, right_attr_refs); - self.get_join_selectivity_from_keys( - join_typ, - group_id, - left_keys, - right_keys, - output_attr_refs.attr_refs(), - input_correlation, - left_row_cnt.0, - right_row_cnt.0, - left_attr_cnt, - ) - .await? - }; - Ok(EstimatedStatistic( - (left_row_cnt.0 * right_row_cnt.0 * selectivity).max(1.0), - )) - } -} diff --git a/optd-cost-model/src/cost/join/mod.rs b/optd-cost-model/src/cost/join/mod.rs deleted file mode 100644 index 71b991b..0000000 --- a/optd-cost-model/src/cost/join/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::common::{ - nodes::{ArcPredicateNode, PredicateType, ReprPredicateNode}, - predicates::{attr_index_pred::AttrIndexPred, bin_op_pred::BinOpType}, - properties::attr_ref::{ - AttrRef, AttrRefs, BaseTableAttrRef, GroupAttrRefs, SemanticCorrelation, - }, -}; - -pub mod core; -pub mod hash_join; -pub mod nested_loop_join; - -pub(crate) fn get_input_correlation( - left_prop: GroupAttrRefs, - right_prop: GroupAttrRefs, -) -> Option { - SemanticCorrelation::merge( - left_prop.output_correlation().cloned(), - right_prop.output_correlation().cloned(), - ) -} - -/// Check if an expr_tree is a join condition, returning the join on attr ref pair if it is. -/// The reason the check and the info are in the same function is because their code is almost -/// identical. It only picks out equality conditions between two attribute refs on different -/// tables -pub(crate) fn get_on_attr_ref_pair( - expr_tree: ArcPredicateNode, - attr_refs: &AttrRefs, -) -> Option<(AttrIndexPred, AttrIndexPred)> { - // 1. Check that it's equality - if expr_tree.typ == PredicateType::BinOp(BinOpType::Eq) { - let left_child = expr_tree.child(0); - let right_child = expr_tree.child(1); - // 2. Check that both sides are attribute refs - if left_child.typ == PredicateType::AttrIndex && right_child.typ == PredicateType::AttrIndex - { - // 3. Check that both sides don't belong to the same table (if we don't know, that - // means they don't belong) - let left_attr_ref_expr = AttrIndexPred::from_pred_node(left_child) - .expect("we already checked that the type is AttrRef"); - let right_attr_ref_expr = AttrIndexPred::from_pred_node(right_child) - .expect("we already checked that the type is AttrRef"); - let left_attr_ref = &attr_refs[left_attr_ref_expr.attr_index() as usize]; - let right_attr_ref = &attr_refs[right_attr_ref_expr.attr_index() as usize]; - let is_same_table = if let ( - AttrRef::BaseTableAttrRef(BaseTableAttrRef { - table_id: left_table_id, - .. - }), - AttrRef::BaseTableAttrRef(BaseTableAttrRef { - table_id: right_table_id, - .. - }), - ) = (left_attr_ref, right_attr_ref) - { - left_table_id == right_table_id - } else { - false - }; - if !is_same_table { - Some((left_attr_ref_expr, right_attr_ref_expr)) - } else { - None - } - } else { - None - } - } else { - None - } -} diff --git a/optd-cost-model/src/cost/join/nested_loop_join.rs b/optd-cost-model/src/cost/join/nested_loop_join.rs deleted file mode 100644 index ff6a2b1..0000000 --- a/optd-cost-model/src/cost/join/nested_loop_join.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{ - common::{ - nodes::{ArcPredicateNode, JoinType}, - types::GroupId, - }, - cost_model::CostModelImpl, - storage::CostModelStorageManager, - CostModelResult, EstimatedStatistic, -}; - -use super::get_input_correlation; - -impl CostModelImpl { - #[allow(clippy::too_many_arguments)] - pub async fn get_nlj_row_cnt( - &self, - join_typ: JoinType, - group_id: GroupId, - left_row_cnt: EstimatedStatistic, - right_row_cnt: EstimatedStatistic, - left_group_id: GroupId, - right_group_id: GroupId, - join_cond: ArcPredicateNode, - ) -> CostModelResult { - let selectivity = { - let output_attr_refs = self.memo.get_attribute_refs(group_id); - let left_attr_refs = self.memo.get_attribute_refs(left_group_id); - let right_attr_refs = self.memo.get_attribute_refs(right_group_id); - let input_correlation = get_input_correlation(left_attr_refs, right_attr_refs); - - self.get_join_selectivity_from_expr_tree( - join_typ, - group_id, - join_cond, - output_attr_refs.attr_refs(), - input_correlation, - left_row_cnt.0, - right_row_cnt.0, - ) - .await? - }; - Ok(EstimatedStatistic( - (left_row_cnt.0 * right_row_cnt.0 * selectivity).max(1.0), - )) - } -} diff --git a/optd-cost-model/src/cost/limit.rs b/optd-cost-model/src/cost/limit.rs deleted file mode 100644 index c63c0e0..0000000 --- a/optd-cost-model/src/cost/limit.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{ - common::{ - nodes::{ArcPredicateNode, ReprPredicateNode}, - predicates::constant_pred::ConstantPred, - }, - cost_model::CostModelImpl, - storage::CostModelStorageManager, - CostModelResult, EstimatedStatistic, -}; - -impl CostModelImpl { - pub(crate) fn get_limit_row_cnt( - &self, - child_row_cnt: EstimatedStatistic, - fetch_expr: ArcPredicateNode, - ) -> CostModelResult { - let fetch = ConstantPred::from_pred_node(fetch_expr) - .unwrap() - .value() - .as_u64(); - // u64::MAX represents None - if fetch == u64::MAX { - Ok(child_row_cnt) - } else { - Ok(EstimatedStatistic(child_row_cnt.0.min(fetch as f64))) - } - } -} diff --git a/optd-cost-model/src/cost/mod.rs b/optd-cost-model/src/cost/mod.rs deleted file mode 100644 index b55d449..0000000 --- a/optd-cost-model/src/cost/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod agg; -pub mod filter; -pub mod join; -pub mod limit; diff --git a/optd-cost-model/src/cost_model.rs b/optd-cost-model/src/cost_model.rs deleted file mode 100644 index 38957f9..0000000 --- a/optd-cost-model/src/cost_model.rs +++ /dev/null @@ -1,268 +0,0 @@ -#![allow(dead_code, unused_imports, unused_variables)] - -use std::sync::Arc; - -use optd_persistent::{ - cost_model::interface::{CatalogSource, Stat, StatType}, - CostModelStorageLayer, -}; - -use crate::{ - common::{ - nodes::{ArcPredicateNode, PhysicalNodeType, ReprPredicateNode}, - predicates::list_pred::ListPred, - types::{AttrId, EpochId, ExprId, TableId}, - }, - memo_ext::MemoExt, - stats::AttributeCombValueStats, - storage::{self, CostModelStorageManager}, - ComputeCostContext, Cost, CostModel, CostModelResult, EstimatedStatistic, StatValue, -}; - -/// TODO: documentation -pub struct CostModelImpl { - pub storage_manager: S, - pub default_catalog_source: CatalogSource, - pub memo: Arc, -} - -impl CostModelImpl { - /// TODO: documentation - pub fn new( - storage_manager: S, - default_catalog_source: CatalogSource, - memo: Arc, - ) -> Self { - Self { - storage_manager, - default_catalog_source, - memo, - } - } -} - -#[async_trait::async_trait] -impl CostModel for CostModelImpl { - /// TODO: should we add epoch_id? - async fn compute_operation_cost( - &self, - node: PhysicalNodeType, - predicates: &[ArcPredicateNode], - children_costs: &[Cost], - children_stats: &[EstimatedStatistic], - context: ComputeCostContext, - ) -> CostModelResult { - let res = self.storage_manager.get_cost(context.expr_id).await; - if let Ok((Some(cost), _)) = res { - return Ok(cost); - }; - let mut output_statistic = None; - if let Ok((_, Some(statistic))) = res { - output_statistic = Some(statistic); - }; - let output_cost = match node { - PhysicalNodeType::PhysicalScan => { - let output_statistic_data = output_statistic.unwrap_or( - self.derive_statistics( - node, - predicates, - children_stats, - context.clone(), - false, - ) - .await?, - ); - output_statistic = Some(output_statistic_data.clone()); - Cost { - compute_cost: 0.0, - io_cost: output_statistic_data.0, - } - } - PhysicalNodeType::PhysicalEmptyRelation => Cost { - compute_cost: 0.1, - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalLimit => Cost { - compute_cost: children_costs[0].compute_cost, - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalFilter => Cost { - // TODO: now this equation is specific to optd, and try to make this equation more general - compute_cost: children_costs[1].compute_cost * children_stats[0].0, - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalNestedLoopJoin(join_typ) => { - let child_compute_cost = children_costs[2].compute_cost; - Cost { - compute_cost: children_stats[0].0 * children_stats[1].0 * child_compute_cost - + children_stats[0].0, - io_cost: 0.0, - } - } - // TODO: we should document that the first child is the left table, which is used to build - // the hash table. - PhysicalNodeType::PhysicalHashJoin(join_typ) => Cost { - compute_cost: children_stats[0].0 * 2.0 + children_stats[1].0, - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalAgg => Cost { - compute_cost: children_stats[0].0 - * (children_costs[1].compute_cost + children_costs[2].compute_cost), - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalProjection => Cost { - compute_cost: children_stats[0].0 * children_costs[1].compute_cost, - io_cost: 0.0, - }, - PhysicalNodeType::PhysicalSort => Cost { - compute_cost: children_stats[0].0 * children_stats[0].0.ln_1p().max(1.0), - io_cost: 0.0, - }, - }; - let res = self - .storage_manager - .store_cost( - context.expr_id, - Some(output_cost.clone()), - output_statistic, - None, - ) - .await; - if res.is_err() { - eprintln!("Failed to store output cost"); - } - Ok(output_cost) - } - - /// TODO: should we add epoch_id? - async fn derive_statistics( - &self, - node: PhysicalNodeType, - predicates: &[ArcPredicateNode], - children_statistics: &[EstimatedStatistic], - context: ComputeCostContext, - store_output_statistic: bool, - ) -> CostModelResult { - let res = self.storage_manager.get_cost(context.expr_id).await; - if let Ok((_, Some(statistic))) = res { - return Ok(statistic); - } - let output_statistic = match node { - PhysicalNodeType::PhysicalScan => { - let table_id = TableId(predicates[0].data.as_ref().unwrap().as_u64()); - let row_cnt = self - .storage_manager - .get_table_row_count(table_id) - .await? - .unwrap_or(1) as f64; - Ok(EstimatedStatistic(row_cnt)) - } - PhysicalNodeType::PhysicalEmptyRelation => Ok(EstimatedStatistic(0.01)), - PhysicalNodeType::PhysicalLimit => { - self.get_limit_row_cnt(children_statistics[0].clone(), predicates[1].clone()) - } - PhysicalNodeType::PhysicalFilter => { - self.get_filter_row_cnt( - children_statistics[0].clone(), - context.group_id, - predicates[0].clone(), - ) - .await - } - PhysicalNodeType::PhysicalNestedLoopJoin(join_typ) => { - self.get_nlj_row_cnt( - join_typ, - context.group_id, - children_statistics[0].clone(), - children_statistics[1].clone(), - context.children_group_ids[0], - context.children_group_ids[1], - predicates[0].clone(), - ) - .await - } - PhysicalNodeType::PhysicalHashJoin(join_typ) => { - self.get_hash_join_row_cnt( - join_typ, - context.group_id, - children_statistics[0].clone(), - children_statistics[1].clone(), - context.children_group_ids[0], - context.children_group_ids[1], - ListPred::from_pred_node(predicates[0].clone()).unwrap(), - ListPred::from_pred_node(predicates[1].clone()).unwrap(), - ) - .await - } - PhysicalNodeType::PhysicalAgg => { - self.get_agg_row_cnt(context.group_id, predicates[1].clone()) - .await - } - PhysicalNodeType::PhysicalSort | PhysicalNodeType::PhysicalProjection => { - Ok(children_statistics[0].clone()) - } - }?; - if store_output_statistic { - let res = self - .storage_manager - .store_cost(context.expr_id, None, Some(output_statistic.clone()), None) - .await; - if res.is_err() { - eprintln!("Failed to store output statistic"); - } - }; - Ok(output_statistic) - } - - async fn update_statistics( - &self, - stats: Vec, - source: String, - data: String, - ) -> CostModelResult<()> { - todo!() - } - - async fn get_table_statistic_for_analysis( - &self, - table_id: TableId, - stat_type: StatType, - epoch_id: Option, - ) -> CostModelResult> { - todo!() - } - - async fn get_attribute_statistic_for_analysis( - &self, - attr_ids: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> CostModelResult> { - todo!() - } - - async fn get_cost_for_analysis( - &self, - expr_id: ExprId, - epoch_id: Option, - ) -> CostModelResult> { - todo!() - } -} - -impl CostModelImpl { - /// TODO: documentation - /// TODO: if we have memory cache, - /// we should add the reference. (&AttributeCombValueStats) - pub(crate) async fn get_attribute_comb_stats( - &self, - table_id: TableId, - attr_comb: &[u64], - ) -> CostModelResult> { - self.storage_manager - .get_attributes_comb_statistics(table_id, attr_comb) - .await - } -} - -// TODO: Add tests for `derive_statistic`` and `compute_operation_cost`. diff --git a/optd-cost-model/src/lib.rs b/optd-cost-model/src/lib.rs deleted file mode 100644 index 4b65038..0000000 --- a/optd-cost-model/src/lib.rs +++ /dev/null @@ -1,191 +0,0 @@ -use common::{ - nodes::{ArcPredicateNode, PhysicalNodeType}, - types::{AttrId, EpochId, ExprId, GroupId, TableId}, -}; -use optd_persistent::{ - cost_model::interface::{Stat, StatType}, - BackendError, -}; - -pub mod common; -pub mod cost; -pub mod cost_model; -pub mod memo_ext; -pub mod stats; -pub mod storage; -pub mod test_utils; -pub mod utils; - -pub enum StatValue { - Int(i64), - Float(f64), - String(String), -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] -pub struct ComputeCostContext { - pub group_id: GroupId, - pub expr_id: ExprId, - pub children_group_ids: Vec, -} - -#[derive(Default, Clone, Debug, PartialOrd, PartialEq)] -pub struct Cost { - pub compute_cost: f64, - pub io_cost: f64, -} - -impl From for optd_persistent::cost_model::interface::Cost { - fn from(c: Cost) -> optd_persistent::cost_model::interface::Cost { - Self { - compute_cost: c.compute_cost, - io_cost: c.io_cost, - } - } -} - -impl From for Cost { - fn from(c: optd_persistent::cost_model::interface::Cost) -> Cost { - Self { - compute_cost: c.compute_cost, - io_cost: c.io_cost, - } - } -} - -/// Estimated statistic calculated by the cost model. -/// It is the estimated output row count of the targeted expression. -#[derive(PartialEq, PartialOrd, Clone, Debug)] -pub struct EstimatedStatistic(pub f64); - -impl From for f32 { - fn from(e: EstimatedStatistic) -> f32 { - e.0 as f32 - } -} - -impl From for f64 { - fn from(e: EstimatedStatistic) -> f64 { - e.0 - } -} - -impl From for EstimatedStatistic { - fn from(f: f32) -> EstimatedStatistic { - Self(f as f64) - } -} - -pub type CostModelResult = Result; - -#[derive(Debug)] -pub enum SemanticError { - // TODO: Add more error types - UnknownStatisticType, - VersionedStatisticNotFound, - AttributeNotFound(TableId, u64), // (table_id, attribute_base_index) - // FIXME: not sure if this should be put here - InvalidPredicate(String), -} - -#[derive(Debug)] -pub enum CostModelError { - ORMError(BackendError), - SemanticError(SemanticError), - SerdeError(serde_json::Error), -} - -impl From for CostModelError { - fn from(err: BackendError) -> Self { - CostModelError::ORMError(err) - } -} - -impl From for CostModelError { - fn from(err: SemanticError) -> Self { - CostModelError::SemanticError(err) - } -} - -impl From for CostModelError { - fn from(err: serde_json::Error) -> Self { - CostModelError::SerdeError(err) - } -} - -#[async_trait::async_trait] -pub trait CostModel: 'static + Send + Sync { - /// TODO: documentation - async fn compute_operation_cost( - &self, - node: PhysicalNodeType, - predicates: &[ArcPredicateNode], - children_costs: &[Cost], - children_stats: &[EstimatedStatistic], - context: ComputeCostContext, - ) -> CostModelResult; - - /// TODO: documentation - /// It is for cardinality estimation. The output should be the estimated - /// statistic calculated by the cost model. - /// If this method is called by `compute_operation_cost`, please set - /// `store_output_statistic` to `false`; if it is called by the optimizer, - /// please set `store_output_statistic` to `true`. Since we can store the - /// estimated statistic and cost by calling the ORM method once. - /// - /// TODO: I am not sure whether to introduce `store_output_statistic`, since - /// it add complexity to the interface, considering currently only Scan needs - /// the output row count to calculate the costs. So updating the database twice - /// seems cheap. But in the future, maybe more cost computations rely on the output - /// row count. (Of course, it should be removed if we separate the cost and - /// estimated_statistic into 2 tables.) - /// - /// TODO: Consider make it a helper function, so we can store Cost in the - /// ORM more easily. - /// - /// TODO: I would suggest to rename this method to `derive_row_count`, since - /// statistic is easily to be confused with the real statistic. - /// Also we need to update other places to use estimated statistic to row count, - /// either in this crate or in optd-persistent. - async fn derive_statistics( - &self, - node: PhysicalNodeType, - predicates: &[ArcPredicateNode], - children_stats: &[EstimatedStatistic], - context: ComputeCostContext, - store_output_statistic: bool, - ) -> CostModelResult; - - /// TODO: documentation - /// It is for **REAL** statistic updates, not for estimated statistics. - /// TODO: Change data from String to other types. - async fn update_statistics( - &self, - stats: Vec, - source: String, - data: String, - ) -> CostModelResult<()>; - - /// TODO: documentation - async fn get_table_statistic_for_analysis( - &self, - table_id: TableId, - stat_type: StatType, - epoch_id: Option, - ) -> CostModelResult>; - - /// TODO: documentation - async fn get_attribute_statistic_for_analysis( - &self, - attr_ids: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> CostModelResult>; - - /// TODO: documentation - async fn get_cost_for_analysis( - &self, - expr_id: ExprId, - epoch_id: Option, - ) -> CostModelResult>; -} diff --git a/optd-cost-model/src/memo_ext.rs b/optd-cost-model/src/memo_ext.rs deleted file mode 100644 index 78d4225..0000000 --- a/optd-cost-model/src/memo_ext.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::common::{ - properties::{ - attr_ref::{AttrRef, GroupAttrRefs}, - schema::Schema, - Attribute, - }, - types::GroupId, -}; - -/// [`MemoExt`] is a trait that provides methods to access the schema, column reference, and attribute -/// information of a group in the memo. The information are used by the cost model to compute the cost of -/// an expression. -/// -/// [`MemoExt`] should be implemented by the optimizer core to provide the necessary information to the cost -/// model. All information required here is already present in the memo, so the optimizer core should be able -/// to implement this trait without additional work. -pub trait MemoExt: Send + Sync + 'static { - /// Get the schema of a group in the memo. - fn get_schema(&self, group_id: GroupId) -> Schema; - /// Get the attribute info of a given attribute in a group in the memo. - fn get_attribute_info(&self, group_id: GroupId, attr_ref_idx: u64) -> Attribute; - /// Get the attribute reference of a group in the memo. - fn get_attribute_refs(&self, group_id: GroupId) -> GroupAttrRefs; - /// Get the attribute reference of a given attribute in a group in the memo. - fn get_attribute_ref(&self, group_id: GroupId, attr_ref_idx: u64) -> AttrRef; - - // TODO: Figure out what other information is needed to compute the cost... -} diff --git a/optd-cost-model/src/stats/arith_encoder.rs b/optd-cost-model/src/stats/arith_encoder.rs deleted file mode 100644 index 730fcdb..0000000 --- a/optd-cost-model/src/stats/arith_encoder.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! This module provides an encoder that converts alpha-numeric strings -//! into f64 values, designed to maintain the natural ordering of strings. -//! -//! While the encoding is theoretically lossless, in practice, it may suffer -//! from precision loss due to floating-point errors. -//! -//! Non-alpha-numeric characters are relegated to the end of the encoded value, -//! rendering them indistinguishable from one another in this context. - -use std::{collections::HashMap, sync::LazyLock}; - -// The alphanumerical ordering. -const ALPHANUMERIC_ORDER: [char; 95] = [ - ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', - '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', '0', '1', '2', '3', '4', - '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -]; - -const PMF: f64 = 1.0 / (ALPHANUMERIC_ORDER.len() as f64); - -static CDF: LazyLock> = LazyLock::new(|| { - let length = ALPHANUMERIC_ORDER.len() + 1; // To account for non-alpha-numeric characters. - let mut cdf = HashMap::with_capacity(length); - for (index, &char) in ALPHANUMERIC_ORDER.iter().enumerate() { - cdf.insert(char, (index as f64) / (length as f64)); - } - cdf -}); - -pub fn encode(string: &str) -> f64 { - let mut left = 0.0; - // 10_000.0 is fairly arbitrary. don't make it f64::MAX though because it causes overflow in - // other places of the code - let mut right = 10_000.0; - - for char in string.chars() { - let cdf = CDF.get(&char).unwrap_or(&1.0); - let distance = right - left; - right = left + distance * (cdf + PMF); - left += distance * cdf; - } - - left -} - -// Start of unit testing section. -#[cfg(test)] -mod tests { - use super::encode; - - #[test] - fn encode_tests() { - assert!(encode("") < encode("abc")); - assert!(encode("abc") < encode("bcd")); - - assert!(encode("a") < encode("aaa")); - assert!(encode("!a") < encode("a!")); - assert!(encode("Alexis") < encode("Schlomer")); - - assert!(encode("Gungnir Rules!") < encode("Schlomer")); - assert!(encode("Gungnir Rules!") < encode("Schlomer")); - - assert_eq!(encode(" "), encode(" ")); - assert_eq!(encode("Same"), encode("Same")); - assert!(encode("Nicolas ") < encode("Nicolas💰💼")); - } -} diff --git a/optd-cost-model/src/stats/mod.rs b/optd-cost-model/src/stats/mod.rs deleted file mode 100644 index 7ec2510..0000000 --- a/optd-cost-model/src/stats/mod.rs +++ /dev/null @@ -1,211 +0,0 @@ -#![allow(unused)] - -mod arith_encoder; -pub mod utilities; - -use crate::common::values::Value; -use serde::{Deserialize, Serialize}; -use utilities::counter::Counter; -use utilities::{ - simple_map::{self, SimpleMap}, - tdigest::TDigest, -}; - -// Default n-distinct estimate for derived columns or columns lacking statistics -pub const DEFAULT_NUM_DISTINCT: u64 = 200; -// A placeholder for unimplemented!() for codepaths which are accessed by plannertest -pub const UNIMPLEMENTED_SEL: f64 = 0.01; -// Default statistics. All are from selfuncs.h in Postgres unless specified otherwise -// Default selectivity estimate for equalities such as "A = b" -pub const DEFAULT_EQ_SEL: f64 = 0.005; -// Default selectivity estimate for inequalities such as "A < b" -pub const DEFAULT_INEQ_SEL: f64 = 0.3333333333333333; -// Used for estimating pattern selectivity character-by-character. These numbers -// are not used on their own. Depending on the characters in the pattern, the -// selectivity is multiplied by these factors. -// -// See `FULL_WILDCARD_SEL` and `FIXED_CHAR_SEL` in Postgres. -pub const FULL_WILDCARD_SEL_FACTOR: f64 = 5.0; -pub const FIXED_CHAR_SEL_FACTOR: f64 = 0.2; - -pub type AttributeCombValue = Vec>; - -// TODO: remove the clone, see the comment in the [`AttributeCombValueStats`] -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(tag = "type")] -pub enum MostCommonValues { - Counter(Counter), - SimpleFrequency(SimpleMap), - // Add more types here... -} - -impl MostCommonValues { - // it is true that we could just expose freq_over_pred() and use that for freq() and - // total_freq() however, freq() and total_freq() each have potential optimizations (freq() - // is O(1) instead of O(n) and total_freq() can be cached) - // additionally, it makes sense to return an Option for freq() instead of just 0 if value - // doesn't exist thus, I expose three different functions - pub fn freq(&self, value: &AttributeCombValue) -> Option { - match self { - MostCommonValues::Counter(counter) => counter.frequencies().get(value).copied(), - MostCommonValues::SimpleFrequency(simple_map) => simple_map.m.get(value).copied(), - } - } - - pub fn total_freq(&self) -> f64 { - match self { - MostCommonValues::Counter(counter) => counter.frequencies().values().sum(), - MostCommonValues::SimpleFrequency(simple_map) => simple_map.m.values().sum(), - } - } - - pub fn freq_over_pred(&self, pred: Box bool>) -> f64 { - match self { - MostCommonValues::Counter(counter) => counter - .frequencies() - .iter() - .filter(|(val, _)| pred(val)) - .map(|(_, freq)| freq) - .sum(), - MostCommonValues::SimpleFrequency(simple_map) => simple_map - .m - .iter() - .filter(|(val, _)| pred(val)) - .map(|(_, freq)| freq) - .sum(), - } - } - - // returns the # of entries (i.e. value + freq) in the most common values structure - pub fn cnt(&self) -> usize { - match self { - MostCommonValues::Counter(counter) => counter.frequencies().len(), - MostCommonValues::SimpleFrequency(simple_map) => simple_map.m.len(), - } - } - - pub fn empty() -> Self { - MostCommonValues::SimpleFrequency(SimpleMap::new(vec![])) - } -} - -// TODO: remove the clone, see the comment in the [`AttributeCombValueStats`] -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(tag = "type")] -pub enum Distribution { - TDigest(TDigest), - SimpleDistribution(SimpleMap), - // Add more types here... -} - -impl Distribution { - pub fn cdf(&self, value: &Value) -> f64 { - match self { - Distribution::TDigest(tdigest) => { - let nb_rows = tdigest.norm_weight; - if nb_rows == 0 { - tdigest.cdf(value) - } else { - tdigest.centroids.len() as f64 * tdigest.cdf(value) / nb_rows as f64 - } - } - Distribution::SimpleDistribution(simple_distribution) => { - *simple_distribution.m.get(value).unwrap_or(&0.0) - } - } - } - - pub fn empty() -> Self { - Distribution::SimpleDistribution(SimpleMap::new(vec![])) - } -} - -// TODO: Remove the clone. Now I have to add this because -// persistent.rs doesn't have a memory cache, so we have to -// return AttributeCombValueStats rather than &AttributeCombValueStats. -// But this poses a problem for mock.rs when testing, since mock storage -// only has memory hash map, so we need to return a clone of AttributeCombValueStats. -// Later, if memory cache is added, we should change this to return a reference. -// **and** remove the clone. -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct AttributeCombValueStats { - pub mcvs: MostCommonValues, // Does NOT contain full nulls. - pub distr: Option, // Does NOT contain mcvs; optional. - pub ndistinct: u64, // Does NOT contain full nulls. - pub null_frac: f64, // % of full nulls. -} - -impl AttributeCombValueStats { - pub fn new( - mcvs: MostCommonValues, - distr: Option, - ndistinct: u64, - null_frac: f64, - ) -> Self { - Self { - mcvs, - ndistinct, - null_frac, - distr, - } - } -} - -#[cfg(test)] -mod tests { - use super::{Counter, MostCommonValues}; - use crate::{common::values::Value, stats::AttributeCombValue}; - use serde_json::json; - - #[test] - fn test_most_common_values() { - let elem1 = vec![Some(Value::Int32(1))]; - let elem2 = vec![Some(Value::Int32(2))]; - let mut counter = Counter::new(&[elem1.clone(), elem2.clone()]); - - let elems = vec![elem2.clone(), elem1.clone(), elem2.clone(), elem2.clone()]; - counter.aggregate(&elems); - - let mcvs = MostCommonValues::Counter(counter); - assert_eq!(mcvs.freq(&elem1), Some(0.25)); - assert_eq!(mcvs.freq(&elem2), Some(0.75)); - assert_eq!(mcvs.total_freq(), 1.0); - - let elem1_cloned = elem1.clone(); - let pred1 = Box::new(move |x: &AttributeCombValue| x == &elem1_cloned); - let pred2 = Box::new(move |x: &AttributeCombValue| x != &elem1); - assert_eq!(mcvs.freq_over_pred(pred1), 0.25); - assert_eq!(mcvs.freq_over_pred(pred2), 0.75); - - assert_eq!(mcvs.cnt(), 2); - } - - #[test] - fn test_most_common_values_serde() { - let elem1 = vec![Some(Value::Int32(1))]; - let elem2 = vec![Some(Value::Int32(2))]; - let mut counter = Counter::new(&[elem1.clone(), elem2.clone()]); - - let elems = vec![elem2.clone(), elem1.clone(), elem2.clone(), elem2.clone()]; - counter.aggregate(&elems); - - let mcvs = MostCommonValues::Counter(counter); - let serialized = serde_json::to_value(&mcvs).unwrap(); - println!("serialized: {:?}", serialized); - - let deserialized: MostCommonValues = serde_json::from_value(serialized).unwrap(); - assert_eq!(mcvs.freq(&elem1), Some(0.25)); - assert_eq!(mcvs.freq(&elem2), Some(0.75)); - assert_eq!(mcvs.total_freq(), 1.0); - - let elem1_cloned = elem1.clone(); - let pred1 = Box::new(move |x: &AttributeCombValue| x == &elem1_cloned); - let pred2 = Box::new(move |x: &AttributeCombValue| x != &elem1); - assert_eq!(mcvs.freq_over_pred(pred1), 0.25); - assert_eq!(mcvs.freq_over_pred(pred2), 0.75); - - assert_eq!(mcvs.cnt(), 2); - } - - // TODO: Add tests for Distribution -} diff --git a/optd-cost-model/src/stats/utilities/counter.rs b/optd-cost-model/src/stats/utilities/counter.rs deleted file mode 100644 index 368700c..0000000 --- a/optd-cost-model/src/stats/utilities/counter.rs +++ /dev/null @@ -1,204 +0,0 @@ -use std::collections::HashMap; -use std::hash::Hash; - -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; - -/// The Counter structure to track exact frequencies of fixed elements. -/// TODO: remove the clone, see the comment in the [`AttributeCombValueStats`] -#[serde_with::serde_as] -#[derive(Default, Serialize, Deserialize, Debug, Clone)] -pub struct Counter { - #[serde_as(as = "HashMap")] - counts: HashMap, // The exact counts of an element T. - total_count: i32, // The total number of elements. -} - -// Self-contained implementation of the Counter data structure. -impl Counter -where - T: PartialEq + Eq + Hash + Clone + Serialize + DeserializeOwned, -{ - /// Creates and initializes a new empty Counter with the frequency map sized - /// based on the number of unique elements in `to_track`. - pub fn new(to_track: &[T]) -> Self { - let mut counts: HashMap = HashMap::with_capacity(to_track.len()); - for item in to_track { - counts.insert(item.clone(), 0); - } - - Counter:: { - counts, - total_count: 0, - } - } - - pub fn new_from_existing(counts: HashMap, total_count: i32) -> Self { - Counter:: { - counts, - total_count, - } - } - - // Inserts an element in the Counter if it is being tracked. - fn insert_element(&mut self, elem: T, occ: i32) { - if let Some(frequency) = self.counts.get_mut(&elem) { - *frequency += occ; - } - } - - /// Digests an array of data into the Counter structure. - pub fn aggregate(&mut self, data: &[T]) { - data.iter() - .for_each(|key| self.insert_element(key.clone(), 1)); - self.total_count += data.len() as i32; - } - - /// Merges another Counter into the current one. - /// Particularly useful for parallel execution. - pub fn merge(&mut self, other: &Counter) { - other - .counts - .iter() - .for_each(|(key, occ)| self.insert_element(key.clone(), *occ)); - self.total_count += other.total_count; - } - - /// Returns the frequencies of the most common values. - pub fn frequencies(&self) -> HashMap { - self.counts - .iter() - .map(|(key, &value)| (key.clone(), value as f64 / self.total_count as f64)) - .collect() - } - - /// Whether the counter tracks the given key. - pub fn is_tracking(&self, key: &T) -> bool { - self.counts.contains_key(key) - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - use std::sync::{Arc, Mutex}; - - use crossbeam::thread; - use rand::rngs::StdRng; - use rand::seq::SliceRandom; - use rand::SeedableRng; - - use super::Counter; - - // Generates hardcoded frequencies and returns them, - // along with a flattened randomized array containing those frequencies. - fn generate_frequencies() -> (HashMap, Vec) { - let mut frequencies = HashMap::new(); - - frequencies.insert(0, 2); - frequencies.insert(1, 4); - frequencies.insert(2, 9); - frequencies.insert(3, 8); - frequencies.insert(4, 50); - frequencies.insert(5, 6); - - let mut flattened = Vec::new(); - for (key, &value) in &frequencies { - for _ in 0..value { - flattened.push(*key); - } - } - - let mut rng = StdRng::seed_from_u64(0); - flattened.shuffle(&mut rng); - - (frequencies, flattened) - } - - #[test] - fn aggregate() { - let to_track = vec![0, 1, 2, 3]; - let mut mcv = Counter::::new(&to_track); - - let (frequencies, flattened) = generate_frequencies(); - - mcv.aggregate(&flattened); - - let mcv_freq = mcv.frequencies(); - assert_eq!(mcv_freq.len(), to_track.len()); - - to_track.iter().for_each(|item| { - assert!(mcv_freq.contains_key(item)); - assert_eq!( - mcv_freq.get(item), - frequencies - .get(item) - .map(|e| (*e as f64 / flattened.len() as f64)) - .as_ref() - ); - }); - } - - #[test] - fn merge() { - let to_track = vec![0, 1, 2, 3]; - let n_jobs = 16; - - let total_frequencies = Arc::new(Mutex::new(HashMap::::new())); - let total_count = Arc::new(Mutex::new(0)); - let result_mcv = Arc::new(Mutex::new(Counter::::new(&to_track))); - thread::scope(|s| { - for _ in 0..n_jobs { - s.spawn(|_| { - let mut local_mcv = Counter::::new(&to_track); - - let (local_frequencies, flattened) = generate_frequencies(); - let mut total_frequencies = total_frequencies.lock().unwrap(); - let mut total_count = total_count.lock().unwrap(); - for (&key, &value) in &local_frequencies { - *total_frequencies.entry(key).or_insert(0) += value; - *total_count += value; - } - - local_mcv.aggregate(&flattened); - - let mcv_local_freq = local_mcv.frequencies(); - assert_eq!(mcv_local_freq.len(), to_track.len()); - - to_track.iter().for_each(|item| { - assert!(mcv_local_freq.contains_key(item)); - assert_eq!( - mcv_local_freq.get(item), - local_frequencies - .get(item) - .map(|e| (*e as f64 / flattened.len() as f64)) - .as_ref() - ); - }); - - let mut result = result_mcv.lock().unwrap(); - result.merge(&local_mcv); - }); - } - }) - .unwrap(); - - let mcv = result_mcv.lock().unwrap(); - let total_count = total_count.lock().unwrap(); - let mcv_freq = mcv.frequencies(); - - assert_eq!(*total_count, mcv.total_count); - to_track.iter().for_each(|item| { - assert!(mcv_freq.contains_key(item)); - assert_eq!( - mcv_freq.get(item), - total_frequencies - .lock() - .unwrap() - .get(item) - .map(|e| (*e as f64 / *total_count as f64)) - .as_ref() - ); - }); - } -} diff --git a/optd-cost-model/src/stats/utilities/mod.rs b/optd-cost-model/src/stats/utilities/mod.rs deleted file mode 100644 index 0a7903b..0000000 --- a/optd-cost-model/src/stats/utilities/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod counter; -pub mod simple_map; -pub mod tdigest; diff --git a/optd-cost-model/src/stats/utilities/simple_map.rs b/optd-cost-model/src/stats/utilities/simple_map.rs deleted file mode 100644 index d04439e..0000000 --- a/optd-cost-model/src/stats/utilities/simple_map.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::collections::HashMap; -use std::hash::Hash; - -use serde::{Deserialize, Serialize}; - -use crate::common::values::Value; - -/// TODO: documentation -/// Now it is mainly for testing purposes. -#[derive(Clone, Serialize, Deserialize, Debug, Default)] -pub struct SimpleMap { - pub(crate) m: HashMap, -} - -impl SimpleMap { - pub fn new(v: Vec<(K, f64)>) -> Self { - Self { - m: v.into_iter().collect(), - } - } -} diff --git a/optd-cost-model/src/stats/utilities/tdigest.rs b/optd-cost-model/src/stats/utilities/tdigest.rs deleted file mode 100644 index 96a2269..0000000 --- a/optd-cost-model/src/stats/utilities/tdigest.rs +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (c) 2023-2024 CMU Database Group -// -// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -//! Simplified implementation of the TDigest data structure as described in -//! Ted Dunning's paper: -//! "Computing Extremely Accurate Quantiles Using t-Digests" (2019). -//! For more details, refer to: https://arxiv.org/pdf/1902.04023.pdf - -use std::f64::consts::PI; -use std::hash::Hash; -use std::marker::PhantomData; - -use itertools::Itertools; -use serde::{Deserialize, Serialize}; - -use crate::{common::values::Value, stats::arith_encoder}; - -pub const DEFAULT_COMPRESSION: f64 = 200.0; - -/// Trait to transform any object into a stream of bytes. -pub trait IntoFloat { - fn to_float(&self) -> f64; -} - -/// The TDigest structure for the statistical aggregator to query quantiles. -#[derive(Clone, Serialize, Deserialize, Debug)] -pub struct TDigest { - /// A sorted array of Centroids, according to their mean. - pub centroids: Vec, /* TODO(Alexis): Temporary fix to normalize the stats in - * stats.rs [pub]. */ - /// Compression factor: higher is more precise, but has higher memory requirements. - compression: f64, - /// Number of values in the TDigest (sum of all centroids). - total_weight: usize, - - // TODO(Alexis): Temporary fix to normalize the stats in stats.rs [field]. - pub norm_weight: usize, - - data_type: PhantomData, // For type checker. -} - -/// A Centroid is a cluster of aggregated data points. -#[derive(PartialEq, PartialOrd, Clone, Serialize, Deserialize, Debug)] -pub struct Centroid { - // TODO(Alexis): Temporary fix to normalize the stats in stats.rs [pub]. - /// Mean of all aggregated points in this cluster. - mean: f64, - /// The number of points in this cluster. - weight: usize, -} - -// Utility functions defined on a Centroid. -impl Centroid { - // Merges an existing Centroid into itself. - fn merge(&mut self, other: &Centroid) { - let weight = self.weight + other.weight; - self.mean = - ((self.mean * self.weight as f64) + (other.mean * other.weight as f64)) / weight as f64; - self.weight = weight; - } -} - -// IntoFloat implementation of optd's Value. -impl IntoFloat for Value { - fn to_float(&self) -> f64 { - match self { - Value::UInt8(v) => *v as f64, - Value::UInt16(v) => *v as f64, - Value::UInt32(v) => *v as f64, - Value::UInt64(v) => *v as f64, - Value::Int8(v) => *v as f64, - Value::Int16(v) => *v as f64, - Value::Int32(v) => *v as f64, - Value::Int64(v) => *v as f64, - Value::Float(v) => *v.0, - Value::Bool(v) => *v as i64 as f64, - Value::String(v) => arith_encoder::encode(v), - Value::Date32(v) => *v as f64, - _ => unreachable!(), - } - } -} - -// Self-contained implementation of the TDigest data structure. -impl TDigest -where - T: IntoFloat + Eq + Hash + Clone, -{ - /// Creates and initializes a new empty TDigest. - pub fn new(compression: f64) -> Self { - TDigest { - centroids: Vec::new(), - compression, - total_weight: 0, - - norm_weight: 0, - data_type: PhantomData, - } - } - - /// Ingests an array of non-NaN f64 values into the TDigest. - pub fn merge_values(&mut self, values: &[T]) { - let centroids = values - .iter() - .map(|val| val.to_float()) - .sorted_by(|a, b| a.partial_cmp(b).unwrap()) - .map(|v| Centroid { mean: v, weight: 1 }) - .collect_vec(); - let compression = self.compression; - let total_weight = centroids.len(); - - // Create an ephemeral TDigest to reuse the same interface. - self.merge(&TDigest { - centroids, - compression, - total_weight, - - norm_weight: 0, - data_type: PhantomData, - }); - } - - /// Merges two TDigests together and returns a new one. - /// Particularly useful for parallel execution. - /// Note: self to_ignore set is *NOT* updated. - pub fn merge(&mut self, other: &TDigest) { - let mut sorted_centroids = self.centroids.iter().merge(other.centroids.iter()); - - let mut new_centroids = Vec::new(); - let total_weight = self.total_weight + other.total_weight; - - // Initialize the greedy merging (copy first Centroid as a starting point). - let mut q_curr = 0.0; - let mut q_limit = self.k_rev_scale(self.k_scale(q_curr) + 1.0); - - let mut tmp_centroid = match sorted_centroids.next() { - Some(centroid) => centroid.clone(), - None => { - return; - } - }; - - // Iterate over ordered and merged Centroids (starting from index 1). - for centroid in sorted_centroids { - let q_new = (tmp_centroid.weight + centroid.weight) as f64 / total_weight as f64; - if (q_curr + q_new) <= q_limit { - tmp_centroid.merge(centroid) - } else { - q_curr += tmp_centroid.weight as f64 / total_weight as f64; - q_limit = self.k_rev_scale(self.k_scale(q_curr) + 1.0); - new_centroids.push(tmp_centroid); - tmp_centroid = centroid.clone(); - } - } - new_centroids.push(tmp_centroid); - - self.centroids = new_centroids; - self.total_weight += other.total_weight; - } - - /// Obtains a given quantile from the TDigest. - /// Returns 0.0 if TDigest is empty. - /// Performs a linear interpollation between two neighboring Centroids if needed. - /// Note: This is *not* normalized with nb_ignored. - pub fn quantile(&self, q: f64) -> f64 { - let target_cum = q * (self.total_weight as f64); - let pos_cum = self // Finds the centroid whose *cumulative weight* exceeds or equals the quantile. - .centroids - .iter() - .map(|c| c.weight) - .scan(0, |acc, weight| { - *acc += weight; - Some(*acc) - }) - .enumerate() - .find(|&(_, cum)| target_cum < (cum as f64)); - - match pos_cum { - Some((pos, cum)) => { - // TODO: We ignore edge-cases where Centroid's weights are 1. - if (pos == 0) || (pos == self.centroids.len() - 1) { - self.centroids[pos].mean - } else { - // Quantile is somewhere between in (prev+curr)/2 and (curr+next)/2 means. - let (prev, curr, next) = ( - &self.centroids[pos - 1], - &self.centroids[pos], - &self.centroids[pos + 1], - ); - let (min_q, max_q) = - ((prev.mean + curr.mean) / 2.0, (curr.mean + next.mean) / 2.0); - lerp( - min_q, - max_q, - ((cum as f64) - target_cum) / (curr.weight as f64), - ) - } - } - None => self.centroids.last().map(|c| c.mean).unwrap_or(0.0), - } - } - - /// Obtains the CDF corresponding to a given value. - /// Returns 0.0 if the TDigest is empty. - /// Note: This *is* normalized with nb_ignored. - pub fn cdf(&self, v: &T) -> f64 { - let mut cum_sum = 0; - let pos_cum = self // Finds the centroid whose *mean* exceeds or equals the given value. - .centroids - .iter() - .enumerate() - .find(|(_, c)| { - cum_sum += c.weight; // Get the cum_sum as a side effect. - v.to_float() < c.mean - }) - .map(|(pos, _)| (pos, cum_sum)); - - let nb_total = self.total_weight as f64; - match pos_cum { - Some((_pos, cum)) => { - // TODO: Can do better with 2 lerps, left as future work. - // TODO: We ignore edge-cases where Centroid's weights are 1. - (cum as f64) / nb_total - } - None => self.centroids.last().map(|_| 1.0).unwrap_or(0.0), - } - } - - // Obtains the k-distance for a given quantile. - // Note: The scaling function implemented is k1 in Ted Dunning's paper. - fn k_scale(&self, quantile: f64) -> f64 { - (self.compression / (2.0 * PI)) * (2.0 * quantile - 1.0).asin() - } - - // Obtains the quantile associated to a k-distance. - // There are probably numerical optimizations to flatten the nested - // k_scale(k_rev_scale()) calls. But let's keep it simple. - fn k_rev_scale(&self, k_distance: f64) -> f64 { - ((2.0 * PI * k_distance / self.compression).sin() + 1.0) / 2.0 - } -} - -// Performs the linear interpolation between a and b, given a fraction f. -fn lerp(a: f64, b: f64, f: f64) -> f64 { - (a * (1.0 - f)) + (b * f) -} - -#[cfg(test)] -mod tests { - use std::sync::{Arc, Mutex}; - - use crossbeam::thread; - use ordered_float::OrderedFloat; - use rand::distributions::{Distribution, Uniform, WeightedIndex}; - use rand::rngs::StdRng; - use rand::SeedableRng; - - use super::{IntoFloat, TDigest}; - - impl IntoFloat for OrderedFloat { - fn to_float(&self) -> f64 { - self.0 - } - } - - // Whether obtained = expected +/- error - fn is_close(obtained: f64, expected: f64, error: f64) -> bool { - ((expected - error) < obtained) && (obtained < (expected + error)) - } - - // Checks whether the tdigest follows a uniform distribution. - fn check_tdigest_uniform( - tdigest: &TDigest>, - buckets: i32, - max: f64, - min: f64, - error: f64, - ) { - for k in 0..buckets { - let expected_cdf = (k as f64) / (buckets as f64); - let expected_quantile = (max - min) * expected_cdf + min; - - let obtained_cdf = tdigest.cdf(&OrderedFloat(expected_quantile)); - let obtained_quantile = tdigest.quantile(expected_cdf); - - assert!(is_close(obtained_cdf, expected_cdf, error)); - assert!(is_close( - obtained_quantile, - expected_quantile, - (max - min) * error, - )); - } - } - - #[test] - fn uniform_merge_sequential() { - let buckets = 200; - let error = 0.03; // 3% absolute error on each quantile; error gets worse near the median. - let mut tdigest = TDigest::new(buckets as f64); - - let (min, max) = (-1000.0, 1000.0); - let uniform_distr = Uniform::new(min, max); - let mut rng = StdRng::seed_from_u64(0); - - let batch_size = 1024; - let batch_numbers = 64; - - for _ in 0..batch_numbers { - let mut random_numbers = Vec::with_capacity(batch_size); - for _ in 0..batch_size { - let num: f64 = uniform_distr.sample(&mut rng); - random_numbers.push(OrderedFloat(num)); - } - tdigest.merge_values(&random_numbers); - } - - check_tdigest_uniform(&tdigest, buckets, max, min, error); - } - - #[test] - fn uniform_merge_parallel() { - let buckets = 200; - let error = 0.03; // 3% absolute error on each quantile, note error is worse near the median. - - let (min, max) = (-1000.0, 1000.0); - - let batch_size = 65536; - let batch_numbers = 64; - - let result_tdigest = Arc::new(Mutex::new(TDigest::new(buckets as f64))); - thread::scope(|s| { - for _ in 0..batch_numbers { - s.spawn(|_| { - let mut local_tdigest = TDigest::new(buckets as f64); - - let mut random_numbers = Vec::with_capacity(batch_size); - let uniform_distr = Uniform::new(min, max); - let mut rng = StdRng::seed_from_u64(0); - - for _ in 0..batch_size { - let num: f64 = uniform_distr.sample(&mut rng); - random_numbers.push(OrderedFloat(num)); - } - local_tdigest.merge_values(&random_numbers); - - let mut result = result_tdigest.lock().unwrap(); - result.merge(&local_tdigest); - }); - } - }) - .unwrap(); - - let tdigest = result_tdigest.lock().unwrap(); - check_tdigest_uniform(&tdigest, buckets, max, min, error); - } - - #[test] - fn weighted_merge() { - let buckets = 200; - let error = 0.05; // 5% absolute error on each quantile, note error is worse near the median. - - let mut tdigest = TDigest::new(buckets as f64); - - let choices = [9.0, 900.0, 990.0, 9990.0, 190000.0, 990000.0]; - let weights = [1, 2, 1, 3, 4, 5]; // Total of 16. - let total_weight: i32 = weights.iter().sum(); - - let weighted_distr = WeightedIndex::new(weights).unwrap(); - let mut rng = StdRng::seed_from_u64(0); - - let batch_size = 128; - let batch_numbers = 16; - - for _ in 0..batch_numbers { - let mut random_numbers = Vec::with_capacity(batch_size); - for _ in 0..batch_size { - let num: f64 = choices[weighted_distr.sample(&mut rng)]; - random_numbers.push(OrderedFloat(num)); - } - tdigest.merge_values(&random_numbers); - } - - let mut curr_weight = 0; - for (c, w) in choices.iter().zip(weights) { - curr_weight += w; - let estimate_cdf = tdigest.cdf(&OrderedFloat(*c)); - let obtained_cdf = (curr_weight as f64) / (total_weight as f64); - assert!(is_close(obtained_cdf, estimate_cdf, error)); - } - } -} diff --git a/optd-cost-model/src/storage/mock.rs b/optd-cost-model/src/storage/mock.rs deleted file mode 100644 index f20c417..0000000 --- a/optd-cost-model/src/storage/mock.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![allow(unused_variables, dead_code)] -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -use crate::{ - common::types::{EpochId, ExprId, TableId}, - stats::AttributeCombValueStats, - Cost, CostModelResult, EstimatedStatistic, -}; - -use super::CostModelStorageManager; - -pub type AttrIndices = Vec; - -#[serde_with::serde_as] -#[derive(Serialize, Deserialize, Debug)] -pub struct TableStats { - pub row_cnt: u64, - #[serde_as(as = "HashMap")] - pub column_comb_stats: HashMap, -} - -impl TableStats { - pub fn new( - row_cnt: u64, - column_comb_stats: HashMap, - ) -> Self { - Self { - row_cnt, - column_comb_stats, - } - } -} - -pub type BaseTableStats = HashMap; - -pub struct CostModelStorageMockManagerImpl { - pub(crate) per_table_stats_map: BaseTableStats, -} - -impl CostModelStorageMockManagerImpl { - pub fn new(per_table_stats_map: BaseTableStats) -> Self { - Self { - per_table_stats_map, - } - } -} - -impl CostModelStorageManager for CostModelStorageMockManagerImpl { - async fn get_attributes_comb_statistics( - &self, - table_id: TableId, - attr_base_indices: &[u64], - ) -> CostModelResult> { - let table_stats = self.per_table_stats_map.get(&table_id); - match table_stats { - None => Ok(None), - Some(table_stats) => match table_stats.column_comb_stats.get(attr_base_indices) { - None => Ok(None), - Some(stats) => Ok(Some(stats.clone())), - }, - } - } - - async fn get_table_row_count(&self, table_id: TableId) -> CostModelResult> { - let table_stats = self.per_table_stats_map.get(&table_id); - Ok(table_stats.map(|stats| stats.row_cnt)) - } - - /// TODO: finish this when implementing the cost get/store tests - async fn get_cost( - &self, - expr_id: ExprId, - ) -> CostModelResult<(Option, Option)> { - todo!() - } - - /// TODO: finish this when implementing the cost get/store tests - async fn store_cost( - &self, - expr_id: ExprId, - cost: Option, - estimated_statistic: Option, - epoch_id: Option, - ) -> CostModelResult<()> { - todo!() - } -} diff --git a/optd-cost-model/src/storage/mod.rs b/optd-cost-model/src/storage/mod.rs deleted file mode 100644 index 14cccd6..0000000 --- a/optd-cost-model/src/storage/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{ - common::types::{EpochId, ExprId, TableId}, - stats::AttributeCombValueStats, - Cost, CostModelResult, EstimatedStatistic, -}; - -pub mod mock; -pub mod persistent; - -#[trait_variant::make(Send)] -pub trait CostModelStorageManager { - async fn get_attributes_comb_statistics( - &self, - table_id: TableId, - attr_base_indices: &[u64], - ) -> CostModelResult>; - - async fn get_table_row_count(&self, table_id: TableId) -> CostModelResult>; - - async fn get_cost( - &self, - expr_id: ExprId, - ) -> CostModelResult<(Option, Option)>; - - async fn store_cost( - &self, - expr_id: ExprId, - cost: Option, - estimated_statistic: Option, - epoch_id: Option, - ) -> CostModelResult<()>; -} diff --git a/optd-cost-model/src/storage/persistent.rs b/optd-cost-model/src/storage/persistent.rs deleted file mode 100644 index b3078a6..0000000 --- a/optd-cost-model/src/storage/persistent.rs +++ /dev/null @@ -1,166 +0,0 @@ -#![allow(unused_variables)] -use std::sync::Arc; - -use optd_persistent::{cost_model::interface::StatType, CostModelStorageLayer}; - -use crate::{ - common::types::{EpochId, ExprId, TableId}, - stats::{utilities::counter::Counter, AttributeCombValueStats, Distribution, MostCommonValues}, - Cost, CostModelResult, EstimatedStatistic, -}; - -use super::CostModelStorageManager; - -/// TODO: documentation -pub struct CostModelStorageManagerImpl { - pub backend_manager: Arc, - // TODO: in-memory cache -} - -impl CostModelStorageManagerImpl { - pub fn new(backend_manager: Arc) -> Self { - Self { backend_manager } - } -} - -impl CostModelStorageManager - for CostModelStorageManagerImpl -{ - /// Gets the latest statistics for a given table. Currently we only support base table - /// statistic retrieval. - /// - /// TODO: Currently, in `AttributeCombValueStats`, only `Distribution` is optional. - /// This poses a question about the behavior of the system if there is no corresponding - /// `MostCommonValues`, `ndistinct`, or other statistics. We should have a clear - /// specification about the behavior of the system in the presence of missing statistics. - /// - /// TODO: if we have memory cache, - /// we should add the reference. (&AttributeCombValueStats) - /// - /// TODO: Shall we pass in an epoch here to make sure that the statistics are from the same - /// epoch? - async fn get_attributes_comb_statistics( - &self, - table_id: TableId, - attr_base_indices: &[u64], - ) -> CostModelResult> { - let dist: Option = self - .backend_manager - .get_stats_for_attr_indices_based( - table_id.into(), - attr_base_indices.iter().map(|&x| x as i32).collect(), - StatType::Distribution, - None, - ) - .await? - .map(|json| serde_json::from_value(json).unwrap()); - - let mcvs = self - .backend_manager - .get_stats_for_attr_indices_based( - table_id.into(), - attr_base_indices.iter().map(|&x| x as i32).collect(), - StatType::MostCommonValues, - None, - ) - .await? - .map(|json| serde_json::from_value(json).unwrap()) - .unwrap_or_else(|| MostCommonValues::Counter(Counter::default())); - - let ndistinct = self - .backend_manager - .get_stats_for_attr_indices_based( - table_id.into(), - attr_base_indices.iter().map(|&x| x as i32).collect(), - StatType::Cardinality, - None, - ) - .await? - .map(|json| serde_json::from_value(json).unwrap()) - .unwrap_or(0); - - let table_row_count = self - .backend_manager - .get_stats_for_attr_indices_based( - table_id.into(), - attr_base_indices.iter().map(|&x| x as i32).collect(), - StatType::TableRowCount, - None, - ) - .await? - .map(|json| serde_json::from_value(json).unwrap()) - .unwrap_or(0); - let non_null_count = self - .backend_manager - .get_stats_for_attr_indices_based( - table_id.into(), - attr_base_indices.iter().map(|&x| x as i32).collect(), - StatType::NonNullCount, - None, - ) - .await? - .map(|json| serde_json::from_value(json).unwrap()) - .unwrap_or(0); - - // FIXME: Only minimal checks for invalid values is conducted here. We should have - // much clear specification about the behavior of the system in the presence of - // invalid statistics. - let null_frac = if table_row_count == 0 { - 0.0 - } else { - 1.0 - (non_null_count as f64 / table_row_count as f64) - }; - - Ok(Some(AttributeCombValueStats::new( - mcvs, dist, ndistinct, null_frac, - ))) - } - - async fn get_table_row_count(&self, table_id: TableId) -> CostModelResult> { - Ok(self - .backend_manager - .get_stats_for_table(table_id.into(), StatType::TableRowCount, None) - .await? - .map(serde_json::from_value) - .transpose()?) - } - - /// TODO: The name is misleading, since we can also get the estimated statistic. We should - /// rename it. - /// - /// TODO: Add retry logic here. - async fn get_cost( - &self, - expr_id: ExprId, - ) -> CostModelResult<(Option, Option)> { - let (cost, estimated_statistic) = self.backend_manager.get_cost(expr_id.into()).await?; - Ok(( - cost.map(|c| c.into()), - estimated_statistic.map(|x| x.into()), - )) - } - - /// TODO: The name is misleading, since we can also get the estimated statistic. We should - /// rename it. - /// - /// TODO: Add retry logic here. - async fn store_cost( - &self, - expr_id: ExprId, - cost: Option, - estimated_statistic: Option, - epoch_id: Option, - ) -> CostModelResult<()> { - self.backend_manager - .store_cost( - expr_id.into(), - cost.map(|c| c.into()), - estimated_statistic.map(|x| x.into()), - epoch_id.map(|id| id.into()), - ) - .await?; - Ok(()) - } - - // TODO: Support querying for a specific type of statistics. -} diff --git a/optd-cost-model/src/test_utils.rs b/optd-cost-model/src/test_utils.rs deleted file mode 100644 index 60db90f..0000000 --- a/optd-cost-model/src/test_utils.rs +++ /dev/null @@ -1,565 +0,0 @@ -/// I thought about using the system's own parser and planner to generate these expression trees, -/// but this is not currently feasible because it would create a cyclic dependency between -/// optd-datafusion-bridge and optd-datafusion-repr -#[cfg(test)] -pub mod tests { - use itertools::Itertools; - use std::{collections::HashMap, sync::Arc}; - - use arrow_schema::DataType; - use optd_persistent::cost_model::interface::CatalogSource; - - use crate::{ - common::{ - nodes::{ArcPredicateNode, ReprPredicateNode}, - predicates::{ - attr_index_pred::AttrIndexPred, - bin_op_pred::{BinOpPred, BinOpType}, - cast_pred::CastPred, - constant_pred::{ConstantPred, ConstantType}, - in_list_pred::InListPred, - like_pred::LikePred, - list_pred::ListPred, - log_op_pred::{LogOpPred, LogOpType}, - un_op_pred::{UnOpPred, UnOpType}, - }, - properties::{ - attr_ref::{AttrRef, GroupAttrRefs}, - schema::Schema, - Attribute, - }, - types::{GroupId, TableId}, - values::Value, - }, - cost_model::CostModelImpl, - memo_ext::MemoExt, - stats::{ - utilities::simple_map::SimpleMap, AttributeCombValueStats, Distribution, - MostCommonValues, - }, - storage::mock::{CostModelStorageMockManagerImpl, TableStats}, - }; - - pub struct MemoGroupInfo { - pub schema: Schema, - pub attr_refs: GroupAttrRefs, - } - - impl MemoGroupInfo { - pub fn new(schema: Schema, attr_refs: GroupAttrRefs) -> Self { - Self { schema, attr_refs } - } - } - - #[derive(Default)] - pub struct MockMemoExtImpl { - memo: HashMap, - } - - impl MockMemoExtImpl { - pub fn add_group_info( - &mut self, - group_id: GroupId, - schema: Schema, - attr_ref: GroupAttrRefs, - ) { - self.memo - .insert(group_id, MemoGroupInfo::new(schema, attr_ref)); - } - } - - impl MemoExt for MockMemoExtImpl { - fn get_schema(&self, group_id: GroupId) -> Schema { - self.memo.get(&group_id).unwrap().schema.clone() - } - - fn get_attribute_info(&self, group_id: GroupId, attr_ref_idx: u64) -> Attribute { - self.memo.get(&group_id).unwrap().schema.attributes[attr_ref_idx as usize].clone() - } - - fn get_attribute_refs(&self, group_id: GroupId) -> GroupAttrRefs { - self.memo.get(&group_id).unwrap().attr_refs.clone() - } - - fn get_attribute_ref(&self, group_id: GroupId, attr_ref_idx: u64) -> AttrRef { - self.memo.get(&group_id).unwrap().attr_refs.attr_refs()[attr_ref_idx as usize].clone() - } - } - - impl From> for MockMemoExtImpl { - fn from(memo: HashMap) -> Self { - Self { memo } - } - } - - pub const TEST_TABLE1_ID: TableId = TableId(0); - pub const TEST_TABLE2_ID: TableId = TableId(1); - pub const TEST_TABLE3_ID: TableId = TableId(2); - pub const TEST_TABLE4_ID: TableId = TableId(3); - - pub const TEST_GROUP1_ID: GroupId = GroupId(0); - pub const TEST_GROUP2_ID: GroupId = GroupId(1); - pub const TEST_GROUP3_ID: GroupId = GroupId(2); - pub const TEST_GROUP4_ID: GroupId = GroupId(3); - - // This is base index rather than ref index. - pub const TEST_ATTR1_BASE_INDEX: u64 = 0; - pub const TEST_ATTR2_BASE_INDEX: u64 = 1; - pub const TEST_ATTR3_BASE_INDEX: u64 = 2; - - pub const TEST_ATTR1_NAME: &str = "attr1"; - pub const TEST_ATTR2_NAME: &str = "attr2"; - pub const TEST_ATTR3_NAME: &str = "attr3"; - pub const TEST_ATTR4_NAME: &str = "attr4"; - - pub type TestPerAttributeStats = AttributeCombValueStats; - // TODO: add tests for non-mock storage manager - pub type TestOptCostModelMock = CostModelImpl; - - // Use this method, we only create one group `TEST_GROUP1_ID` in the memo. - // We put the first attribute in the first table as the ref index 0 in the group. - // And put the second attribute in the first table as the ref index 1 in the group. - // etc. - // The orders of attributes and tables are defined by the order of their ids (smaller first). - pub fn create_mock_cost_model( - table_id: Vec, - // u64 should be base attribute index. - per_attribute_stats: Vec>, - row_counts: Vec>, - ) -> TestOptCostModelMock { - let attr_ids: Vec<(TableId, u64, Option)> = per_attribute_stats - .iter() - .enumerate() - .map(|(idx, m)| (table_id[idx], m)) - .flat_map(|(table_id, m)| { - m.iter() - .map(|(attr_idx, _)| (table_id, *attr_idx, None)) - .collect_vec() - }) - .sorted_by_key(|(table_id, attr_idx, _)| (*table_id, *attr_idx)) - .collect(); - create_mock_cost_model_with_memo( - table_id.clone(), - per_attribute_stats, - row_counts, - create_one_group_all_base_attributes_mock_memo(attr_ids), - ) - } - - pub fn create_mock_cost_model_with_attr_types( - table_id: Vec, - // u64 should be base attribute index. - per_attribute_stats: Vec>, - attributes: Vec>, - row_counts: Vec>, - ) -> TestOptCostModelMock { - let attr_ids: Vec<(TableId, u64, Option)> = attributes - .iter() - .enumerate() - .map(|(idx, m)| (table_id[idx], m)) - .flat_map(|(table_id, m)| { - m.iter() - .map(|(attr_idx, typ)| (table_id, *attr_idx, Some(*typ))) - .collect_vec() - }) - .sorted_by_key(|(table_id, attr_idx, _)| (*table_id, *attr_idx)) - .collect(); - create_mock_cost_model_with_memo( - table_id.clone(), - per_attribute_stats, - row_counts, - create_one_group_all_base_attributes_mock_memo(attr_ids), - ) - } - - pub fn create_mock_cost_model_with_memo( - table_id: Vec, - per_attribute_stats: Vec>, - row_counts: Vec>, - memo: MockMemoExtImpl, - ) -> TestOptCostModelMock { - let storage_manager = CostModelStorageMockManagerImpl::new( - table_id - .into_iter() - .zip(per_attribute_stats) - .zip(row_counts) - .map(|((table_id, per_attr_stats), row_count)| { - ( - table_id, - TableStats::new( - row_count.unwrap_or(100), - per_attr_stats - .into_iter() - .map(|(attr_idx, stats)| (vec![attr_idx], stats)) - .collect(), - ), - ) - }) - .collect(), - ); - CostModelImpl::new(storage_manager, CatalogSource::Mock, Arc::new(memo)) - } - - // attributes: Vec<(TableId, AttrBaseIndex)> - pub fn create_one_group_all_base_attributes_mock_memo( - attr_ids: Vec<(TableId, u64, Option)>, - ) -> MockMemoExtImpl { - let group_info = MemoGroupInfo::new( - Schema::new( - attr_ids - .clone() - .into_iter() - .map(|(_, _, typ)| Attribute { - name: "attr".to_string(), - typ: typ.unwrap_or(ConstantType::Int64), - nullable: false, - }) - .collect(), - ), - GroupAttrRefs::new( - attr_ids - .into_iter() - .map(|(table_id, attr_base_index, _)| { - AttrRef::new_base_table_attr_ref(table_id, attr_base_index) - }) - .collect(), - None, - ), - ); - MockMemoExtImpl::from(HashMap::from([(TEST_GROUP1_ID, group_info)])) - } - - /// Create a cost model two tables, each with one attribute. Each attribute has 100 values. - pub fn create_two_table_mock_cost_model( - tbl1_per_attr_stats: TestPerAttributeStats, - tbl2_per_attr_stats: TestPerAttributeStats, - additional_memo: Option>, - ) -> TestOptCostModelMock { - create_two_table_mock_cost_model_custom_row_cnts( - tbl1_per_attr_stats, - tbl2_per_attr_stats, - 100, - 100, - additional_memo, - ) - } - - /// Create a cost model three tables, each with one attribute. Each attribute has 100 values. - pub fn create_three_table_mock_cost_model( - tbl1_per_column_stats: TestPerAttributeStats, - tbl2_per_column_stats: TestPerAttributeStats, - tbl3_per_column_stats: TestPerAttributeStats, - ) -> TestOptCostModelMock { - let storage_manager = CostModelStorageMockManagerImpl::new( - vec![ - ( - TEST_TABLE1_ID, - TableStats::new( - 100, - vec![(vec![0], tbl1_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE2_ID, - TableStats::new( - 100, - vec![(vec![0], tbl2_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE3_ID, - TableStats::new( - 100, - vec![(vec![0], tbl3_per_column_stats)].into_iter().collect(), - ), - ), - ] - .into_iter() - .collect(), - ); - let memo = HashMap::from([ - ( - TEST_GROUP1_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP2_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP3_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR3_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE3_ID, 0)], - None, - ), - ), - ), - ]); - CostModelImpl::new( - storage_manager, - CatalogSource::Mock, - Arc::new(MockMemoExtImpl::from(memo)), - ) - } - - /// Create a cost model four tables, each with one attribute. Each attribute has 100 values. - pub fn create_four_table_mock_cost_model( - tbl1_per_column_stats: TestPerAttributeStats, - tbl2_per_column_stats: TestPerAttributeStats, - tbl3_per_column_stats: TestPerAttributeStats, - tbl4_per_column_stats: TestPerAttributeStats, - ) -> TestOptCostModelMock { - let storage_manager = CostModelStorageMockManagerImpl::new( - vec![ - ( - TEST_TABLE1_ID, - TableStats::new( - 100, - vec![(vec![0], tbl1_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE2_ID, - TableStats::new( - 100, - vec![(vec![0], tbl2_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE3_ID, - TableStats::new( - 100, - vec![(vec![0], tbl3_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE4_ID, - TableStats::new( - 100, - vec![(vec![0], tbl4_per_column_stats)].into_iter().collect(), - ), - ), - ] - .into_iter() - .collect(), - ); - let memo = HashMap::from([ - ( - TEST_GROUP1_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP2_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP3_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR3_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE3_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP4_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR4_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE4_ID, 0)], - None, - ), - ), - ), - ]); - CostModelImpl::new( - storage_manager, - CatalogSource::Mock, - Arc::new(MockMemoExtImpl::from(memo)), - ) - } - - /// We need custom row counts because some join algorithms rely on the row cnt - pub fn create_two_table_mock_cost_model_custom_row_cnts( - tbl1_per_column_stats: TestPerAttributeStats, - tbl2_per_column_stats: TestPerAttributeStats, - tbl1_row_cnt: u64, - tbl2_row_cnt: u64, - additional_memo: Option>, - ) -> TestOptCostModelMock { - let storage_manager = CostModelStorageMockManagerImpl::new( - vec![ - ( - TEST_TABLE1_ID, - TableStats::new( - tbl1_row_cnt, - vec![(vec![0], tbl1_per_column_stats)].into_iter().collect(), - ), - ), - ( - TEST_TABLE2_ID, - TableStats::new( - tbl2_row_cnt, - vec![(vec![0], tbl2_per_column_stats)].into_iter().collect(), - ), - ), - ] - .into_iter() - .collect(), - ); - let mut memo = HashMap::from([ - ( - TEST_GROUP1_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR1_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE1_ID, 0)], - None, - ), - ), - ), - ( - TEST_GROUP2_ID, - MemoGroupInfo::new( - vec![Attribute::new_non_null_int64(TEST_ATTR2_NAME.to_string())].into(), - GroupAttrRefs::new( - vec![AttrRef::new_base_table_attr_ref(TEST_TABLE2_ID, 0)], - None, - ), - ), - ), - ]); - if let Some(additional_memo) = additional_memo { - memo.extend(additional_memo); - } - CostModelImpl::new( - storage_manager, - CatalogSource::Mock, - Arc::new(MockMemoExtImpl::from(memo)), - ) - } - - impl TestOptCostModelMock { - pub fn get_row_count(&self, table_id: TableId) -> u64 { - self.storage_manager - .per_table_stats_map - .get(&table_id) - .map(|stats| stats.row_cnt) - .unwrap_or(0) - } - - pub fn get_attr_refs(&self, group_id: GroupId) -> GroupAttrRefs { - self.memo.get_attribute_refs(group_id) - } - } - - pub fn attr_index(attr_index: u64) -> ArcPredicateNode { - AttrIndexPred::new(attr_index).into_pred_node() - } - - pub fn cnst(value: Value) -> ArcPredicateNode { - ConstantPred::new(value).into_pred_node() - } - - pub fn cast(child: ArcPredicateNode, cast_type: DataType) -> ArcPredicateNode { - CastPred::new(child, cast_type).into_pred_node() - } - - pub fn bin_op( - op_type: BinOpType, - left: ArcPredicateNode, - right: ArcPredicateNode, - ) -> ArcPredicateNode { - BinOpPred::new(left, right, op_type).into_pred_node() - } - - pub fn log_op(op_type: LogOpType, children: Vec) -> ArcPredicateNode { - LogOpPred::new(op_type, children).into_pred_node() - } - - pub fn un_op(op_type: UnOpType, child: ArcPredicateNode) -> ArcPredicateNode { - UnOpPred::new(child, op_type).into_pred_node() - } - - pub fn empty_list() -> ArcPredicateNode { - ListPred::new(vec![]).into_pred_node() - } - - pub fn list(children: Vec) -> ArcPredicateNode { - ListPred::new(children).into_pred_node() - } - - pub fn in_list(attr_idx: u64, list: Vec, negated: bool) -> InListPred { - InListPred::new( - attr_index(attr_idx), - ListPred::new(list.into_iter().map(cnst).collect_vec()), - negated, - ) - } - - pub fn like(attr_idx: u64, pattern: &str, negated: bool) -> LikePred { - LikePred::new( - negated, - false, - attr_index(attr_idx), - cnst(Value::String(pattern.into())), - ) - } - - pub(crate) fn empty_per_attr_stats() -> TestPerAttributeStats { - TestPerAttributeStats::new( - MostCommonValues::empty(), - Some(Distribution::empty()), - 0, - 0.0, - ) - } - - pub(crate) fn per_attr_stats_with_ndistinct(ndistinct: u64) -> TestPerAttributeStats { - TestPerAttributeStats::new( - MostCommonValues::empty(), - Some(Distribution::empty()), - ndistinct, - 0.0, - ) - } - - pub(crate) fn per_attr_stats_with_dist_and_ndistinct( - dist: Vec<(Value, f64)>, - ndistinct: u64, - ) -> TestPerAttributeStats { - TestPerAttributeStats::new( - MostCommonValues::empty(), - Some(Distribution::SimpleDistribution(SimpleMap::new(dist))), - ndistinct, - 0.0, - ) - } -} diff --git a/optd-cost-model/src/utils.rs b/optd-cost-model/src/utils.rs deleted file mode 100644 index 125c499..0000000 --- a/optd-cost-model/src/utils.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! optd's implementation of disjoint sets (union finds). It's send + sync + serializable. - -use std::{collections::HashMap, hash::Hash}; -#[derive(Clone, Default)] -pub struct DisjointSets { - data_idx: HashMap, - parents: Vec, -} - -impl std::fmt::Debug for DisjointSets { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "DisjointSets") - } -} - -impl DisjointSets { - pub fn new() -> Self { - Self { - data_idx: HashMap::new(), - parents: Vec::new(), - } - } - - pub fn contains(&self, data: &T) -> bool { - self.data_idx.contains_key(data) - } - - #[must_use] - pub fn make_set(&mut self, data: T) -> Option<()> { - if self.data_idx.contains_key(&data) { - return None; - } - let idx = self.parents.len(); - self.data_idx.insert(data.clone(), idx); - self.parents.push(idx); - Some(()) - } - - fn find(&mut self, mut idx: usize) -> usize { - while self.parents[idx] != idx { - self.parents[idx] = self.parents[self.parents[idx]]; - idx = self.parents[idx]; - } - idx - } - - fn find_const(&self, mut idx: usize) -> usize { - while self.parents[idx] != idx { - idx = self.parents[idx]; - } - idx - } - - #[must_use] - pub fn union(&mut self, data1: &T, data2: &T) -> Option<()> { - let idx1 = *self.data_idx.get(data1)?; - let idx2 = *self.data_idx.get(data2)?; - let parent1 = self.find(idx1); - let parent2 = self.find(idx2); - if parent1 != parent2 { - self.parents[parent1] = parent2; - } - Some(()) - } - - pub fn same_set(&self, data1: &T, data2: &T) -> Option { - let idx1 = *self.data_idx.get(data1)?; - let idx2 = *self.data_idx.get(data2)?; - Some(self.find_const(idx1) == self.find_const(idx2)) - } - - pub fn set_size(&self, data: &T) -> Option { - let idx = *self.data_idx.get(data)?; - let parent = self.find_const(idx); - Some( - self.parents - .iter() - .filter(|&&x| self.find_const(x) == parent) - .count(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_union_find() { - let mut set = DisjointSets::new(); - set.make_set("a").unwrap(); - set.make_set("b").unwrap(); - set.make_set("c").unwrap(); - set.make_set("d").unwrap(); - set.make_set("e").unwrap(); - assert!(set.same_set(&"a", &"a").unwrap()); - assert!(!set.same_set(&"a", &"b").unwrap()); - assert_eq!(set.set_size(&"a").unwrap(), 1); - assert_eq!(set.set_size(&"c").unwrap(), 1); - set.union(&"a", &"b").unwrap(); - assert_eq!(set.set_size(&"a").unwrap(), 2); - assert_eq!(set.set_size(&"c").unwrap(), 1); - assert!(set.same_set(&"a", &"b").unwrap()); - assert!(!set.same_set(&"a", &"c").unwrap()); - set.union(&"b", &"c").unwrap(); - assert!(set.same_set(&"a", &"c").unwrap()); - assert!(!set.same_set(&"a", &"d").unwrap()); - assert_eq!(set.set_size(&"a").unwrap(), 3); - assert_eq!(set.set_size(&"d").unwrap(), 1); - set.union(&"d", &"e").unwrap(); - assert!(set.same_set(&"d", &"e").unwrap()); - assert!(!set.same_set(&"a", &"d").unwrap()); - assert_eq!(set.set_size(&"a").unwrap(), 3); - assert_eq!(set.set_size(&"d").unwrap(), 2); - set.union(&"c", &"e").unwrap(); - assert!(set.same_set(&"a", &"e").unwrap()); - assert_eq!(set.set_size(&"d").unwrap(), 5); - } -} diff --git a/optd-mvp/Cargo.toml b/optd-mvp/Cargo.toml new file mode 100644 index 0000000..f4a3a62 --- /dev/null +++ b/optd-mvp/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "optd-mvp" +version = "0.1.0" +edition = "2021" +authors = ["Connor Tsui"] + +[dependencies] + +# `VARIANTS` constant made public in "1.1.1". +sea-orm = { version = "1.1.1", features = [ + "sqlx-sqlite", + "runtime-tokio-rustls", + "macros", + "debug-print", + "with-json", +] } +sea-orm-migration = "1.0" +serde = "1.0" +serde_json = "1.0.118" # Support `Hash` on `serde_json::Value` in "1.0.118". +tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } +trait-variant = "0.1.2" # Support `make(Send)` syntax in "0.1.2". +thiserror = "2.0" +fxhash = "0.2" + +# Pin more recent versions for `-Zminimal-versions`. +async-trait = "0.1.43" # Remove lifetime parameter from "0.1.42". +async-stream = "0.3.1" # Fix unsatisfied trait bound from "0.3.0". +strum = "0.26.0" # Fix `std::marker::Sized` from "0.25.0". + diff --git a/optd-mvp/DESIGN.md b/optd-mvp/DESIGN.md new file mode 100644 index 0000000..6d1863d --- /dev/null +++ b/optd-mvp/DESIGN.md @@ -0,0 +1,214 @@ +# Duplicate Elimination Memo Table + +_Connor Tsui, December 2024_ + +Note that most of the details are in `src/memo/persistent/implementation.rs`. + +For this document, we are assuming that the memo table is backed by a database / ORM. Both the +problems and the features detailed in this document are unique to this design, and likely do not +apply to an in-memory memo table. + +## Group Merging + +During logical exploration, there will be rules that create cycles between groups. The easy solution +for this is to immediately merge two groups together when the engine determines that adding an +expression would result in a duplicate expression from another group. + +However, if we want to support parallel exploration, this could be prone to high contention. By +definition, merging group 1 into group 2 would mean that _every expression_ that has a child of +group 1 with would need to be rewritten to point to group 2 instead. + +This is prohibitive in a parallel setting, as that would mean every single task that gets affected +would need to either wait for the rewrites to happen before resuming work, or potentially need to +abort their work because data has changed underneath them. + +So immediate / eager group merging is not a great idea for parallel exploration. However, if we +don't merge two groups that are equivalent, we are subject to doing duplicate work for every +duplicate expression in the memo table during physical optimization. + +Instead of merging groups together immediately, we can instead maintain an auxiliary data structure +that records the groups that _eventually_ need to get merged, and "lazily" merge those groups +together once every group has finished exploration. We will refer to merging groups as the act of +recording that the groups should eventually be merged together after exploration is finished. + +## Union-Find Group Sets + +We use the well-known Union-Find algorithm and corresponding data structure as the auxiliary data +structure that tracks the to-be-merged groups. + +Union-Find supports `Union` and `Find` operations, where `Union` merges sets and `Find` searches for +a "canonical" or "root" element that is shared between all elements in a given set. Note that we +will also support an iteration operation that iterates over all elements in a given set. We will +need this for [duplicate detection](#fingerprinting--group-merge), which is explained below. + +For more information about Union-Find, see these +[15-451 lecture notes](https://www.cs.cmu.edu/~15451-f24/lectures/lecture08-union-find.pdf). We will +use the exact same data structure, but add an additional `next` pointer for each node that embeds +a circular linked list for each set. + +Here, we make the elements the groups themselves (really the group IDs), which allows us to merge +group sets together and also determine a "root group" that all groups in a set can agree on. + +When every group in a group set has finished exploration, we can safely begin to merge them +together by moving all expressions from every group in the group set into a single large group. +Other than making sure that any reference to an old group in the group set points to this new large +group, exploration of all groups is done and physical optimization can start. + +Note that since we are now waiting for exploration of all groups to finish, this algorithm is much +closer to the Volcano framework than the Cascades' incremental search. However, since we eventually +will want to store trails / breadcrumbs of decisions made to skip work in the future, and since we +essentially have unlimited space due to the memo table being backed by a DBMS, this is not as much +of a problem. + +## Duplicate Detection + +Deciding that we will merge groups lazily does not solve all of our problems. We have to know _when_ +we want to merge these groups. + +A naive approach is to simply loop over every expression in the memo table and check if we are about +to insert a duplicate. This, of course, is bad for performance. + +We will use a fingerprinting / hashing method to detect when a duplicate expression might be +inserted into the memo table (returning an error instead of inserting), and we will use that to +trigger group merges. + +For every logical expression we insert into the memo table, we will create a fingerprint that +contains both the kind of expression / relation (Scan, Filter, Join) and a hash of all +information that makes that expression unique. For example: + +- The fingerprint of a Scan should probably contain a hash of the table name and the pushdown + predicate. +- The fingerprint of a Filter should probably contain a hash of its child group ID and predicate. +- The fingerprint of a Join should probably contain a hash of the left group ID and the right group + ID, as well as the join predicate. + +Note that the above descriptions are slightly inaccurate, and we'll explain why in a later +[section](#fingerprinting--group-merge). + +Also, if we have duplicate detection for logical expression, and we do not start physical +optimization until after full plan enumeration, then we do not actually need to do duplicate +detection of physical expressions, since they are derivative of the deduplicated logical +expressions. + +### Fingerprint Matching Algorithm + +When an expression is added to the memo table, it will first calculate the fingerprint of the +expression. The memo table will compare this fingerprint with every fingerprint in the memo table to +check if we have seen this expression before (in any group). While this is effectively a scan +through every expression, supporting the fingerprint table with an B+tree index will speed up this +operation dramatically (since these fingerprints can be sorted by expression / relation kind). + +If there are no identical fingerprints, then there is no duplicate expression, and we can safely +add the expression into the memo table. However, if there are matching fingerprints, we need to +further check for false positives due to hash collisions. + +We do full exact match equality checks with every expression that had a fingerprint match. If there +are no exact matches, then we can safely add the expression into the memo table. However, if we find +an exact match (note that there can be at most one exact match since we have an invariant that there +cannot be duplicate expressions), then we know that the expression we are trying to add already +exists in the memo table. + +### Fingerprinting + Group Merge + +There is a slight problem with the algorithm described above. It does not account for when a child +group has merged into another group. + +For example, let's say we have groups 1, 2, and 3. We insert an expression Join(1, 2) into the +memo table with its fingerprint calculated with groups 1 and 2. It is possible that we find out that +groups 2 and 3 need to merged. This means that Join(1, 2) and Join (1, 3) are actually identical +expressions, and the fingerprinting strategies for expressions described above do not handle this. + +We will solve this problem by adding allowing multiple fingerprints to reference the same logical +expression, and we will generate a new fingerprint for every expression that is affected by a group +merge / every expression who's parent group now has a new root group. + +In the above scenario, we will find every expression in the memo table that has group 2 as a child. +For each expression, we will generate another fingerprint with group 2 "rewritten" as group 3 in the +hash. Note that we _do not_ modify the original expression, we are simply adding another fingerprint +into the memo table. + +Finally, we need to handle when multiple groups in a group set are merged into another group set. +For example, if a left group set { 1, 2, 3, 4, 5 } with root 1 needs to be merged into a right group +set { 6, 7, 8, 9, 10 } with root 6, then we need to generate a new fingerprint for every expression +in groups 1, 2, 3, 4, and 5 with group 1 "rewritten" as group 6. + +More formally, we are maintaining this invariant: +**For every expression, there exists a fingerprint that maps back to the expression that uses the** +**root groups of their children to calculate the hash.** + +For example, if we have a group set { 1, 3, 5 } with root group 1 and group set { 2, 4, 6 } with +root group 2, the fingerprint of Join(5, 4) should really be a fingerprint of Join(1, 2). + +This invariant means that when we are checking if some expression already exists, we should use the +root groups of the child groups in our expression to calculate the fingerprint, and we can guarantee +that no fingerprint matches implies no duplicates. + +A further implication of this invariant means that new fingerprints need to be generated every time +we merge groups. If we have a left group set { 1, 3, 5 } with root group 1 and right group set +{ 2, 4, 6 } with root group 2, and we merge the first group set into the second, then every +expression that has a child group of 1, 3, or 5 now has a stale fingerprint that uses root group 1 +instead of root group 2. + +Thus, when we merge the left group into the right group, we need to do the following: + +1. Gather the group set, i.e. every single group that has root group 1 (iterate) +2. Retrieve every single expression that has a child group in the group set (via junction table) +3. Generate a new fingerprint for each expression and add it into the memo table + +The speed of steps 2 and 3 above are largely dependent on the backing DBMS. However, we can support +step 1 directly in the union find data structure by maintain a circular linked list for every set. +Each group now tracks both a `parent` pointer and a `next` pointer. When merging / unioning a set +into another set, we swap the `next` pointers of the two roots to maintain the circular linked list. +This allows us to do step 1 in linear time relative to the size of the group set. + +### Discovered Duplicates + +The above algorithm has one more problem: merging groups can cause the memo table to "discover" that +there are duplicate expressions in the memo table. + +Here is an example: let's say we have the following groups, each with one expression (note that the +example will work even with multiple expressions): + +1. `Scan(1)` +2. `Scan(2)` +3. `Filter(1)` +4. `Filter(2)` +5. `Filter(4)` +6. `Join(3, 4)` +7. `Join(3, 5)` +8. `Sort(6)` +9. `Sort(7)` + +Note how groups 5 is just a second filter on top of group 2. Suppose that we find out that +`(Filter(4) = Filter(Filter(2))) == Filter(2)`. In that case, we need to merge groups 4 and 5. The +problem here is that groups 6 and 7 are considered separate groups, but we have now discovered that +they are actually the same. The same is true for groups 8 and 9. In this scenario, the merging of +groups has "generated" a duplicate expression. + +However, this is not as big of a problem as it might seem. The issue we want to avoid is lots of +duplicate work or even an infinite loop of rule application. Observe that if we apply a rule to both +the expression in group 6 and group 7 that we will get the same exact expression. + +For example, if we apply join commutativity to the expression in group 6 (`Join(3, 4)`), we would +add `Join(4, 3)` into group 6. When we apply join commutativity to the expression in group 7 +(`Join(3, 5)`), we would get back `Join(5, 3)`. However, the memo table will detect this as a +duplicate because it will use the root group of 4 and 5 to generate the fingerprint and see that +`Join(4, 3)` already exists. Again, similar logic applies for groups 8 and 9. + +At a high level, almost all of our operations are lazy. Work does not need to be done unless it is +absolutely necessary for correctness. By allowing some amount of duplicates, we get some nice +properties with respect to parallelizing memo table access. + +## Efficiency and Parallelism + +Fingerprinting by itself is very efficient, as creating a fingerprint and looking up a fingerprint +can be made quite efficient with indexes. The real concern here is that merging two groups is very, +very expensive. Depending on the workload, it is both possible that the amortized cost is low or +that group merging takes a majority of the work. + +However, we must remember that we want to parallelize access to the memo table. The above algorithms +are notably **read and append only**. There is never a point where we need to update an expression +to maintain invariants. This is important, as it means that we can add and lookup expression and +groups _without having to take any locks_. If we enforce a serializable isolation level, then every +method on the memo table can be done in parallel with relatively low contention due to there being +zero write-write conflicts. diff --git a/optd-persistent/README.md b/optd-mvp/entities.md similarity index 81% rename from optd-persistent/README.md rename to optd-mvp/entities.md index 4a44127..fc13a39 100644 --- a/optd-persistent/README.md +++ b/optd-mvp/entities.md @@ -8,10 +8,10 @@ This assumes that you already have the `sqlite3` binary installed. First, make s $ cargo install sea-orm-cli ``` -Make sure your working directory is in the crate root: +Make sure your working directory is in the crate root (not workspace): ```sh -$ cd optd-persistent +$ cd optd-mvp ``` If you have not generate the `sqlite.db` file yet, you will need to run this command which will generate the `sqlite.db` file and run all of the migrations: @@ -22,14 +22,6 @@ $ cargo run --bin migrate Finally, run this command to generate / overwrite the `entities` module in the `src` directory. -``` -$ sea-orm-cli generate entity -u sqlite:./sqlite.db -o src/entities -``` - -# Demo - -To run the demo, run the root binary crate: - ```sh -$ cargo run --bin optd-persistent +$ sea-orm-cli generate entity -u sqlite:./sqlite.db -o src/entities ``` diff --git a/optd-persistent/src/bin/migrate.rs b/optd-mvp/src/bin/migrate.rs similarity index 62% rename from optd-persistent/src/bin/migrate.rs rename to optd-mvp/src/bin/migrate.rs index d6a36a6..0634f23 100644 --- a/optd-persistent/src/bin/migrate.rs +++ b/optd-mvp/src/bin/migrate.rs @@ -1,4 +1,7 @@ -use optd_persistent::{migrate, DATABASE_FILENAME, DATABASE_URL}; +//! A simple script that generates the database file needed for `sea-orm-cli` to extract the schemas +//! from and generate the `entities` module. + +use optd_mvp::{migrate, DATABASE_FILENAME, DATABASE_URL}; use sea_orm::*; use sea_orm_migration::prelude::*; diff --git a/optd-persistent/src/entities/logical_property.rs b/optd-mvp/src/entities/fingerprint.rs similarity index 53% rename from optd-persistent/src/entities/logical_property.rs rename to optd-mvp/src/entities/fingerprint.rs index 755575c..2ab6a7f 100644 --- a/optd-persistent/src/entities/logical_property.rs +++ b/optd-mvp/src/entities/fingerprint.rs @@ -3,30 +3,30 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "logical_property")] +#[sea_orm(table_name = "fingerprint")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, - pub group_id: i32, - pub variant_tag: i16, - pub data: Json, + pub logical_expression_id: i32, + pub kind: i16, + pub hash: i64, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( - belongs_to = "super::cascades_group::Entity", - from = "Column::GroupId", - to = "super::cascades_group::Column::Id", + belongs_to = "super::logical_expression::Entity", + from = "Column::LogicalExpressionId", + to = "super::logical_expression::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] - CascadesGroup, + LogicalExpression, } -impl Related for Entity { +impl Related for Entity { fn to() -> RelationDef { - Relation::CascadesGroup.def() + Relation::LogicalExpression.def() } } diff --git a/optd-persistent/src/entities/cascades_group.rs b/optd-mvp/src/entities/group.rs similarity index 65% rename from optd-persistent/src/entities/cascades_group.rs rename to optd-mvp/src/entities/group.rs index 9ea79d1..333ab05 100644 --- a/optd-persistent/src/entities/cascades_group.rs +++ b/optd-mvp/src/entities/group.rs @@ -3,30 +3,44 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "cascades_group")] +#[sea_orm(table_name = "group")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, - pub latest_winner: Option, - pub in_progress: bool, - pub is_optimized: bool, + pub status: i8, + pub winner: Option, + pub cost: Option, + pub parent_id: Option, + pub next_id: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { - #[sea_orm(has_many = "super::group_winner::Entity")] - GroupWinner, + #[sea_orm( + belongs_to = "Entity", + from = "Column::NextId", + to = "Column::Id", + on_update = "Cascade", + on_delete = "SetNull" + )] + SelfRef2, + #[sea_orm( + belongs_to = "Entity", + from = "Column::ParentId", + to = "Column::Id", + on_update = "Cascade", + on_delete = "SetNull" + )] + SelfRef1, #[sea_orm(has_many = "super::logical_children::Entity")] LogicalChildren, #[sea_orm(has_many = "super::logical_expression::Entity")] LogicalExpression, - #[sea_orm(has_many = "super::logical_property::Entity")] - LogicalProperty, #[sea_orm(has_many = "super::physical_children::Entity")] PhysicalChildren, #[sea_orm( belongs_to = "super::physical_expression::Entity", - from = "Column::LatestWinner", + from = "Column::Winner", to = "super::physical_expression::Column::Id", on_update = "Cascade", on_delete = "SetNull" @@ -34,24 +48,12 @@ pub enum Relation { PhysicalExpression, } -impl Related for Entity { - fn to() -> RelationDef { - Relation::GroupWinner.def() - } -} - impl Related for Entity { fn to() -> RelationDef { Relation::LogicalChildren.def() } } -impl Related for Entity { - fn to() -> RelationDef { - Relation::LogicalProperty.def() - } -} - impl Related for Entity { fn to() -> RelationDef { Relation::PhysicalChildren.def() @@ -63,7 +65,7 @@ impl Related for Entity { super::logical_children::Relation::LogicalExpression.def() } fn via() -> Option { - Some(super::logical_children::Relation::CascadesGroup.def().rev()) + Some(super::logical_children::Relation::Group.def().rev()) } } @@ -72,11 +74,7 @@ impl Related for Entity { super::physical_children::Relation::PhysicalExpression.def() } fn via() -> Option { - Some( - super::physical_children::Relation::CascadesGroup - .def() - .rev(), - ) + Some(super::physical_children::Relation::Group.def().rev()) } } diff --git a/optd-persistent/src/entities/logical_children.rs b/optd-mvp/src/entities/logical_children.rs similarity index 80% rename from optd-persistent/src/entities/logical_children.rs rename to optd-mvp/src/entities/logical_children.rs index 120641f..a0ac39c 100644 --- a/optd-persistent/src/entities/logical_children.rs +++ b/optd-mvp/src/entities/logical_children.rs @@ -14,16 +14,16 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( - belongs_to = "super::cascades_group::Entity", + belongs_to = "super::group::Entity", from = "Column::GroupId", - to = "super::cascades_group::Column::Id", + to = "super::group::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] - CascadesGroup, + Group, #[sea_orm( belongs_to = "super::logical_expression::Entity", - from = "Column::GroupId", + from = "Column::LogicalExpressionId", to = "super::logical_expression::Column::Id", on_update = "Cascade", on_delete = "Cascade" @@ -31,9 +31,9 @@ pub enum Relation { LogicalExpression, } -impl Related for Entity { +impl Related for Entity { fn to() -> RelationDef { - Relation::CascadesGroup.def() + Relation::Group.def() } } diff --git a/optd-persistent/src/entities/logical_expression.rs b/optd-mvp/src/entities/logical_expression.rs similarity index 70% rename from optd-persistent/src/entities/logical_expression.rs rename to optd-mvp/src/entities/logical_expression.rs index 6beff04..82d938f 100644 --- a/optd-persistent/src/entities/logical_expression.rs +++ b/optd-mvp/src/entities/logical_expression.rs @@ -8,34 +8,41 @@ pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub group_id: i32, - pub fingerprint: i64, - pub variant_tag: i16, + pub kind: i16, pub data: Json, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { + #[sea_orm(has_many = "super::fingerprint::Entity")] + Fingerprint, #[sea_orm( - belongs_to = "super::cascades_group::Entity", + belongs_to = "super::group::Entity", from = "Column::GroupId", - to = "super::cascades_group::Column::Id", + to = "super::group::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] - CascadesGroup, + Group, #[sea_orm(has_many = "super::logical_children::Entity")] LogicalChildren, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::Fingerprint.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::LogicalChildren.def() } } -impl Related for Entity { +impl Related for Entity { fn to() -> RelationDef { - super::logical_children::Relation::CascadesGroup.def() + super::logical_children::Relation::Group.def() } fn via() -> Option { Some( diff --git a/optd-mvp/src/entities/mod.rs b/optd-mvp/src/entities/mod.rs new file mode 100644 index 0000000..3abd379 --- /dev/null +++ b/optd-mvp/src/entities/mod.rs @@ -0,0 +1,10 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +pub mod prelude; + +pub mod fingerprint; +pub mod group; +pub mod logical_children; +pub mod logical_expression; +pub mod physical_children; +pub mod physical_expression; diff --git a/optd-persistent/src/entities/physical_children.rs b/optd-mvp/src/entities/physical_children.rs similarity index 83% rename from optd-persistent/src/entities/physical_children.rs rename to optd-mvp/src/entities/physical_children.rs index d8f9db0..e58e9ca 100644 --- a/optd-persistent/src/entities/physical_children.rs +++ b/optd-mvp/src/entities/physical_children.rs @@ -14,13 +14,13 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( - belongs_to = "super::cascades_group::Entity", + belongs_to = "super::group::Entity", from = "Column::GroupId", - to = "super::cascades_group::Column::Id", + to = "super::group::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] - CascadesGroup, + Group, #[sea_orm( belongs_to = "super::physical_expression::Entity", from = "Column::PhysicalExpressionId", @@ -31,9 +31,9 @@ pub enum Relation { PhysicalExpression, } -impl Related for Entity { +impl Related for Entity { fn to() -> RelationDef { - Relation::CascadesGroup.def() + Relation::Group.def() } } diff --git a/optd-mvp/src/entities/physical_expression.rs b/optd-mvp/src/entities/physical_expression.rs new file mode 100644 index 0000000..4fba71e --- /dev/null +++ b/optd-mvp/src/entities/physical_expression.rs @@ -0,0 +1,48 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "physical_expression")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub group_id: i32, + pub kind: i16, + pub data: Json, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::group::Entity", + from = "Column::GroupId", + to = "super::group::Column::Id", + on_update = "Cascade", + on_delete = "Cascade" + )] + Group, + #[sea_orm(has_many = "super::physical_children::Entity")] + PhysicalChildren, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::PhysicalChildren.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::physical_children::Relation::Group.def() + } + fn via() -> Option { + Some( + super::physical_children::Relation::PhysicalExpression + .def() + .rev(), + ) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-mvp/src/entities/prelude.rs b/optd-mvp/src/entities/prelude.rs new file mode 100644 index 0000000..8e8deaa --- /dev/null +++ b/optd-mvp/src/entities/prelude.rs @@ -0,0 +1,10 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +#![allow(unused_imports)] + +pub use super::fingerprint::Entity as Fingerprint; +pub use super::group::Entity as Group; +pub use super::logical_children::Entity as LogicalChildren; +pub use super::logical_expression::Entity as LogicalExpression; +pub use super::physical_children::Entity as PhysicalChildren; +pub use super::physical_expression::Entity as PhysicalExpression; diff --git a/optd-mvp/src/expression/logical_expression.rs b/optd-mvp/src/expression/logical_expression.rs new file mode 100644 index 0000000..4ddf46e --- /dev/null +++ b/optd-mvp/src/expression/logical_expression.rs @@ -0,0 +1,212 @@ +//! Definition of logical expressions / relations in our query optimization framework. +//! +//! FIXME: All fields are placeholders. +//! +//! TODO Figure out if each relation should be in a different submodule. +//! TODO This entire file is a WIP. + +use crate::{entities::*, memo::GroupId}; +use fxhash::hash; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug)] +pub enum LogicalExpression { + Scan(Scan), + Filter(Filter), + Join(Join), +} + +impl LogicalExpression { + pub fn kind(&self) -> i16 { + match self { + LogicalExpression::Scan(_) => 0, + LogicalExpression::Filter(_) => 1, + LogicalExpression::Join(_) => 2, + } + } + + /// Calculates the fingerprint of a given expression, but replaces all of the children group IDs + /// with a new group ID if it is listed in the input `rewrites` list. + /// + /// TODO Allow each expression to implement a trait that does this. + pub fn fingerprint_with_rewrite(&self, rewrites: &[(GroupId, GroupId)]) -> i64 { + // Closure that rewrites a group ID if needed. + let rewrite = |x: GroupId| { + if rewrites.is_empty() { + return x; + } + + if let Some(i) = rewrites.iter().position(|(curr, _new)| &x == curr) { + assert_eq!(rewrites[i].0, x); + rewrites[i].1 + } else { + x + } + }; + + let kind = self.kind() as u16 as usize; + let hash = match self { + LogicalExpression::Scan(scan) => hash(scan.table.as_str()), + LogicalExpression::Filter(filter) => { + hash(&rewrite(filter.child).0) ^ hash(filter.expression.as_str()) + } + LogicalExpression::Join(join) => { + // Make sure that there is a difference between `Join(A, B)` and `Join(B, A)`. + hash(&(rewrite(join.left).0 + 1)) + ^ hash(&(rewrite(join.right).0 + 2)) + ^ hash(join.expression.as_str()) + } + }; + + // Mask out the bottom 16 bits of `hash` and replace them with `kind`. + ((hash & !0xFFFF) | kind) as i64 + } + + /// Checks equality between two expressions, with both expression rewriting their child group + /// IDs according to the input `rewrites` list. + pub fn eq_with_rewrite(&self, other: &Self, rewrites: &[(GroupId, GroupId)]) -> bool { + // Closure that rewrites a group ID if needed. + let rewrite = |x: GroupId| { + if rewrites.is_empty() { + return x; + } + + if let Some(i) = rewrites.iter().position(|(curr, _new)| &x == curr) { + assert_eq!(rewrites[i].0, x); + rewrites[i].1 + } else { + x + } + }; + + match (self, other) { + (LogicalExpression::Scan(scan_left), LogicalExpression::Scan(scan_right)) => { + scan_left.table == scan_right.table + } + (LogicalExpression::Filter(filter_left), LogicalExpression::Filter(filter_right)) => { + rewrite(filter_left.child) == rewrite(filter_right.child) + && filter_left.expression == filter_right.expression + } + (LogicalExpression::Join(join_left), LogicalExpression::Join(join_right)) => { + rewrite(join_left.left) == rewrite(join_right.left) + && rewrite(join_left.right) == rewrite(join_right.right) + && join_left.expression == join_right.expression + } + _ => false, + } + } + + pub fn children(&self) -> Vec { + match self { + LogicalExpression::Scan(_) => vec![], + LogicalExpression::Filter(filter) => vec![filter.child], + LogicalExpression::Join(join) => vec![join.left, join.right], + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Scan { + table: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Filter { + child: GroupId, + expression: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Join { + left: GroupId, + right: GroupId, + expression: String, +} + +/// TODO Use a macro. +impl From for LogicalExpression { + fn from(value: logical_expression::Model) -> Self { + match value.kind { + 0 => Self::Scan( + serde_json::from_value(value.data) + .expect("unable to deserialize data into a logical `Scan`"), + ), + 1 => Self::Filter( + serde_json::from_value(value.data) + .expect("Unable to deserialize data into a logical `Filter`"), + ), + 2 => Self::Join( + serde_json::from_value(value.data) + .expect("Unable to deserialize data into a logical `Join`"), + ), + _ => panic!(), + } + } +} + +/// TODO Use a macro. +impl From for logical_expression::Model { + fn from(value: LogicalExpression) -> logical_expression::Model { + fn create_logical_expression( + kind: i16, + data: serde_json::Value, + ) -> logical_expression::Model { + logical_expression::Model { + id: -1, + group_id: -1, + kind, + data, + } + } + + let kind = value.kind(); + match value { + LogicalExpression::Scan(scan) => create_logical_expression( + kind, + serde_json::to_value(scan).expect("unable to serialize logical `Scan`"), + ), + LogicalExpression::Filter(filter) => create_logical_expression( + kind, + serde_json::to_value(filter).expect("unable to serialize logical `Filter`"), + ), + LogicalExpression::Join(join) => create_logical_expression( + kind, + serde_json::to_value(join).expect("unable to serialize logical `Join`"), + ), + } + } +} + +#[cfg(test)] +pub use build::*; + +#[cfg(test)] +mod build { + use super::*; + use crate::expression::LogicalExpression; + + pub fn scan(table_schema: String) -> LogicalExpression { + LogicalExpression::Scan(Scan { + table: table_schema, + }) + } + + pub fn filter(child_group: GroupId, expression: String) -> LogicalExpression { + LogicalExpression::Filter(Filter { + child: child_group, + expression, + }) + } + + pub fn join( + left_group: GroupId, + right_group: GroupId, + expression: String, + ) -> LogicalExpression { + LogicalExpression::Join(Join { + left: left_group, + right: right_group, + expression, + }) + } +} diff --git a/optd-mvp/src/expression/mod.rs b/optd-mvp/src/expression/mod.rs new file mode 100644 index 0000000..3b6d7cf --- /dev/null +++ b/optd-mvp/src/expression/mod.rs @@ -0,0 +1,62 @@ +//! In-memory representation of logical and physical expression / operators / relations. +//! +//! TODO more docs. + +mod logical_expression; +pub use logical_expression::*; + +mod physical_expression; +pub use physical_expression::*; + +/// The representation of an expression. +/// +/// TODO more docs. +#[derive(Clone, Debug)] +pub enum Expression { + Logical(LogicalExpression), + Physical(PhysicalExpression), +} + +/// Converts the database / JSON representation of a logical expression into an in-memory one. +impl From for Expression { + fn from(value: crate::entities::logical_expression::Model) -> Self { + Self::Logical(value.into()) + } +} + +/// Converts the in-memory representation of a logical expression into the database / JSON version. +/// +/// # Panics +/// +/// This will panic if the [`Expression`] is [`Expression::Physical`]. +impl From for crate::entities::logical_expression::Model { + fn from(value: Expression) -> Self { + let Expression::Logical(expr) = value else { + panic!("Attempted to convert an in-memory physical expression into a logical database / JSON expression"); + }; + + expr.into() + } +} + +/// Converts the database / JSON representation of a physical expression into an in-memory one. +impl From for Expression { + fn from(value: crate::entities::physical_expression::Model) -> Self { + Self::Physical(value.into()) + } +} + +/// Converts the in-memory representation of a physical expression into the database / JSON version. +/// +/// # Panics +/// +/// This will panic if the [`Expression`] is [`Expression::Physical`]. +impl From for crate::entities::physical_expression::Model { + fn from(value: Expression) -> Self { + let Expression::Physical(expr) = value else { + panic!("Attempted to convert an in-memory logical expression into a physical database / JSON expression"); + }; + + expr.into() + } +} diff --git a/optd-mvp/src/expression/physical_expression.rs b/optd-mvp/src/expression/physical_expression.rs new file mode 100644 index 0000000..9c451b7 --- /dev/null +++ b/optd-mvp/src/expression/physical_expression.rs @@ -0,0 +1,100 @@ +//! Definition of physical expressions / operators in our query optimization framework. +//! +//! FIXME: All fields are placeholders. +//! +//! TODO Figure out if each operator should be in a different submodule. +//! TODO This entire file is a WIP. + +use crate::{entities::*, memo::GroupId}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum PhysicalExpression { + TableScan(TableScan), + Filter(PhysicalFilter), + HashJoin(HashJoin), +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct TableScan { + table_schema: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct PhysicalFilter { + child: GroupId, + expression: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct HashJoin { + left: GroupId, + right: GroupId, + expression: String, +} + +/// TODO Use a macro. +impl From for PhysicalExpression { + fn from(value: physical_expression::Model) -> Self { + match value.kind { + 0 => Self::TableScan( + serde_json::from_value(value.data) + .expect("unable to deserialize data into a physical `TableScan`"), + ), + 1 => Self::Filter( + serde_json::from_value(value.data) + .expect("Unable to deserialize data into a physical `Filter`"), + ), + 2 => Self::HashJoin( + serde_json::from_value(value.data) + .expect("Unable to deserialize data into a physical `HashJoin`"), + ), + _ => panic!(), + } + } +} + +/// TODO Use a macro. +impl From for physical_expression::Model { + fn from(value: PhysicalExpression) -> physical_expression::Model { + fn create_physical_expression( + kind: i16, + data: serde_json::Value, + ) -> physical_expression::Model { + physical_expression::Model { + id: -1, + group_id: -1, + kind, + data, + } + } + + match value { + PhysicalExpression::TableScan(scan) => create_physical_expression( + 0, + serde_json::to_value(scan).expect("unable to serialize physical `TableScan`"), + ), + PhysicalExpression::Filter(filter) => create_physical_expression( + 1, + serde_json::to_value(filter).expect("unable to serialize physical `Filter`"), + ), + PhysicalExpression::HashJoin(join) => create_physical_expression( + 2, + serde_json::to_value(join).expect("unable to serialize physical `HashJoin`"), + ), + } + } +} + +#[cfg(test)] +pub use build::*; + +#[cfg(test)] +mod build { + use super::*; + use crate::expression::PhysicalExpression; + + pub fn table_scan(table_schema: String) -> PhysicalExpression { + PhysicalExpression::TableScan(TableScan { table_schema }) + } +} diff --git a/optd-mvp/src/lib.rs b/optd-mvp/src/lib.rs new file mode 100644 index 0000000..48a4c78 --- /dev/null +++ b/optd-mvp/src/lib.rs @@ -0,0 +1,37 @@ +use sea_orm::*; +use sea_orm_migration::prelude::*; +use thiserror::Error; + +mod migrator; +use migrator::Migrator; + +mod entities; + +mod memo; +use memo::MemoError; + +mod expression; + +/// The filename of the SQLite database for migration. +pub const DATABASE_FILENAME: &str = "sqlite.db"; +/// The URL of the SQLite database for migration. +pub const DATABASE_URL: &str = "sqlite:./sqlite.db?mode=rwc"; + +/// An error type wrapping all the different kinds of error the optimizer might raise. +#[derive(Error, Debug)] +pub enum OptimizerError { + #[error("SeaORM error")] + Database(#[from] sea_orm::error::DbErr), + #[error("Memo table logical error")] + Memo(#[from] MemoError), + #[error("unknown error")] + Unknown, +} + +/// Shorthand for a [`Result`] with an error type [`OptimizerError`]. +pub type OptimizerResult = Result; + +/// Applies all migrations. +pub async fn migrate(db: &DatabaseConnection) -> Result<(), DbErr> { + Migrator::refresh(db).await +} diff --git a/optd-mvp/src/main.rs b/optd-mvp/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/optd-mvp/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/optd-mvp/src/memo/mod.rs b/optd-mvp/src/memo/mod.rs new file mode 100644 index 0000000..5147fe1 --- /dev/null +++ b/optd-mvp/src/memo/mod.rs @@ -0,0 +1,54 @@ +//! This module contains items related to the memo table. +//! +//! TODO more docs. + +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +/// A new type of an integer identifying a unique group. +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +#[serde(transparent)] +pub struct GroupId(pub(crate) i32); + +/// A new type of an integer identifying a root group / canonical group ID of a group set. +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +#[serde(transparent)] +pub struct RootGroupId(pub(crate) i32); + +/// A [`RootGroupId`] is always [`GroupId`], but not vice versa. +impl From for GroupId { + fn from(value: RootGroupId) -> Self { + Self(value.0) + } +} + +/// A new type of an integer identifying a unique logical expression. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LogicalExpressionId(i32); + +/// A new type of an integer identifying a unique physical expression. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PhysicalExpressionId(i32); + +/// A status enum representing the different states a group can be during query optimization. +#[repr(u8)] +pub enum GroupStatus { + InProgress = 0, + Explored = 1, + Optimized = 2, +} + +/// The different kinds of errors that might occur while running operations on a memo table. +#[derive(Error, Debug)] +pub enum MemoError { + #[error("unknown group ID {0:?}")] + UnknownGroup(GroupId), + #[error("unknown logical expression ID {0:?}")] + UnknownLogicalExpression(LogicalExpressionId), + #[error("unknown physical expression ID {0:?}")] + UnknownPhysicalExpression(PhysicalExpressionId), + #[error("invalid expression encountered")] + InvalidExpression, +} + +mod persistent; diff --git a/optd-mvp/src/memo/persistent/implementation.rs b/optd-mvp/src/memo/persistent/implementation.rs new file mode 100644 index 0000000..293bd50 --- /dev/null +++ b/optd-mvp/src/memo/persistent/implementation.rs @@ -0,0 +1,636 @@ +//! This module contains the implementation of [`PersistentMemo`]. +//! +//! TODO For parallelism, almost all of these methods need to be under transactions. +//! TODO Write more docs. +//! TODO Remove dead code. + +#![allow(dead_code)] + +use super::PersistentMemo; +use crate::{ + entities::*, + expression::{LogicalExpression, PhysicalExpression}, + memo::{ + GroupId, GroupStatus, LogicalExpressionId, MemoError, PhysicalExpressionId, RootGroupId, + }, + OptimizerResult, DATABASE_URL, +}; +use sea_orm::{ + entity::prelude::*, + entity::{IntoActiveModel, NotSet, Set}, + Database, +}; +use std::collections::HashSet; + +impl PersistentMemo { + /// Creates a new `PersistentMemo` struct by connecting to a database defined at + /// [`DATABASE_URL`]. + pub async fn new() -> Self { + Self { + db: Database::connect(DATABASE_URL).await.unwrap(), + } + } + + /// Deletes all objects in the backing database. + /// + /// Since there is no asynchronous drop yet in Rust, in order to drop all objects in the + /// database, the user must call this manually. + pub async fn cleanup(&self) { + macro_rules! delete_all { + ($($module: ident),+ $(,)?) => { + $( + $module::Entity::delete_many() + .exec(&self.db) + .await + .unwrap(); + )+ + }; + } + + delete_all! { + group, + fingerprint, + logical_expression, + logical_children, + physical_expression, + physical_children + }; + } + + /// Retrieves a [`group::Model`] given its ID. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// FIXME: use an in-memory representation of a group instead. + pub async fn get_group(&self, group_id: GroupId) -> OptimizerResult { + Ok(group::Entity::find_by_id(group_id.0) + .one(&self.db) + .await? + .ok_or(MemoError::UnknownGroup(group_id))?) + } + + /// Retrieves the root / canonical group ID of the given group ID. + /// + /// The groups form a union find / disjoint set parent pointer forest, where group merging + /// causes two trees to merge. + /// + /// This function uses the path compression optimization, which amortizes the cost to a single + /// lookup (theoretically in constant time, but we must be wary of the I/O roundtrip). + pub async fn get_root_group(&self, group_id: GroupId) -> OptimizerResult { + let curr_group = self.get_group(group_id).await?; + + // If we have no parent, then we are at the root. + let Some(parent_id) = curr_group.parent_id else { + return Ok(RootGroupId(curr_group.id)); + }; + + // Recursively find the root group ID. + let root_id = Box::pin(self.get_root_group(GroupId(parent_id))).await?; + + // Path Compression Optimization: + // For every group along the path that we walked, set their parent id pointer to the root. + // This allows for an amortized O(1) cost for `get_root_group`. + let mut active_group = curr_group.into_active_model(); + + // Update the group to point to the new parent. + active_group.parent_id = Set(Some(root_id.0)); + active_group.update(&self.db).await?; + + Ok(RootGroupId(root_id.0)) + } + + /// Retrieves every group ID of groups that share the same root group with the input group. + /// + /// If a group does not exist in the cycle, returns a [`MemoError::UnknownGroup`] error. + /// + /// The group records form a union-find data structure that also maintains a circular linked + /// list in every set that allows us to iterate over all elements in a set in linear time. + pub async fn get_group_set(&self, group_id: GroupId) -> OptimizerResult> { + // Iterate over the circular linked list until we reach ourselves again. + let base_group = self.get_group(group_id).await?; + + // The only case when `next_id` is set to `None` is if the current group is a root, which + // means that this group is the only group in the set. + if base_group.next_id.is_none() { + assert!(base_group.parent_id.is_none()); + return Ok(vec![group_id]); + } + + // Iterate over the circular linked list until we see ourselves again, collecting nodes + // along the way. + let mut set = vec![group_id]; + let mut next_id = base_group + .next_id + .expect("next pointer cannot be null if it is in a cycle"); + loop { + let curr_group = self.get_group(GroupId(next_id)).await?; + + if curr_group.id == group_id.0 { + break; + } + + set.push(GroupId(curr_group.id)); + next_id = curr_group + .next_id + .expect("next pointer cannot be null if it is in a cycle"); + } + + Ok(set) + } + + /// Retrieves a [`physical_expression::Model`] given a [`PhysicalExpressionId`]. + /// + /// If the physical expression does not exist, returns a + /// [`MemoError::UnknownPhysicalExpression`] error. + pub async fn get_physical_expression( + &self, + physical_expression_id: PhysicalExpressionId, + ) -> OptimizerResult<(GroupId, PhysicalExpression)> { + // Lookup the entity in the database via the unique expression ID. + let model = physical_expression::Entity::find_by_id(physical_expression_id.0) + .one(&self.db) + .await? + .ok_or(MemoError::UnknownPhysicalExpression(physical_expression_id))?; + + let group_id = GroupId(model.group_id); + let expr = model.into(); + + Ok((group_id, expr)) + } + + /// Retrieves a [`logical_expression::Model`] given its [`LogicalExpressionId`]. + /// + /// If the logical expression does not exist, returns a [`MemoError::UnknownLogicalExpression`] + /// error. + pub async fn get_logical_expression( + &self, + logical_expression_id: LogicalExpressionId, + ) -> OptimizerResult<(GroupId, LogicalExpression)> { + // Lookup the entity in the database via the unique expression ID. + let model = logical_expression::Entity::find_by_id(logical_expression_id.0) + .one(&self.db) + .await? + .ok_or(MemoError::UnknownLogicalExpression(logical_expression_id))?; + + let group_id = GroupId(model.group_id); + let expr = model.into(); + + Ok((group_id, expr)) + } + + /// Retrieves all of the logical expression "children" IDs of a group. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// FIXME: `find_related` does not work for some reason, have to use manual `filter`. + pub async fn get_logical_children( + &self, + group_id: GroupId, + ) -> OptimizerResult> { + // Search for expressions that have the given parent group ID. + let children = logical_expression::Entity::find() + .filter(logical_expression::Column::GroupId.eq(group_id.0)) + .all(&self.db) + .await? + .into_iter() + .map(|m| LogicalExpressionId(m.id)) + .collect(); + + Ok(children) + } + + /// Retrieves all of the physical expression "children" IDs of a group. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + pub async fn get_physical_children( + &self, + group_id: GroupId, + ) -> OptimizerResult> { + // Search for expressions that have the given parent group ID. + let children = physical_expression::Entity::find() + .filter(physical_expression::Column::GroupId.eq(group_id.0)) + .all(&self.db) + .await? + .into_iter() + .map(|m| PhysicalExpressionId(m.id)) + .collect(); + + Ok(children) + } + + /// Updates / replaces a group's status. Returns the previous group status. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + pub async fn update_group_status( + &self, + group_id: GroupId, + status: GroupStatus, + ) -> OptimizerResult { + // First retrieve the group record. + let mut group = self.get_group(group_id).await?.into_active_model(); + + // Update the group's status. + let old_status = group.status; + group.status = Set(status as u8 as i8); + group.update(&self.db).await?; + + let old_status = match old_status.unwrap() { + 0 => GroupStatus::InProgress, + 1 => GroupStatus::Explored, + 2 => GroupStatus::Optimized, + _ => panic!("encountered an invalid group status"), + }; + + Ok(old_status) + } + + /// Updates / replaces a group set's best physical plan (winner). Optionally returns the + /// previous winner's physical expression ID. + /// + /// Note that we want to update the root group and not a child group that has been merged into + /// a different group. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// FIXME: In the future, this should first check that we aren't overwriting a winner that was + /// updated from another thread by comparing against the cost of the plan. + pub async fn update_group_winner( + &self, + root_group_id: RootGroupId, + physical_expression_id: PhysicalExpressionId, + ) -> OptimizerResult> { + // First retrieve the group record. + let mut group = self.get_group(root_group_id.into()).await?.into_active_model(); + + // Update the group to point to the new winner. + let old_id = group.winner; + group.winner = Set(Some(physical_expression_id.0)); + group.update(&self.db).await?; + + // Note that the `unwrap` here is unwrapping the `ActiveValue`, not the `Option`. + let old_id = old_id.unwrap().map(PhysicalExpressionId); + Ok(old_id) + } + + /// Adds a logical expression to an existing group via its ID. + /// + /// The caller is required to pass in a slice of [`GroupId`] that represent the child groups of + /// the input expression. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// If the memo table detects that the input logical expression is a duplicate expression, this + /// function will **not** insert the expression into the memo table. Instead, it will return an + /// `Ok(Err(expression_id))`, which is a unique identifier of the expression that the input is a + /// duplicate of. The caller can use this ID to retrieve the group the original belongs to. + /// + /// If the memo table detects that the input is unique, it will insert the expression into the + /// input group and return an `Ok(Ok(expression_id))`. + pub async fn add_logical_expression_to_group( + &self, + group_id: GroupId, + logical_expression: LogicalExpression, + children: &[GroupId], + ) -> OptimizerResult> { + // Check if the expression already exists anywhere in the memo table. + if let Some(existing_id) = self + .is_duplicate_logical_expression(&logical_expression, children) + .await? + { + return Ok(Err(existing_id)); + } + + // Check if the group actually exists. + let _ = self.get_group(group_id).await?; + + // Insert the expression. + let model: logical_expression::Model = logical_expression.into(); + let mut active_model = model.into_active_model(); + active_model.group_id = Set(group_id.0); + active_model.id = NotSet; + let new_model = active_model.insert(&self.db).await?; + + let expr_id = new_model.id; + + // Insert the child groups of the expression into the junction / children table. + logical_children::Entity::insert_many(children.iter().copied().map(|child_id| { + logical_children::ActiveModel { + logical_expression_id: Set(expr_id), + group_id: Set(child_id.0), + } + })) + .on_empty_do_nothing() + .exec(&self.db) + .await?; + + // Finally, insert the fingerprint of the logical expression as well. + let new_expr: LogicalExpression = new_model.into(); + let kind = new_expr.kind(); + + // In order to calculate a correct fingerprint, we will want to use the IDs of the root + // groups of the children instead of the child ID themselves. + let mut rewrites = vec![]; + for &child_id in children { + let root_id = self.get_root_group(child_id).await?; + rewrites.push((child_id, root_id.into())); + } + let hash = new_expr.fingerprint_with_rewrite(&rewrites); + + let fingerprint = fingerprint::ActiveModel { + id: NotSet, + logical_expression_id: Set(expr_id), + kind: Set(kind), + hash: Set(hash), + }; + fingerprint::Entity::insert(fingerprint) + .exec(&self.db) + .await?; + + Ok(Ok(LogicalExpressionId(expr_id))) + } + + /// Adds a physical expression to an existing group via its ID. + /// + /// The caller is required to pass in a slice of [`GroupId`] that represent the child groups of + /// the input expression. + /// + /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// On successful insertion, returns the ID of the physical expression. + pub async fn add_physical_expression_to_group( + &self, + group_id: GroupId, + physical_expression: PhysicalExpression, + children: &[GroupId], + ) -> OptimizerResult { + // Check if the group actually exists. + let _ = self.get_group(group_id).await?; + + // Insert the expression. + let model: physical_expression::Model = physical_expression.into(); + let mut active_model = model.into_active_model(); + active_model.group_id = Set(group_id.0); + active_model.id = NotSet; + let new_model = active_model.insert(&self.db).await?; + + // Insert the child groups of the expression into the junction / children table. + physical_children::Entity::insert_many(children.iter().copied().map(|child_id| { + physical_children::ActiveModel { + physical_expression_id: Set(new_model.id), + group_id: Set(child_id.0), + } + })) + .on_empty_do_nothing() + .exec(&self.db) + .await?; + + Ok(PhysicalExpressionId(new_model.id)) + } + + /// Checks if the given logical expression is a duplicate / already exists in the memo table. + /// + /// In order to prevent a large amount of duplicate work, the memo table must support duplicate + /// expression detection. + /// + /// Returns `Some((group_id, expression_id))` if the memo table detects that the expression + /// already exists, and `None` otherwise. + /// + /// This function assumes that the child groups of the expression are currently roots of their + /// group sets. For example, if G1 and G2 should be merged, and G1 is the root, then the input + /// expression should _not_ have G2 as a child, and should be replaced with G1. + pub async fn is_duplicate_logical_expression( + &self, + logical_expression: &LogicalExpression, + children: &[GroupId], + ) -> OptimizerResult> { + let model: logical_expression::Model = logical_expression.clone().into(); + + // Lookup all expressions that have the same fingerprint and kind. There may be false + // positives, but we will check for those next. + let kind = model.kind; + + // In order to calculate a correct fingerprint, we will want to use the IDs of the root + // groups of the children instead of the child ID themselves. + let mut rewrites = vec![]; + for &child_id in children { + let root_id = self.get_root_group(child_id).await?; + rewrites.push((child_id, root_id.into())); + } + let fingerprint = logical_expression.fingerprint_with_rewrite(&rewrites); + + // Filter first by the fingerprint, and then the kind. + // FIXME: The kind is already embedded into the fingerprint, so we may not actually need the + // second filter? + let potential_matches = fingerprint::Entity::find() + .filter(fingerprint::Column::Hash.eq(fingerprint)) + .filter(fingerprint::Column::Kind.eq(kind)) + .all(&self.db) + .await?; + + if potential_matches.is_empty() { + return Ok(None); + } + + // Now that we have all of the expressions that match the given fingerprint, we need to + // filter out all of the expressions that might have had the same fingerprint but are not + // actually equivalent (hash collisions). + let mut match_id = None; + for potential_match in potential_matches { + let expr_id = LogicalExpressionId(potential_match.logical_expression_id); + let (group_id, expr) = self.get_logical_expression(expr_id).await?; + + // We need to add the root groups of the new expression to the rewrites vector. + // TODO make this much more efficient by making rewrites a hash map, potentially im::HashMap. + let mut rewrites = rewrites.clone(); + for child_id in expr.children() { + let root_id = self.get_root_group(child_id).await?; + rewrites.push((child_id, root_id.into())); + } + + // Check for an exact match after rewrites. + if logical_expression.eq_with_rewrite(&expr, &rewrites) { + match_id = Some((group_id, expr_id)); + + // There should be at most one duplicate expression, so we can break here. + break; + } + } + + Ok(match_id) + } + + /// Adds a new group into the memo table via a logical expression, creating a new group if the + /// logical expression does not already exist. + /// + /// The caller is required to pass in a slice of [`GroupId`] that represent the child groups of + /// the input expression. + /// + /// If the expression already exists, then this function will return the [`GroupId`] of the + /// parent group and the corresponding (already existing) [`LogicalExpressionId`]. It will also + /// completely ignore the group ID field of the input expression as well as ignore the input + /// slice of child groups. + /// + /// If the expression does not exist, this function will create a new group and a new + /// expression, returning brand new IDs for both. + pub async fn add_group( + &self, + logical_expression: LogicalExpression, + children: &[GroupId], + ) -> OptimizerResult> + { + // Check if the expression already exists in the memo table. + if let Some((group_id, existing_id)) = self + .is_duplicate_logical_expression(&logical_expression, children) + .await? + { + return Ok(Err((group_id, existing_id))); + } + + // The expression does not exist yet, so we need to create a new group and new expression. + let group = group::ActiveModel { + status: Set(0), // `GroupStatus::InProgress` status. + ..Default::default() + }; + + // Create the new group. + let group_res = group::Entity::insert(group).exec(&self.db).await?; + let group_id = group_res.last_insert_id; + + // Insert the input expression into the newly created group. + let expression: logical_expression::Model = logical_expression.clone().into(); + let mut active_expression = expression.into_active_model(); + active_expression.group_id = Set(group_id); + active_expression.id = NotSet; + let new_expression = active_expression.insert(&self.db).await?; + + let group_id = new_expression.group_id; + let expr_id = new_expression.id; + + // Insert the child groups of the expression into the junction / children table. + logical_children::Entity::insert_many(children.iter().copied().map(|child_id| { + logical_children::ActiveModel { + logical_expression_id: Set(new_expression.id), + group_id: Set(child_id.0), + } + })) + .on_empty_do_nothing() + .exec(&self.db) + .await?; + + // Finally, insert the fingerprint of the logical expression as well. + let new_logical_expression: LogicalExpression = new_expression.into(); + let kind = new_logical_expression.kind(); + + // In order to calculate a correct fingerprint, we will want to use the IDs of the root + // groups of the children instead of the child ID themselves. + let mut rewrites = vec![]; + for &child_id in children { + let root_id = self.get_root_group(child_id).await?; + rewrites.push((child_id, root_id.into())); + } + let hash = new_logical_expression.fingerprint_with_rewrite(&rewrites); + + let fingerprint = fingerprint::ActiveModel { + id: NotSet, + logical_expression_id: Set(expr_id), + kind: Set(kind), + hash: Set(hash), + }; + fingerprint::Entity::insert(fingerprint) + .exec(&self.db) + .await?; + + Ok(Ok((GroupId(group_id), LogicalExpressionId(expr_id)))) + } + + /// Merges two groups sets together. + /// + /// If either of the input groups do not exist, returns a [`MemoError::UnknownGroup`] error. + /// + /// TODO write docs. + /// TODO highly inefficient, need to understand metrics and performance testing. + /// TODO Optimization: add rank / size into data structure + pub async fn merge_groups( + &self, + left_group_id: GroupId, + right_group_id: GroupId, + ) -> OptimizerResult { + // Without a rank / size field, we have no way of determining which set is better to merge + // into the other. So we will arbitrarily choose to merge the left group into the right + // group here. If rank is added in the future, then merge the smaller set into the larger. + + let left_root_id = self.get_root_group(left_group_id).await?; + let left_root = self.get_group(left_root_id.into()).await?; + // A `None` next pointer means it should technically be pointing to itself. + let left_next = left_root.next_id.unwrap_or(left_root_id.0); + let mut active_left_root = left_root.into_active_model(); + + let right_root_id = self.get_root_group(right_group_id).await?; + let right_root = self.get_group(right_root_id.into()).await?; + // A `None` next pointer means it should technically be pointing to itself. + let right_next = right_root.next_id.unwrap_or(right_root_id.0); + let mut active_right_root = right_root.into_active_model(); + + // Before we actually update the group records, We first need to generate new fingerprints + // for every single expression that has a child group in the left set. + // TODO make this more efficient, this code is doing double work from `get_group_set`. + let group_set_ids = self.get_group_set(left_group_id).await?; + let mut left_group_models = Vec::with_capacity(group_set_ids.len()); + for &group_id in &group_set_ids { + left_group_models.push(self.get_group(group_id).await?); + } + + // Retrieve every single expression that has a child group in the left set. + let left_group_expressions: Vec> = left_group_models + .load_many_to_many( + logical_expression::Entity, + logical_children::Entity, + &self.db, + ) + .await?; + + // Need to replace every single occurrence of groups in the set with the new root. + let rewrites: Vec<(GroupId, GroupId)> = group_set_ids + .iter() + .map(|&group_id| (group_id, right_root_id.into())) + .collect(); + + // For each expression, generate a new fingerprint. + let mut seen = HashSet::new(); + for model in left_group_expressions.into_iter().flatten() { + let expr_id = model.id; + + // There may be duplicates in the expressions list. + if seen.contains(&expr_id) { + continue; + } else { + seen.insert(expr_id); + } + + let logical_expression: LogicalExpression = model.into(); + let hash = logical_expression.fingerprint_with_rewrite(&rewrites); + + let fingerprint = fingerprint::ActiveModel { + id: NotSet, + logical_expression_id: Set(expr_id), + kind: Set(logical_expression.kind()), + hash: Set(hash), + }; + fingerprint::Entity::insert(fingerprint) + .exec(&self.db) + .await?; + } + + // Update the left group root to point to the right group root. + active_left_root.parent_id = Set(Some(right_root_id.0)); + + // Swap the next pointers of each root to maintain the circular linked list. + active_left_root.next_id = Set(Some(right_next)); + active_right_root.next_id = Set(Some(left_next)); + + active_left_root.update(&self.db).await?; + active_right_root.update(&self.db).await?; + + Ok(right_root_id) + } +} diff --git a/optd-mvp/src/memo/persistent/mod.rs b/optd-mvp/src/memo/persistent/mod.rs new file mode 100644 index 0000000..ed64fc5 --- /dev/null +++ b/optd-mvp/src/memo/persistent/mod.rs @@ -0,0 +1,18 @@ +//! This module contains the definition and implementation of the [`PersistentMemo`] type, which +//! implements the `Memo` trait and supports memo table operations necessary for query optimization. + +use sea_orm::DatabaseConnection; + +#[cfg(test)] +mod tests; + +/// A persistent memo table, backed by a database on disk. +/// +/// TODO more docs. +pub struct PersistentMemo { + /// This `PersistentMemo` is reliant on the SeaORM [`DatabaseConnection`] that stores all of the + /// objects needed for query optimization. + db: DatabaseConnection, +} + +mod implementation; diff --git a/optd-mvp/src/memo/persistent/tests.rs b/optd-mvp/src/memo/persistent/tests.rs new file mode 100644 index 0000000..be3115c --- /dev/null +++ b/optd-mvp/src/memo/persistent/tests.rs @@ -0,0 +1,471 @@ +use crate::{expression::*, memo::persistent::PersistentMemo}; + +/// Tests that exact expression matches are detected and handled by the memo table. +#[ignore] +#[tokio::test] +async fn test_simple_logical_duplicates() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + let scan = scan("t1".to_string()); + let scan1a = scan.clone(); + let scan1b = scan.clone(); + let scan2a = scan.clone(); + let scan2b = scan.clone(); + + // Insert a new group and its corresponding expression. + let (group_id, logical_expression_id) = memo.add_group(scan, &[]).await.unwrap().ok().unwrap(); + + // Test `add_logical_expression`. + { + // Attempting to create a new group with a duplicate expression should fail every time. + let (group_id_1a, logical_expression_id_1a) = + memo.add_group(scan1a, &[]).await.unwrap().err().unwrap(); + assert_eq!(group_id, group_id_1a); + assert_eq!(logical_expression_id, logical_expression_id_1a); + + // Try again just in case... + let (group_id_1b, logical_expression_id_1b) = + memo.add_group(scan1b, &[]).await.unwrap().err().unwrap(); + assert_eq!(group_id, group_id_1b); + assert_eq!(logical_expression_id, logical_expression_id_1b); + } + + // Test `add_logical_expression_to_group`. + { + // Attempting to add a duplicate expression into the same group should also fail every time. + let (group_id_2a, logical_expression_id_2a) = memo + .add_logical_expression_to_group(group_id, scan2a, &[]) + .await + .unwrap() + .err() + .unwrap(); + assert_eq!(group_id, group_id_2a); + assert_eq!(logical_expression_id, logical_expression_id_2a); + + let (group_id_2b, logical_expression_id_2b) = memo + .add_logical_expression_to_group(group_id, scan2b, &[]) + .await + .unwrap() + .err() + .unwrap(); + assert_eq!(group_id, group_id_2b); + assert_eq!(logical_expression_id, logical_expression_id_2b); + } + + memo.cleanup().await; +} + +/// Tests that physical expression are _not_ subject to duplicate detection and elimination. +/// +/// !!! Important !!! Note that this behavior should not actually be seen during query optimization, +/// since if logical expression have been deduplicated, there should not be any duplicate physical +/// expressions as they are derivative of the deduplicated logical expressions. +#[ignore] +#[tokio::test] +async fn test_simple_add_physical_expression() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Insert a new group and its corresponding expression. + let scan = scan("t1".to_string()); + let (group_id, _) = memo.add_group(scan, &[]).await.unwrap().ok().unwrap(); + + // Insert two identical physical expressions into the _same_ group. + let table_scan_1 = table_scan("t1".to_string()); + let table_scan_2 = table_scan_1.clone(); + + let physical_expression_id_1 = memo + .add_physical_expression_to_group(group_id, table_scan_1, &[]) + .await + .unwrap(); + + let physical_expression_id_2 = memo + .add_physical_expression_to_group(group_id, table_scan_2, &[]) + .await + .unwrap(); + + // Since physical expressions do not need duplicate detection, + assert_ne!(physical_expression_id_1, physical_expression_id_2); + + memo.cleanup().await; +} + +/// Tests if the memo tables able to correctly retrieve a group's expressions. +#[ignore] +#[tokio::test] +async fn test_simple_tree() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Create two scan groups. + let scan1: LogicalExpression = scan("t1".to_string()); + let scan2 = scan("t2".to_string()); + let (scan_id_1, scan_expr_id_1) = memo.add_group(scan1, &[]).await.unwrap().ok().unwrap(); + let (scan_id_2, scan_expr_id_2) = memo.add_group(scan2, &[]).await.unwrap().ok().unwrap(); + + assert_eq!( + memo.get_logical_children(scan_id_1).await.unwrap(), + &[scan_expr_id_1] + ); + assert_eq!( + memo.get_logical_children(scan_id_2).await.unwrap(), + &[scan_expr_id_2] + ); + + // Create two join expression that should be in the same group. + let join1 = join(scan_id_1, scan_id_2, "t1.a = t2.b".to_string()); + let join2 = join(scan_id_2, scan_id_1, "t1.a = t2.b".to_string()); + + // Create the group, adding the first expression. + let (join_id, join_expr_id_1) = memo + .add_group(join1, &[scan_id_1, scan_id_2]) + .await + .unwrap() + .ok() + .unwrap(); + // Add the second expression. + let join_expr_id_2 = memo + .add_logical_expression_to_group(join_id, join2, &[scan_id_2, scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + + assert_ne!(join_expr_id_1, join_expr_id_2); + assert_eq!( + memo.get_logical_children(join_id).await.unwrap(), + &[join_expr_id_1, join_expr_id_2] + ); + + memo.cleanup().await; +} + +/// Tests a single group merge. See comments in the test itself for more information. +#[ignore] +#[tokio::test] +async fn test_simple_group_link() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Create two scan groups. + let scan1 = scan("t1".to_string()); + let scan2 = scan("t2".to_string()); + let (scan_id_1, _) = memo.add_group(scan1, &[]).await.unwrap().ok().unwrap(); + let (scan_id_2, _) = memo.add_group(scan2, &[]).await.unwrap().ok().unwrap(); + + // Create two join expression that should be in the same group. + // Even though these are obviously the same expression (to humans), the fingerprints will be + // different, and so they will be put into different groups. + let join1 = join(scan_id_1, scan_id_2, "t1.a = t2.b".to_string()); + let join2 = join(scan_id_2, scan_id_1, "t2.b = t1.a".to_string()); + let join_unknown = join2.clone(); + + let (join_group_1, _) = memo + .add_group(join1, &[scan_id_1, scan_id_2]) + .await + .unwrap() + .ok() + .unwrap(); + let (join_group_2, join_expr_2) = memo + .add_group(join2, &[scan_id_2, scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + assert_ne!(join_group_1, join_group_2); + + // Assume that some rule was applied to `join1`, and it outputs something like `join_unknown`. + // The memo table will tell us that `join_unknown == join2`. + // Take note here that `join_unknown` is a clone of `join2`, not `join1`. + let (existing_group, not_actually_new_expr_id) = memo + .add_logical_expression_to_group(join_group_1, join_unknown, &[scan_id_2, scan_id_1]) + .await + .unwrap() + .err() + .unwrap(); + assert_eq!(existing_group, join_group_2); + assert_eq!(not_actually_new_expr_id, join_expr_2); + + // The above tells the application that the expression already exists in the memo, specifically + // under `existing_group`. Thus, we should link these two groups together. + memo.merge_groups(join_group_1, join_group_2).await.unwrap(); + + let test_root_1 = memo.get_root_group(join_group_1).await.unwrap(); + let test_root_2 = memo.get_root_group(join_group_2).await.unwrap(); + assert_eq!(test_root_1, test_root_2); + + memo.cleanup().await; +} + +#[ignore] +#[tokio::test] +async fn test_group_merge_ladder() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Build up a tree of true filters that should be collapsed into a single table scan. + let scan_base = scan("t1".to_string()); + let (scan_id, _) = memo.add_group(scan_base, &[]).await.unwrap().ok().unwrap(); + + let filter0 = filter(scan_id, "true".to_string()); + let (filter_id_0, _) = memo + .add_group(filter0, &[scan_id]) + .await + .unwrap() + .ok() + .unwrap(); + + let filter1 = filter(filter_id_0, "true".to_string()); + let (filter_id_1, _) = memo + .add_group(filter1, &[scan_id]) + .await + .unwrap() + .ok() + .unwrap(); + + let filter2 = filter(filter_id_1, "true".to_string()); + let (filter_id_2, _) = memo + .add_group(filter2, &[scan_id]) + .await + .unwrap() + .ok() + .unwrap(); + + let filter3 = filter(filter_id_2, "true".to_string()); + let (filter_id_3, _) = memo + .add_group(filter3, &[scan_id]) + .await + .unwrap() + .ok() + .unwrap(); + + let mut groups = vec![scan_id, filter_id_0, filter_id_1, filter_id_2, filter_id_3]; + + let m0 = memo.merge_groups(filter_id_3, filter_id_2).await.unwrap(); + let m1 = memo.merge_groups(filter_id_2, filter_id_1).await.unwrap(); + let m2 = memo.merge_groups(filter_id_1, filter_id_0).await.unwrap(); + let root = memo.merge_groups(filter_id_0, scan_id).await.unwrap(); + groups.extend_from_slice(&[m0, m1, m2, root]); + + for group_id in groups { + assert_eq!(root, memo.get_root_group(group_id).await.unwrap()); + } + + memo.cleanup().await; +} + +/// Tests merging a bunch of groups together in order to prevent duplicates from being added. +#[ignore] +#[tokio::test] +async fn test_group_merge() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Create a base group. + let scan1 = scan("t1".to_string()); + let (scan_id_1, _) = memo.add_group(scan1, &[]).await.unwrap().ok().unwrap(); + + // Create a bunch of equivalent groups. + let filter0 = filter(scan_id_1, "true".to_string()); + let filter1 = filter(scan_id_1, "1 < 2".to_string()); + let filter2 = filter(scan_id_1, "2 > 1".to_string()); + let filter3 = filter(scan_id_1, "42 != 100".to_string()); + let filter4 = filter(scan_id_1, "10000 > 0".to_string()); + let filter5 = filter(scan_id_1, "1 + 2 = 3".to_string()); + let filter6 = filter(scan_id_1, "true OR false".to_string()); + let filter7 = filter(scan_id_1, "(1 + 1 > -1 AND true) OR false".to_string()); + let (filter_id_0, _) = memo + .add_group(filter0, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_1, _) = memo + .add_group(filter1, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_2, _) = memo + .add_group(filter2, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_3, _) = memo + .add_group(filter3, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_4, _) = memo + .add_group(filter4, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_5, _) = memo + .add_group(filter5, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_6, _) = memo + .add_group(filter6, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let (filter_id_7, _) = memo + .add_group(filter7, &[scan_id_1]) + .await + .unwrap() + .ok() + .unwrap(); + let filters = vec![ + filter_id_0, + filter_id_1, + filter_id_2, + filter_id_3, + filter_id_4, + filter_id_5, + filter_id_6, + filter_id_7, + ]; + + // Merge them all together. + let quarter_0 = memo.merge_groups(filters[0], filters[1]).await.unwrap(); + let quarter_1 = memo.merge_groups(filters[2], filters[3]).await.unwrap(); + let quarter_2 = memo.merge_groups(filters[4], filters[5]).await.unwrap(); + let quarter_3 = memo.merge_groups(filters[6], filters[7]).await.unwrap(); + let semi_0 = memo.merge_groups(quarter_0, quarter_1).await.unwrap(); + let semi_1 = memo.merge_groups(quarter_2, quarter_3).await.unwrap(); + let final_id = memo.merge_groups(semi_0, semi_1).await.unwrap(); + + // Check that the group set is properly representative. + { + let set = memo.get_group_set(final_id).await.unwrap(); + assert_eq!(set.len(), 8); + for id in set { + assert!(filters.contains(&id)); + } + } + + // Create another base group. + let scan2 = scan("t2".to_string()); + let (scan_id_2, _) = memo.add_group(scan2, &[]).await.unwrap().ok().unwrap(); + + // Add a join group. + let join0 = join(filter_id_0, scan_id_2, "t1.a = t2.a".to_string()); + let (join_group_id, join_expr_id) = memo + .add_group(join0, &[filter_id_0, scan_id_2]) + .await + .unwrap() + .ok() + .unwrap(); + + // Adding the duplicate join expressions should return a duplication error containing the IDs of + // the already existing group and expression. + for filter_id in filters { + let join_test = join(filter_id, scan_id_2, "t1.a = t2.a".to_string()); + let (join_group_id_test, join_expr_id_test) = memo + .add_group(join_test, &[filter_id, scan_id_2]) + .await + .unwrap() + .err() + .unwrap(); + assert_eq!(join_group_id, join_group_id_test); + assert_eq!(join_expr_id, join_expr_id_test); + } + + memo.cleanup().await; +} + +/// Tests the exact same scenario as in the "Discovered Duplicates" section in `DESIGN.md`. +#[ignore] +#[tokio::test] +async fn test_cascading_merge() { + let memo = PersistentMemo::new().await; + memo.cleanup().await; + + // Create the base groups. + let scan1 = scan("t1".to_string()); + let (g1, _) = memo.add_group(scan1, &[]).await.unwrap().ok().unwrap(); + let scan2 = scan("t2".to_string()); + let (g2, _) = memo.add_group(scan2, &[]).await.unwrap().ok().unwrap(); + + let filter1 = filter(g1, "x > 1000".to_string()); + let (g3, _) = memo.add_group(filter1, &[g1]).await.unwrap().ok().unwrap(); + + // Create two groups that will need to be merged. + let filter2a = filter(g2, "a < 42".to_string()); + let (g4, _) = memo.add_group(filter2a, &[g2]).await.unwrap().ok().unwrap(); + let filter2b = filter(g4, "a < 42 AND 1 = 1".to_string()); + let (g5, _) = memo.add_group(filter2b, &[g4]).await.unwrap().ok().unwrap(); + + // Create groups that are dependent on the to-be-merged groups. + let join1 = join(g3, g4, "t1.x = t2.a".to_string()); + let (g6, _) = memo + .add_group(join1, &[g3, g4]) + .await + .unwrap() + .ok() + .unwrap(); + let join2 = join(g3, g5, "t1.x = t2.a".to_string()); + let (g7, _) = memo + .add_group(join2, &[g3, g5]) + .await + .unwrap() + .ok() + .unwrap(); + + // Create more groups that are dependent on the to-be-merged groups. + // TODO actually use a sort expression instead of a `filter` placeholder. + let sort1 = filter(g6, "ORDER BY a".to_string()); + let (g8, _) = memo.add_group(sort1, &[g6]).await.unwrap().ok().unwrap(); + + let sort2 = filter(g7, "ORDER BY a".to_string()); + let (g9, _) = memo.add_group(sort2, &[g7]).await.unwrap().ok().unwrap(); + + // Now that everything is set up, we can merge groups 4 and 5 to begin the cascading process. + let filter_root = memo.merge_groups(g4, g5).await.unwrap(); + assert_eq!(memo.get_root_group(g4).await.unwrap(), filter_root); + assert_eq!(memo.get_root_group(g5).await.unwrap(), filter_root); + + // After merging, the join groups (6 and 7) are technically identical, but we have not merged + // them together yet. However, applying rules will reveal that they are identical, and we will + // know that they need to get merged. + let join1_commute = join(g4, g3, "t1.x = t2.a".to_string()); + let join1_commute_id = memo + .add_logical_expression_to_group(g6, join1_commute, &[g4, g3]) + .await + .unwrap() + .ok() + .unwrap(); + + // Adding this expression should now result in a duplication error and return the above ID. + let join2_commute = join(g5, g3, "t1.x = t2.a".to_string()); + let (existing_g6, existing_id) = memo + .add_logical_expression_to_group(g7, join2_commute, &[g5, g3]) + .await + .unwrap() + .err() + .unwrap(); + assert_eq!(existing_g6, g6); + assert_eq!(existing_id, join1_commute_id); + + // Since the memo table has told us these are duplicates, we can now merge groups 6 and 7. + let join_root = memo.merge_groups(g6, g7).await.unwrap(); + assert_eq!(memo.get_root_group(g6).await.unwrap(), join_root); + assert_eq!(memo.get_root_group(g7).await.unwrap(), join_root); + + // Do a similar thing for the sort groups. We'll skip the expression adding for now and just + // merge them immediately, but remember that the application should observe a duplicate + // somewhere in the memo table before deciding to merge groups. + let sort_root = memo.merge_groups(g8, g9).await.unwrap(); + assert_eq!(memo.get_root_group(g8).await.unwrap(), sort_root); + assert_eq!(memo.get_root_group(g9).await.unwrap(), sort_root); + + memo.cleanup().await; +} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_namespace_metadata.rs b/optd-mvp/src/migrator/memo/m20241127_000001_fingerprint.rs similarity index 50% rename from optd-persistent/src/migrator/catalog/m20241029_000001_namespace_metadata.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_fingerprint.rs index 684621c..e153b9e 100644 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_namespace_metadata.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_fingerprint.rs @@ -1,13 +1,17 @@ -use crate::migrator::catalog::database_metadata::DatabaseMetadata; +//! An entity representing a logical expression fingerprint. +//! +//! TODO write docs. + +use crate::migrator::memo::logical_expression::LogicalExpression; use sea_orm_migration::{prelude::*, schema::*}; -#[derive(Iden)] -pub enum NamespaceMetadata { +#[derive(DeriveIden)] +pub enum Fingerprint { Table, Id, - Name, - DatabaseId, - CreationTime, + LogicalExpressionId, + Kind, + Hash, } #[derive(DeriveMigrationName)] @@ -19,19 +23,19 @@ impl MigrationTrait for Migration { manager .create_table( Table::create() - .table(NamespaceMetadata::Table) + .table(Fingerprint::Table) .if_not_exists() - .col(pk_auto(NamespaceMetadata::Id)) - .col(string(NamespaceMetadata::Name)) - .col(integer(NamespaceMetadata::DatabaseId)) + .col(pk_auto(Fingerprint::Id)) + .col(integer(Fingerprint::LogicalExpressionId)) .foreign_key( ForeignKey::create() - .from(NamespaceMetadata::Table, NamespaceMetadata::DatabaseId) - .to(DatabaseMetadata::Table, DatabaseMetadata::Id) + .from(Fingerprint::Table, Fingerprint::LogicalExpressionId) + .to(LogicalExpression::Table, LogicalExpression::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) - .col(timestamp(NamespaceMetadata::CreationTime)) + .col(small_integer(Fingerprint::Kind)) + .col(big_integer(Fingerprint::Hash)) .to_owned(), ) .await @@ -39,7 +43,7 @@ impl MigrationTrait for Migration { async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager - .drop_table(Table::drop().table(NamespaceMetadata::Table).to_owned()) + .drop_table(Table::drop().table(Fingerprint::Table).to_owned()) .await } } diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_cascades_group.rs b/optd-mvp/src/migrator/memo/m20241127_000001_group.rs similarity index 58% rename from optd-persistent/src/migrator/memo/m20241029_000001_cascades_group.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_group.rs index 1700772..59b5a09 100644 --- a/optd-persistent/src/migrator/memo/m20241029_000001_cascades_group.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_group.rs @@ -1,3 +1,5 @@ +//! FIXME We aren't really following the cascades framework anymore... +//! //! An entity representing a group / equivalence class in the Cascades framework. //! //! Quoted from the Microsoft article _Extensible query optimizers in practice_: @@ -17,65 +19,72 @@ //! # Columns //! //! Each group is assigned a monotonically-increasing (unique) ID. This ID will be important since -//! there are many foreign key references from other tables to `cascades_group`. +//! there are many foreign key references from other tables to `group`. +//! +//! We store an `status` enumeration encoded as an 8-bit integer that is used for quickly +//! determining the state of optimization for this group during the dynamic programming search. //! -//! We additionally store a `latest_winner` foreign key reference to a physical expression. See -//! the [section](#best-physical-plan-winner) below for more details. +//! We additionally store a `winner` foreign key reference to a physical expression paired with a +//! `cost` foreign key reference to a cost record (FIXME). See the +//! [section](#best-physical-plan-winner) below for more details. //! -//! Finally, we store `in_progress` and `is_optimized` flags that are used for quickly determining -//! the state of optimization for this group during the dynamic programming search. +//! Finally, we maintain a union-find graph structure embedded in the group records. See the +//! `DESIGN.md` document for more information. //! //! # Entity Relationships //! //! ### Child Expressions (Logical and Physical) //! -//! To retrieve all of a `cascades_group`'s equivalent expressions, you must query the +//! To retrieve all of a `group`'s equivalent expressions, you must query the //! [`logical_expression`] or the [`physical_expression`] entities via their foreign keys to -//! `cascades_group`. The relationship between [`logical_expression`] and `cascades_group` is +//! `group`. The relationship between [`logical_expression`] and `group` is //! many-to-one, and the exact same many-to-one relationship is held for [`physical_expression`] to -//! `cascades_group`. +//! `group`. //! //! ### Parent Expressions (Logical and Physical) //! -//! Additionally, each logical or physical expression can have any number of `cascades_group`s as -//! children, and a group can be a child of any expression. Thus, `cascades_group` additionally has +//! Additionally, each logical or physical expression can have any number of `group`s as +//! children, and a group can be a child of any expression. Thus, `group` additionally has //! a many-to-many relationship with [`logical_expression`] and [`physical_expression`] via the //! [`logical_children`] and [`physical_children`] entities. //! -//! To reiterate, `cascades_group` has **both** a one-to-many **and** a many-to-many relationship +//! To reiterate, `group` has **both** a one-to-many **and** a many-to-many relationship //! with both [`logical_expression`] and [`physical_expression`]. This is due to groups being both //! parents and children of expressions. //! //! ### Best Physical Plan (Winner) //! -//! The `cascades_group` entity also stores a `latest_winner` _nullable_ foreign key reference to +//! The `group` entity also stores a `winner` _nullable_ foreign key reference to //! a physical expression. This represents the most recent best query plan we have computed. The //! reason it is nullable is because we may not have come up with any best query plan yet. //! //! ### Logical Properties //! -//! Lastly, each `cascades_group` record will have a set of logical properties store in the -//! [`logical_property`] entity, where there is an many-to-one relationship from -//! [`logical_property`] to `cascades_group`. Note that we do not store physical properties directly -//! on the `cascades_group`, but rather we store them for each [`physical_expression`] record. +//! FIXME: Add a logical properties table. +//! +//! Lastly, each `group` record will have a set of logical properties store in the +//! `logical_property` entity, where there is an many-to-one relationship from +//! `logical_property` to `group`. Note that we do not store physical properties directly +//! on the `group`, but rather we store them for each [`physical_expression`] record. //! //! [`logical_expression`]: super::logical_expression //! [`physical_expression`]: super::physical_expression //! [`logical_children`]: super::logical_children //! [`physical_children`]: super::physical_children -//! [`logical_property`]: super::logical_property +//! `logical_property`: super::logical_property use crate::migrator::memo::physical_expression::PhysicalExpression; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveIden)] -pub enum CascadesGroup { +pub enum Group { Table, Id, - LatestWinner, - InProgress, - IsOptimized, + Status, + Winner, + Cost, ParentId, + NextId, } #[derive(DeriveMigrationName)] @@ -87,24 +96,32 @@ impl MigrationTrait for Migration { manager .create_table( Table::create() - .table(CascadesGroup::Table) + .table(Group::Table) .if_not_exists() - .col(pk_auto(CascadesGroup::Id)) - .col(integer_null(CascadesGroup::LatestWinner)) + .col(pk_auto(Group::Id)) + .col(tiny_integer(Group::Status)) + .col(integer_null(Group::Winner)) + .col(big_integer_null(Group::Cost)) .foreign_key( ForeignKey::create() - .from(CascadesGroup::Table, CascadesGroup::LatestWinner) + .from(Group::Table, Group::Winner) .to(PhysicalExpression::Table, PhysicalExpression::Id) .on_delete(ForeignKeyAction::SetNull) .on_update(ForeignKeyAction::Cascade), ) - .col(boolean(CascadesGroup::InProgress)) - .col(boolean(CascadesGroup::IsOptimized)) - .col(integer_null(CascadesGroup::ParentId)) + .col(integer_null(Group::ParentId)) + .foreign_key( + ForeignKey::create() + .from(Group::Table, Group::ParentId) + .to(Group::Table, Group::Id) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col(integer_null(Group::NextId)) .foreign_key( ForeignKey::create() - .from(CascadesGroup::Table, CascadesGroup::ParentId) - .to(CascadesGroup::Table, CascadesGroup::Id) + .from(Group::Table, Group::NextId) + .to(Group::Table, Group::Id) .on_delete(ForeignKeyAction::SetNull) .on_update(ForeignKeyAction::Cascade), ) @@ -115,7 +132,7 @@ impl MigrationTrait for Migration { async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager - .drop_table(Table::drop().table(CascadesGroup::Table).to_owned()) + .drop_table(Table::drop().table(Group::Table).to_owned()) .await } } diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_logical_children.rs b/optd-mvp/src/migrator/memo/m20241127_000001_logical_children.rs similarity index 81% rename from optd-persistent/src/migrator/memo/m20241029_000001_logical_children.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_logical_children.rs index d0835f4..12b5aa6 100644 --- a/optd-persistent/src/migrator/memo/m20241029_000001_logical_children.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_logical_children.rs @@ -1,16 +1,16 @@ -//! An entity representing the [`cascades_group`] children of every [`logical_expression`]. +//! An entity representing the [`group`] children of every [`logical_expression`]. //! //! Formally, this entity is a junction which allows us to represent a many-to-many relationship -//! between [`logical_expression`] and [`cascades_group`]. Expressions can have any number of child +//! between [`logical_expression`] and [`group`]. Expressions can have any number of child //! groups, and every group can be a child of many different expressions, hence the many-to-many //! relationship. //! -//! See [`cascades_group`] for more details. +//! See [`group`] for more details. //! -//! [`cascades_group`]: super::cascades_group +//! [`group`]: super::group //! [`logical_expression`]: super::logical_expression -use crate::migrator::memo::{cascades_group::CascadesGroup, logical_expression::LogicalExpression}; +use crate::migrator::memo::{group::Group, logical_expression::LogicalExpression}; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveIden)] @@ -40,7 +40,7 @@ impl MigrationTrait for Migration { ) .foreign_key( ForeignKey::create() - .from(LogicalChildren::Table, LogicalChildren::GroupId) + .from(LogicalChildren::Table, LogicalChildren::LogicalExpressionId) .to(LogicalExpression::Table, LogicalExpression::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), @@ -48,7 +48,7 @@ impl MigrationTrait for Migration { .foreign_key( ForeignKey::create() .from(LogicalChildren::Table, LogicalChildren::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) + .to(Group::Table, Group::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_logical_expression.rs b/optd-mvp/src/migrator/memo/m20241127_000001_logical_expression.rs similarity index 68% rename from optd-persistent/src/migrator/memo/m20241029_000001_logical_expression.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_logical_expression.rs index 71e28d3..9b5eefc 100644 --- a/optd-persistent/src/migrator/memo/m20241029_000001_logical_expression.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_logical_expression.rs @@ -1,4 +1,4 @@ -//! An entity representing a logical plan expression in the Cascades framework. +//! An entity representing a logical relational expression. //! //! Quoted from the Microsoft article _Extensible query optimizers in practice_: //! @@ -6,7 +6,7 @@ //! > relational algebraic expression. //! //! In the Cascades query optimization framework, the memo table stores equivalence classes of -//! expressions (see [`cascades_group`]). These equivalence classes, or "groups", store both +//! expressions (see [`group`]). These equivalence classes, or "groups", store both //! `logical_expression`s and [`physical_expression`]s. //! //! Optimization starts by "exploring" equivalent logical expressions within a group. For example, @@ -19,23 +19,25 @@ //! Each `logical_expression` has a unique primary key ID, but it holds little importance other than //! helping distinguish between two different expressions. //! -//! The more interesting column is the `fingerprint` column, in which we store a hashed fingerprint -//! value that can be used to efficiently check equality between two potentially equivalent logical -//! expressions (hash-consing). See ???TODO??? for more information on expression fingerprints. -//! //! Finally, since there are many different types of operators, we store a variant tag and a data //! column as JSON to represent the semi-structured data fields of logical operators. //! //! # Entity Relationships //! -//! The only relationship that `logical_expression` has is to [`cascades_group`]. It has **both** a -//! one-to-many **and** a many-to-many relationship with [`cascades_group`], and you can see more -//! details about this in the module-level documentation for [`cascades_group`]. +//! The main relationship that `logical_expression` has is to [`group`]. It has **both** a +//! one-to-many **and** a many-to-many relationship with [`group`], and you can see more +//! details about this in the module-level documentation for [`group`]. +//! +//! The other relationship that `logical_expression` has is to [`fingerprint`]. This table stores +//! 1 or more fingerprints for every (unique) logical expression. The reason we have multiple +//! fingerprints is that an expression can belong to multiple groups during the exploration phase +//! before the merging of groups. //! -//! [`cascades_group`]: super::cascades_group +//! [`group`]: super::group //! [`physical_expression`]: super::physical_expression +//! [`fingerprint`]: super::fingerprint -use crate::migrator::memo::cascades_group::CascadesGroup; +use crate::migrator::memo::group::Group; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveIden)] @@ -43,8 +45,8 @@ pub enum LogicalExpression { Table, Id, GroupId, - Fingerprint, - VariantTag, + Kind, + Data, } #[derive(DeriveMigrationName)] @@ -63,12 +65,12 @@ impl MigrationTrait for Migration { .foreign_key( ForeignKey::create() .from(LogicalExpression::Table, LogicalExpression::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) + .to(Group::Table, Group::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) - .col(big_unsigned(LogicalExpression::Fingerprint)) - .col(small_integer(LogicalExpression::VariantTag)) + .col(small_integer(LogicalExpression::Kind)) + .col(json(LogicalExpression::Data)) .to_owned(), ) .await diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_physical_children.rs b/optd-mvp/src/migrator/memo/m20241127_000001_physical_children.rs similarity index 82% rename from optd-persistent/src/migrator/memo/m20241029_000001_physical_children.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_physical_children.rs index 3983f0c..06ce259 100644 --- a/optd-persistent/src/migrator/memo/m20241029_000001_physical_children.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_physical_children.rs @@ -1,18 +1,16 @@ -//! An entity representing the [`cascades_group`] children of every [`physical_expression`]. +//! An entity representing the [`group`] children of every [`physical_expression`]. //! //! Formally, this entity is a junction which allows us to represent a many-to-many relationship -//! between [`physical_expression`] and [`cascades_group`]. Expressions can have any number of child +//! between [`physical_expression`] and [`group`]. Expressions can have any number of child //! groups, and every group can be a child of many different expressions, hence the many-to-many //! relationship. //! -//! See [`cascades_group`] for more details. +//! See [`group`] for more details. //! -//! [`cascades_group`]: super::cascades_group +//! [`group`]: super::group //! [`physical_expression`]: super::physical_expression -use crate::migrator::memo::{ - cascades_group::CascadesGroup, physical_expression::PhysicalExpression, -}; +use crate::migrator::memo::{group::Group, physical_expression::PhysicalExpression}; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveIden)] @@ -53,7 +51,7 @@ impl MigrationTrait for Migration { .foreign_key( ForeignKey::create() .from(PhysicalChildren::Table, PhysicalChildren::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) + .to(Group::Table, Group::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_physical_expression.rs b/optd-mvp/src/migrator/memo/m20241127_000001_physical_expression.rs similarity index 70% rename from optd-persistent/src/migrator/memo/m20241029_000001_physical_expression.rs rename to optd-mvp/src/migrator/memo/m20241127_000001_physical_expression.rs index 8f7cb96..88cd63b 100644 --- a/optd-persistent/src/migrator/memo/m20241029_000001_physical_expression.rs +++ b/optd-mvp/src/migrator/memo/m20241127_000001_physical_expression.rs @@ -1,4 +1,4 @@ -//! An entity representing a logical plan expression in the Cascades framework. +//! An entity representing a physical plan expression. //! //! Quoted from the Microsoft article _Extensible query optimizers in practice_: //! @@ -6,7 +6,7 @@ //! > _physical plan_ or simply _plan_. //! //! In the Cascades query optimization framework, the memo table stores equivalence classes of -//! expressions (see [`cascades_group`]). These equivalence classes, or "groups", store both +//! expressions (see [`group`]). These equivalence classes, or "groups", store both //! [`logical_expression`]s and `physical_expression`s. //! //! Optimization starts by exploring equivalent logical expressions within a group, and then it @@ -20,23 +20,24 @@ //! Each `physical_expression` has a unique primary key ID, and other tables will store a foreign //! key reference to a specific `physical_expression`s. //! -//! The more interesting column is the `fingerprint` column, in which we store a hashed fingerprint -//! value that can be used to efficiently check equality between two potentially equivalent physical -//! expressions (hash-consing). See ???TODO??? for more information on expression fingerprints. +//! Note that `physical_expression` does **not** store a fingerprint. Remember that we want to +//! detect duplicates in the logical exploration phase. If there are no duplicate logical +//! expressions in the memo table, then there cannot be any duplicate physical expressions, which +//! are derived from said deduplicated logical expressions. //! //! Finally, since there are many different types of operators, we store a variant tag and a data //! column as JSON to represent the semi-structured data fields of logical operators. //! //! # Entity Relationships //! -//! The only relationship that `physical_expression` has is to [`cascades_group`]. It has **both** a -//! one-to-many **and** a many-to-many relationship with [`cascades_group`], and you can see more -//! details about this in the module-level documentation for [`cascades_group`]. +//! The only relationship that `physical_expression` has is to [`group`]. It has **both** a +//! one-to-many **and** a many-to-many relationship with [`group`], and you can see more +//! details about this in the module-level documentation for [`group`]. //! -//! [`cascades_group`]: super::cascades_group +//! [`group`]: super::group //! [`logical_expression`]: super::logical_expression -use crate::migrator::memo::cascades_group::CascadesGroup; +use crate::migrator::memo::group::Group; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveIden)] @@ -44,8 +45,8 @@ pub enum PhysicalExpression { Table, Id, GroupId, - Fingerprint, - VariantTag, + Kind, + Data, } #[derive(DeriveMigrationName)] @@ -64,12 +65,12 @@ impl MigrationTrait for Migration { .foreign_key( ForeignKey::create() .from(PhysicalExpression::Table, PhysicalExpression::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) + .to(Group::Table, Group::Id) .on_delete(ForeignKeyAction::Cascade) .on_update(ForeignKeyAction::Cascade), ) - .col(big_unsigned(PhysicalExpression::Fingerprint)) - .col(small_integer(PhysicalExpression::VariantTag)) + .col(small_integer(PhysicalExpression::Kind)) + .col(json(PhysicalExpression::Data)) .to_owned(), ) .await diff --git a/optd-mvp/src/migrator/memo/mod.rs b/optd-mvp/src/migrator/memo/mod.rs new file mode 100644 index 0000000..a419189 --- /dev/null +++ b/optd-mvp/src/migrator/memo/mod.rs @@ -0,0 +1,16 @@ +//! Entities related to the memo table used for dynamic programming in the our query optimization +//! framework. + +pub(crate) mod m20241127_000001_fingerprint; +pub(crate) mod m20241127_000001_group; +pub(crate) mod m20241127_000001_logical_children; +pub(crate) mod m20241127_000001_logical_expression; +pub(crate) mod m20241127_000001_physical_children; +pub(crate) mod m20241127_000001_physical_expression; + +pub(crate) use m20241127_000001_fingerprint as fingerprint; +pub(crate) use m20241127_000001_group as group; +pub(crate) use m20241127_000001_logical_children as logical_children; +pub(crate) use m20241127_000001_logical_expression as logical_expression; +pub(crate) use m20241127_000001_physical_children as physical_children; +pub(crate) use m20241127_000001_physical_expression as physical_expression; diff --git a/optd-mvp/src/migrator/mod.rs b/optd-mvp/src/migrator/mod.rs new file mode 100644 index 0000000..cbc39ae --- /dev/null +++ b/optd-mvp/src/migrator/mod.rs @@ -0,0 +1,19 @@ +use sea_orm_migration::prelude::*; + +mod memo; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![ + Box::new(memo::group::Migration), + Box::new(memo::fingerprint::Migration), + Box::new(memo::logical_expression::Migration), + Box::new(memo::logical_children::Migration), + Box::new(memo::physical_expression::Migration), + Box::new(memo::physical_children::Migration), + ] + } +} diff --git a/optd-persistent/Cargo.lock b/optd-persistent/Cargo.lock deleted file mode 100644 index 1c45426..0000000 --- a/optd-persistent/Cargo.lock +++ /dev/null @@ -1,2814 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa100a6f6f525226719f8de3f70076be4f4191801ebd92621450d1c51e9053d" - -[[package]] -name = "ahash" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "allocator-api2" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52f4a9cf8f3ff707b4eb1acd0136efd8b3bec6b345ed32fcab47c0a5c99b800" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" - -[[package]] -name = "anstyle-parse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "arrayvec" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7" - -[[package]] -name = "async-stream" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a26cb53174ddd320edfff199a853f93d571f48eeb4dde75e67a9a3dbb7b7e5e" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db134ba52475c060f3329a8ef0f8786d6b872ed01515d4b79c162e5798da1340" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "async-trait" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6287685011f026b98d26afd53251ad0101e856531b423eb2384265f7d4f5b01" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "backtrace" -version = "0.3.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88fb5a785d6b44fd9d6700935608639af1b8356de1e55d5f7c2740f4faa15d82" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "base64" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" - -[[package]] -name = "base64ct" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71acf5509fc522cce1b100ac0121c635129bfd4d91cdf036bcc9b9935f97ccf5" - -[[package]] -name = "bigdecimal" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5274a6b6e0ee020148397245b973e30163b7bffbc6d473613f850cb99888581e" -dependencies = [ - "libm", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" -dependencies = [ - "serde", -] - -[[package]] -name = "block-buffer" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cc" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.52.0", -] - -[[package]] -name = "clap" -version = "4.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" -dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", -] - -[[package]] -name = "clap_builder" -version = "4.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "codespan-reporting" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ce42b8998a383572e0a802d859b1f00c79b7b7474e62fff88ee5c2845d9c13" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" - -[[package]] -name = "crossbeam-queue" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cxx" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c53d75fe543215ca091d792e13351dcb940842dd2829b2a2dd43ab4bd1a015" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618f85c8f132bd8912aab124e15a38adc762bb7e3cef84524adde1692ef3e8bc" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.98", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca21461be76a23df4f63a2107a0bb406ef41548e635ff7edcbd1ab5a6bb997e2" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8da0a2c0697647b5824844a5d2dedcd97a2d7b75e6e4d0b8dd183e4081e1cf" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "darling" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c99d16b88c92aef47e58dadd53e87b4bd234c29934947a6cec8b466300f99b" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ea05d2fcb27b53f7a98faddaf5f2914760330ab7703adfc9df13332b42189f9" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "darling_macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfb82b62b1b8a2a9808fb4caf844ede819a76cfc23b2827d7f94eefb49551eb" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "der" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c5cb402c5c958281c7c0702edea7b780d03b86b606497ca3a10fcd3fc393ac" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dotenvy" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9155c8f4dc55c7470ae9da3f63c6785245093b3f6aeb0f5bf2e968efbba314" -dependencies = [ - "dirs", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -dependencies = [ - "serde", -] - -[[package]] -name = "equivalent" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "event-listener" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "futures-core", - "futures-sink", - "spin 0.9.8", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fa4cc29d25b0687b8570b0da86eac698dcb525110ad8b938fe6712baa711ec" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashlink" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f41e9c77b6fc05b57497b960aad55942a9bbc5b20e1e623cf7fb1868f695d1" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "inherent" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c05a410d53e44fc943a35a32ca27e32af2ea004d5107ccef685d022fc2b9fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "is-terminal" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a9df60778f789c37f76778ae8d0a2471c41baa8b059d98a5873c978f549587" - -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] -name = "js-sys" -version = "0.3.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -dependencies = [ - "spin 0.4.10", -] - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dfb9f65d9966f6ca6522043978030b564f3291af987fbf1dd55b6a064ba1b36" -dependencies = [ - "cc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "lock_api" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" - -[[package]] -name = "md-5" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" -dependencies = [ - "digest", -] - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "minimal-lexical" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6595bb28ed34f43c3fe088e48f6cfb2e033cab45f25a5384d5fdf564fbc8c4b2" - -[[package]] -name = "miniz_oxide" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.45.0", -] - -[[package]] -name = "nom" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" -dependencies = [ - "memchr", - "minimal-lexical", - "version_check", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "optd-persistent" -version = "0.1.0" -dependencies = [ - "async-stream", - "async-trait", - "sea-orm", - "sea-orm-migration", - "serde_json", - "strum", - "tokio", - "trait-variant", -] - -[[package]] -name = "ordered-float" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ouroboros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c86de06555b970aec45229b27291b53154f21a5743a163419f4e4c0b065dcde" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3633d65683f13b9bcfaa3150880b018899fb0e5d0542f4adaea4f503fdb5eabf" -dependencies = [ - "heck 0.4.1", - "itertools 0.12.0", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f4f894f3865f6c0e02810fc597300f34dc2510f66400da262d8ae10e75767d" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.29.0", -] - -[[package]] -name = "paste" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pin-project-lite" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" - -[[package]] -name = "proc-macro-error" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d259aa4825fa1a2371419d30a520219feff9fb3591550a209b4477d2ebaae4f" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.98", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd21889899aa8e1ca2b924c1d3f08086631fc90768225b3268b5d5c3e806a503" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", - "syn-mid", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", - "version_check", - "yansi", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" -dependencies = [ - "bitflags 1.1.0", -] - -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom", - "redox_syscall", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72457500f2cf948feb4efccaeb460570c8f66ee5ba33c936bb4bfaa628d71853" -dependencies = [ - "byteorder", - "regex-syntax", - "utf8-ranges", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "ring" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9d44f9bf6b635117787f72416783eb7e4227aaf255e5ce739563d817176a7e" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "rsa" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd2017d3e6d67384f301f8b06fbf4567afc576430a61624d845eb04d2b30a72" -dependencies = [ - "byteorder", - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "subtle", - "zeroize", -] - -[[package]] -name = "rust_decimal" -version = "1.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" -dependencies = [ - "arrayvec", - "num-traits", - "serde", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.23.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" -dependencies = [ - "base64 0.21.0", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustls-webpki" -version = "0.102.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "ryu" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69" - -[[package]] -name = "sea-bae" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" -dependencies = [ - "heck 0.4.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "sea-orm" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5680a8b686985116607ef5f5af2b1f9e1cc2c228330e93101816a0baa279afa" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "futures", - "log", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum", - "thiserror", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sea-orm-cli" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "tracing", - "tracing-subscriber", - "url", -] - -[[package]] -name = "sea-orm-macros" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a239e3bb1b566ad4ec2654d0d193d6ceddfd733487edc9c21a64d214c773910" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.52", - "unicode-ident", -] - -[[package]] -name = "sea-orm-migration" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" -dependencies = [ - "async-trait", - "clap", - "dotenvy", - "futures", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "sea-query" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" -dependencies = [ - "bigdecimal", - "chrono", - "inherent", - "ordered-float", - "rust_decimal", - "sea-query-derive", - "serde_json", - "time", - "uuid", -] - -[[package]] -name = "sea-query-binder" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" -dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time", - "uuid", -] - -[[package]] -name = "sea-query-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.52", - "thiserror", -] - -[[package]] -name = "sea-schema" -version = "0.16.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a4ff9e87c4340affbec4f7790d724dcd87e71fcd0ffe2247481843380485aa" -dependencies = [ - "futures", - "sea-query", - "sea-schema-derive", -] - -[[package]] -name = "sea-schema-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "serde" -version = "1.0.194" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.194" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "serde_json" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" -dependencies = [ - "itoa 1.0.1", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" -dependencies = [ - "form_urlencoded", - "itoa 0.4.0", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signature" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" -dependencies = [ - "serde", -] - -[[package]] -name = "socket2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "spin" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" -dependencies = [ - "itertools 0.10.0", - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" -dependencies = [ - "atoi", - "bigdecimal", - "byteorder", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown", - "hashlink", - "hex", - "indexmap", - "log", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rust_decimal", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlformat", - "thiserror", - "time", - "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", - "webpki-roots", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.52", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.52", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" -dependencies = [ - "atoi", - "base64 0.22.0", - "bigdecimal", - "bitflags 2.4.0", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa 1.0.1", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand", - "rsa", - "rust_decimal", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" -dependencies = [ - "atoi", - "base64 0.22.0", - "bigdecimal", - "bitflags 2.4.0", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa 1.0.1", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "rand", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" -dependencies = [ - "atoi", - "chrono", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "serde_urlencoded", - "sqlx-core", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn-mid" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "termcolor" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a52c023823933499250b43960b272e25336c6e2ab8684672edc34489f049ccdd" -dependencies = [ - "wincolor", -] - -[[package]] -name = "thiserror" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa 1.0.1", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tokio" -version = "1.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "tokio-stream" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "matchers", - "once_cell", - "regex", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "typenum" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" - -[[package]] -name = "unicode-bidi" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560b941fdb9ea38301b9b708504d612fcdf9c91a8c31d82219bd74cb07d304d" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-ident" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" - -[[package]] -name = "unicode-normalization" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" - -[[package]] -name = "unicode-width" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc85732b6d55a0d520aaf765536a188d9d993770c28633422f85bb646da61335" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" -dependencies = [ - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" - -[[package]] -name = "web-sys" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "whoami" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ad91d846a4a5342c1fb7008d26124ee6cf94a3953751618577295373b32117" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a16a8e2ebfc883e2b1771c6482b1fb3c6831eab289ba391619a2d93a7356220f" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca29cb03c8ceaf20f8224a18a530938305e9872b1478ea24ff44b4f503a1d1d" - -[[package]] -name = "wincolor" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9dc3aa9dcda98b5a16150c54619c1ead22e3d3a5d458778ae914be760aa981a" -dependencies = [ - "winapi", -] - -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb069ac8b2117d36924190469735767f0990833935ab430155e71a44bafe148" -dependencies = [ - "windows_aarch64_msvc 0.29.0", - "windows_i686_gnu 0.29.0", - "windows_i686_msvc 0.29.0", - "windows_x86_64_gnu 0.29.0", - "windows_x86_64_msvc 0.29.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[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.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[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.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[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.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[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.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[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.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[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.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "yansi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" - -[[package]] -name = "zerocopy" -version = "0.7.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/optd-persistent/Cargo.toml b/optd-persistent/Cargo.toml deleted file mode 100644 index 50af728..0000000 --- a/optd-persistent/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "optd-persistent" -version = "0.1.0" -edition = "2021" -authors = ["Sarvesh Tandon", "Connor Tsui"] - -[dependencies] -sea-orm = { version = "1.1.1", features = [ - "sqlx-sqlite", - "runtime-tokio-rustls", - "macros", - "debug-print", - "with-json", -] } -sea-orm-migration = "1.0.0" -serde_json = "1.0.118" # Hash implementation on serde_json::Value -tokio = { version = "1.0.1", features = ["macros", "rt-multi-thread"] } -trait-variant = "0.1.2" - -# Pin more recent versions for -Zminimal-versions -async-trait = "0.1.43" -async-stream = "0.3.1" -strum = "0.26.1" -num_enum = "0.7.3" diff --git a/optd-persistent/src/bin/init.rs b/optd-persistent/src/bin/init.rs deleted file mode 100644 index a0b6b25..0000000 --- a/optd-persistent/src/bin/init.rs +++ /dev/null @@ -1,404 +0,0 @@ -use optd_persistent::cost_model::interface::AttrType; -use optd_persistent::cost_model::interface::ConstraintType; -use optd_persistent::cost_model::interface::IndexType; -use optd_persistent::cost_model::interface::StatType; -use optd_persistent::entities::*; -use optd_persistent::migrate; -use optd_persistent::TEST_DATABASE_FILENAME; -use optd_persistent::TEST_DATABASE_URL; -use sea_orm::sqlx::types::chrono::Utc; -use sea_orm::*; -use serde_json::json; - -async fn init_all_tables() -> Result<(), sea_orm::error::DbErr> { - let _ = std::fs::remove_file(TEST_DATABASE_FILENAME); - - let db = Database::connect(TEST_DATABASE_URL.clone()) - .await - .expect("Unable to connect to the database"); - - migrate(&db) - .await - .expect("Something went wrong during migration"); - - // Inserting into database_metadata - let database_metadata = database_metadata::ActiveModel { - id: Set(1), - name: Set("database1".to_owned()), - creation_time: Set(Utc::now()), - }; - database_metadata::Entity::insert(database_metadata) - .exec(&db) - .await - .expect("Unable to insert database metadata"); - - // Inserting into namespace_metadata - let namespace_metadata = namespace_metadata::ActiveModel { - id: Set(1), - database_id: Set(1), - name: Set("default".to_owned()), - creation_time: Set(Utc::now()), - }; - namespace_metadata::Entity::insert(namespace_metadata) - .exec(&db) - .await - .expect("Unable to insert namespace metadata"); - - // Inserting into table_metadata - let table_metadata = table_metadata::ActiveModel { - id: Set(1), - namespace_id: Set(1), - name: Set("users".to_owned()), - creation_time: Set(Utc::now()), - }; - table_metadata::Entity::insert(table_metadata) - .exec(&db) - .await - .expect("Unable to insert table metadata"); - - // Inserting into attribute - let attribute1 = attribute::ActiveModel { - id: Set(1), - table_id: Set(1), - name: Set("user_id".to_owned()), - compression_method: Set("N".to_owned()), - variant_tag: Set(AttrType::Integer as i32), - base_attribute_number: Set(0), - is_not_null: Set(true), - }; - let attribute2 = attribute::ActiveModel { - id: Set(2), - table_id: Set(1), - name: Set("username".to_owned()), - compression_method: Set("N".to_owned()), - variant_tag: Set(AttrType::Varchar as i32), - base_attribute_number: Set(1), - is_not_null: Set(true), - }; - attribute::Entity::insert(attribute1) - .exec(&db) - .await - .expect("Unable to insert attribute"); - attribute::Entity::insert(attribute2) - .exec(&db) - .await - .expect("Unable to insert attribute"); - - // Inserting into event - let event = event::ActiveModel { - epoch_id: Set(1), - source_variant: Set("execution_engine".to_owned()), - timestamp: Set(Utc::now()), - data: Set(json!({"dba": "parpulse"})), - }; - event::Entity::insert(event) - .exec(&db) - .await - .expect("Unable to insert event"); - - // Inserting into statistic - - // Table statistic - let table_statistic = statistic::ActiveModel { - id: Set(1), - name: Set("row_count".to_owned()), - table_id: Set(Some(1)), - creation_time: Set(Utc::now()), - number_of_attributes: Set(0), - variant_tag: Set(StatType::TableRowCount as i32), - description: Set("".to_owned()), - }; - let table_versioned_statistic = versioned_statistic::ActiveModel { - id: Set(1), - epoch_id: Set(1), - statistic_id: Set(1), - statistic_value: Set(json!(0)), - }; - statistic::Entity::insert(table_statistic) - .exec(&db) - .await - .expect("Unable to insert statistic"); - versioned_statistic::Entity::insert(table_versioned_statistic) - .exec(&db) - .await - .expect("Unable to insert versioned statistic"); - - // Single-column attribute statistic - let single_column_attribute_statistic = statistic::ActiveModel { - id: Set(2), - name: Set("cardinality".to_owned()), - table_id: Set(Some(1)), - creation_time: Set(Utc::now()), - number_of_attributes: Set(1), - variant_tag: Set(StatType::Cardinality as i32), - description: Set("1".to_owned()), - }; - let single_column_attribute_versioned_statistic = versioned_statistic::ActiveModel { - id: Set(2), - epoch_id: Set(1), - statistic_id: Set(2), - statistic_value: Set(json!(0)), - }; - statistic::Entity::insert(single_column_attribute_statistic) - .exec(&db) - .await - .expect("Unable to insert statistic"); - versioned_statistic::Entity::insert(single_column_attribute_versioned_statistic) - .exec(&db) - .await - .expect("Unable to insert versioned statistic"); - - let single_column_statistic_to_attribute_junction = - statistic_to_attribute_junction::ActiveModel { - statistic_id: Set(2), // cardinality - attribute_id: Set(1), // user_id - }; - statistic_to_attribute_junction::Entity::insert(single_column_statistic_to_attribute_junction) - .exec(&db) - .await - .expect("Unable to insert statistic_to_attribute_junction"); - - // Multi-column attribute statistic - let multi_column_attribute_statistic = statistic::ActiveModel { - id: Set(3), - name: Set("joint_cardinality".to_owned()), - table_id: Set(Some(1)), - creation_time: Set(Utc::now()), - number_of_attributes: Set(2), - variant_tag: Set(StatType::Cardinality as i32), - description: Set("1,2".to_owned()), - }; - let multi_column_attribute_versioned_statistic = versioned_statistic::ActiveModel { - id: Set(3), - epoch_id: Set(1), - statistic_id: Set(3), - statistic_value: Set(json!(0)), - }; - statistic::Entity::insert(multi_column_attribute_statistic) - .exec(&db) - .await - .expect("Unable to insert statistic"); - versioned_statistic::Entity::insert(multi_column_attribute_versioned_statistic) - .exec(&db) - .await - .expect("Unable to insert versioned statistic"); - - let multi_column_statistic_to_attribute_junction1 = - statistic_to_attribute_junction::ActiveModel { - statistic_id: Set(3), // joint cardinality - attribute_id: Set(1), // user_id - }; - let multi_column_statistic_to_attribute_junction2 = - statistic_to_attribute_junction::ActiveModel { - statistic_id: Set(3), // joint cardinality - attribute_id: Set(2), // username - }; - statistic_to_attribute_junction::Entity::insert(multi_column_statistic_to_attribute_junction1) - .exec(&db) - .await - .expect("Unable to insert statistic_to_attribute_junction"); - statistic_to_attribute_junction::Entity::insert(multi_column_statistic_to_attribute_junction2) - .exec(&db) - .await - .expect("Unable to insert statistic_to_attribute_junction"); - - // Inserting into index_metadata - let index_metadata = index_metadata::ActiveModel { - id: Set(1), - name: Set("user_id_index".to_owned()), - table_id: Set(1), - is_unique: Set(true), - nulls_not_distinct: Set(false), - is_primary: Set(true), - is_clustered: Set(false), - is_exclusion: Set(false), - variant_tag: Set(IndexType::Hash as i32), - number_of_attributes: Set(1), - description: Set("1".to_owned()), - }; - index_metadata::Entity::insert(index_metadata) - .exec(&db) - .await - .expect("Unable to insert index metadata"); - - // Inserting into trigger - let trigger = trigger::ActiveModel { - id: Set(1), - name: Set("after_insert_user".to_owned()), - table_id: Set(1), - parent_trigger_id: Set(1), - function: Set(json!(r#"{"function": "insert"}"#)), - }; - trigger::Entity::insert(trigger) - .exec(&db) - .await - .expect("Unable to insert trigger"); - - // Inserting into constraint_metadata - let constraint_metadata = constraint_metadata::ActiveModel { - id: Set(1), - name: Set("pk_user_id".to_owned()), - variant_tag: Set(ConstraintType::PrimaryKey as i32), - table_id: Set(Some(1)), - index_id: Set(Some(1)), - foreign_ref_id: Set(None), - check_src: Set("hello".to_owned()), - }; - constraint_metadata::Entity::insert(constraint_metadata) - .exec(&db) - .await - .expect("Unable to insert constraint metadata"); - - // Inserting into attribute_constraint_junction - let attribute_constraint_junction = attribute_constraint_junction::ActiveModel { - attribute_id: Set(1), - constraint_id: Set(1), - }; - attribute_constraint_junction::Entity::insert(attribute_constraint_junction) - .exec(&db) - .await - .expect("Unable to insert attribute_constraint_junction"); - - // Inserting into attribute_foreign_constraint_junction - let attribute_foreign_constraint_junction = - attribute_foreign_constraint_junction::ActiveModel { - attribute_id: Set(1), - constraint_id: Set(1), - }; - attribute_foreign_constraint_junction::Entity::insert(attribute_foreign_constraint_junction) - .exec(&db) - .await - .expect("Unable to insert attribute_foreign_constraint_junction"); - - // Inserting into cascades_group - let cascades_group = cascades_group::ActiveModel { - id: Set(1), - latest_winner: Set(None), - in_progress: Set(true), - is_optimized: Set(false), - }; - cascades_group::Entity::insert(cascades_group) - .exec(&db) - .await - .expect("Unable to insert cascades group"); - - // Inserting into logical_expression - let logical_expression = logical_expression::ActiveModel { - id: Set(1), - group_id: Set(1), - fingerprint: Set(12345), - variant_tag: Set(0), - data: Set(json!(r#"{"expr": "index_scan"}"#)), - }; - logical_expression::Entity::insert(logical_expression) - .exec(&db) - .await - .expect("Unable to insert logical expression"); - - // Inserting into physical_expression - let physical_expression = physical_expression::ActiveModel { - id: Set(1), - group_id: Set(1), - fingerprint: Set(12345), - variant_tag: Set(0), - data: Set(json!(r#"{"expr": "index_scan"}"#)), - }; - physical_expression::Entity::insert(physical_expression) - .exec(&db) - .await - .expect("Unable to insert physical expression"); - - // Inserting into physical_property - let physical_property = physical_property::ActiveModel { - id: Set(1), - physical_expression_id: Set(1), - variant_tag: Set(0), - data: Set(json!(r#"{"property": "indexed"}"#)), - }; - physical_property::Entity::insert(physical_property) - .exec(&db) - .await - .expect("Unable to insert physical property"); - - // Inserting into logical_property - let logical_property = logical_property::ActiveModel { - id: Set(1), - group_id: Set(1), - variant_tag: Set(0), - data: Set(json!(r#"{"property": "indexed"}"#)), - }; - logical_property::Entity::insert(logical_property) - .exec(&db) - .await - .expect("Unable to insert logical property"); - - let logical_children = logical_children::ActiveModel { - logical_expression_id: Set(1), - group_id: Set(1), - }; - logical_children::Entity::insert(logical_children) - .exec(&db) - .await - .expect("Unable to insert logical children"); - - let physical_children = physical_children::ActiveModel { - physical_expression_id: Set(1), - group_id: Set(1), - }; - physical_children::Entity::insert(physical_children) - .exec(&db) - .await - .expect("Unable to insert physical children"); - - // Inserting into plan_cost - let plan_cost = plan_cost::ActiveModel { - id: Set(1), - physical_expression_id: Set(1), - epoch_id: Set(1), - cost: Set(Some(json!({"compute_cost":10, "io_cost":10}))), - estimated_statistic: Set(Some(10.0)), - is_valid: Set(true), - }; - plan_cost::Entity::insert(plan_cost) - .exec(&db) - .await - .expect("Unable to insert plan cost"); - - // Inserting into physical_expression_to_statistic_junction - let physical_expression_to_statistic_junction = - physical_expression_to_statistic_junction::ActiveModel { - physical_expression_id: Set(1), - statistic_id: Set(1), - }; - physical_expression_to_statistic_junction::Entity::insert( - physical_expression_to_statistic_junction, - ) - .exec(&db) - .await - .expect("Unable to insert physical_expression_to_statistic_junction"); - - // Inserting into group_winner - let group_winner = group_winner::ActiveModel { - id: Set(1), - group_id: Set(1), - physical_expression_id: Set(1), - cost_id: Set(1), - epoch_id: Set(1), - }; - group_winner::Entity::insert(group_winner) - .exec(&db) - .await - .expect("Unable to insert group winner"); - - Ok(()) -} - -#[tokio::main] -async fn main() { - if let Err(e) = init_all_tables().await { - eprintln!("Error initializing database: {}", e); - std::process::exit(1); - } - - println!("Database initialized successfully"); -} diff --git a/optd-persistent/src/cost_model/catalog/mock_catalog.rs b/optd-persistent/src/cost_model/catalog/mock_catalog.rs deleted file mode 100644 index 5b2e28e..0000000 --- a/optd-persistent/src/cost_model/catalog/mock_catalog.rs +++ /dev/null @@ -1,165 +0,0 @@ -use sea_orm::prelude::Json; -use serde_json::json; - -use crate::cost_model::interface::{AttrType, IndexType, StatType}; - -/// TODO: documentation -pub struct MockDatabaseMetadata { - pub id: i32, - pub name: String, -} - -pub struct MockNamespaceMetadata { - pub id: i32, - pub name: String, - pub database_id: i32, -} - -pub struct MockTableMetadata { - pub id: i32, - pub name: String, - pub namespace_id: i32, -} - -pub struct MockAttribute { - pub id: i32, - pub name: String, - pub attr_index: i32, - pub table_id: i32, - pub compression_method: char, - pub attr_type: i32, - pub is_not_null: bool, -} - -pub struct MockStatistic { - pub id: i32, - pub stat_type: i32, - pub stat_value: Json, - pub attr_ids: Vec, - pub table_id: Option, - pub name: String, -} - -pub struct MockIndex { - pub id: i32, - pub name: String, - pub table_id: i32, - pub number_of_attributes: i32, - pub index_type: i32, - pub is_unique: bool, - pub nulls_not_distinct: bool, - pub is_primary: bool, - pub is_clustered: bool, - pub is_exclusion: bool, - pub attr_ids: Vec, -} - -pub struct MockTrigger { - pub id: i32, - pub name: String, - pub table_id: i32, - pub parent_trigger_id: i32, - pub function: String, -} - -/// TODO: documentation -#[derive(Default)] -pub struct MockCatalog { - pub databases: Vec, - pub namespaces: Vec, - pub tables: Vec, - pub attributes: Vec, - pub statistics: Vec, - pub indexes: Vec, - pub triggers: Vec, - // TODO: constraints -} - -impl MockCatalog { - /// TODO: documentation - pub fn new() -> Self { - let databases: Vec = vec![MockDatabaseMetadata { - id: 1, - name: "db1".to_string(), - }]; - let namespaces: Vec = vec![MockNamespaceMetadata { - id: 1, - name: "ns1".to_string(), - database_id: 1, - }]; - let tables: Vec = vec![MockTableMetadata { - id: 1, - name: "table1".to_string(), - namespace_id: 1, - }]; - let attributes: Vec = vec![ - MockAttribute { - id: 1, - name: "attr1".to_string(), - attr_index: 1, - table_id: 1, - compression_method: 'n', - attr_type: AttrType::Integer as i32, - is_not_null: true, - }, - MockAttribute { - id: 2, - name: "attr2".to_string(), - attr_index: 2, - table_id: 1, - compression_method: 'n', - attr_type: AttrType::Integer as i32, - is_not_null: false, - }, - ]; - let statistics: Vec = vec![ - MockStatistic { - id: 1, - stat_type: StatType::NonNullCount as i32, - stat_value: json!(100), - attr_ids: vec![1], - table_id: None, - name: "CountAttr1".to_string(), - }, - MockStatistic { - id: 2, - stat_type: StatType::NonNullCount as i32, - stat_value: json!(200), - attr_ids: vec![2], - table_id: None, - name: "CountAttr2".to_string(), - }, - MockStatistic { - id: 3, - stat_type: StatType::TableRowCount as i32, - stat_value: json!(300), - attr_ids: vec![], - table_id: Some(1), - name: "Table1Count".to_string(), - }, - ]; - let indexes: Vec = vec![MockIndex { - id: 1, - name: "index1".to_string(), - table_id: 1, - number_of_attributes: 1, - index_type: IndexType::Hash as i32, - is_unique: false, - nulls_not_distinct: false, - is_primary: true, - is_clustered: false, - is_exclusion: false, - attr_ids: vec![1], - }]; - - MockCatalog { - databases, - namespaces, - tables, - attributes, - statistics, - indexes, - triggers: vec![], - } - } -} diff --git a/optd-persistent/src/cost_model/catalog/mod.rs b/optd-persistent/src/cost_model/catalog/mod.rs deleted file mode 100644 index 4df69d8..0000000 --- a/optd-persistent/src/cost_model/catalog/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod mock_catalog; diff --git a/optd-persistent/src/cost_model/interface.rs b/optd-persistent/src/cost_model/interface.rs deleted file mode 100644 index e4e4ceb..0000000 --- a/optd-persistent/src/cost_model/interface.rs +++ /dev/null @@ -1,177 +0,0 @@ -#![allow(dead_code, unused_imports)] - -use crate::entities::cascades_group; -use crate::entities::logical_expression; -use crate::entities::physical_expression; -use crate::StorageResult; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use sea_orm::prelude::Json; -use sea_orm::*; -use sea_orm_migration::prelude::*; -use serde_json::json; -use std::sync::Arc; - -pub type GroupId = i32; -pub type TableId = i32; -pub type AttrId = i32; -pub type ExprId = i32; -pub type EpochId = i32; -pub type StatId = i32; -pub type AttrIndex = i32; - -/// TODO: documentation -pub enum CatalogSource { - Iceberg(), - Mock, -} - -/// TODO: documentation -#[repr(i32)] -#[derive(Copy, Clone, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] -pub enum AttrType { - Integer = 1, - Float, - Varchar, - Boolean, -} - -/// TODO: documentation -pub enum IndexType { - BTree, - Hash, -} - -/// TODO: documentation -pub enum ConstraintType { - PrimaryKey, - ForeignKey, - Unique, - Check, -} - -/// TODO: documentation -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum StatType { - /// The row count in a table. `TableRowCount` only applies to table statistics. - TableRowCount, - /// The number of non-null values in a column. - NonNullCount, - /// The number of distinct values in a column. - Cardinality, - /// The minimum value in a column. - Min, - /// The maximum value in a column. - Max, - /// The frequency of each value in a column. - MostCommonValues, - /// The distribution of values in a column. - Distribution, -} - -/// TODO: documentation -#[derive(PartialEq)] -pub enum EpochOption { - // TODO(lanlou): Could I make i32 -> EpochId? - Existed(i32), - New(String, String), -} - -/// TODO: documentation -#[derive(Clone, Debug)] -pub struct Stat { - pub stat_type: StatType, - pub stat_value: Json, - pub attr_ids: Vec, - pub table_id: Option, - pub name: String, -} - -/// TODO: documentation -#[derive(Clone, Debug, PartialEq)] -pub struct Cost { - pub compute_cost: f64, - pub io_cost: f64, -} - -#[derive(Clone, Debug)] -pub struct Attr { - pub table_id: i32, - pub name: String, - pub compression_method: String, - pub attr_type: AttrType, - pub base_index: i32, - pub nullable: bool, -} - -/// TODO: documentation -#[trait_variant::make(Send)] -pub trait CostModelStorageLayer { - async fn create_new_epoch(&self, source: String, data: String) -> StorageResult; - - async fn update_stats_from_catalog(&self, c: CatalogSource) -> StorageResult; - - async fn update_stats( - &self, - stat: Stat, - epoch_option: EpochOption, - ) -> StorageResult>; - - async fn store_cost( - &self, - expr_id: ExprId, - cost: Option, - estimated_statistic: Option, - epoch_id: Option, - ) -> StorageResult<()>; - - async fn store_expr_stats_mappings( - &self, - expr_id: ExprId, - stat_ids: Vec, - ) -> StorageResult<()>; - - /// Get the statistics for a given table. - /// - /// If `epoch_id` is None, it will return the latest statistics. - async fn get_stats_for_table( - &self, - table_id: TableId, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult>; - - /// Get the (joint) statistics for one or more attributes. - /// - /// If `epoch_id` is None, it will return the latest statistics. - async fn get_stats_for_attr( - &self, - attr_ids: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult>; - - /// Get the (joint) statistics for one or more attributes based on attribute base indices. - /// - /// If `epoch_id` is None, it will return the latest statistics. - async fn get_stats_for_attr_indices_based( - &self, - table_id: TableId, - attr_base_indices: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult>; - - async fn get_cost_analysis( - &self, - expr_id: ExprId, - epoch_id: EpochId, - ) -> StorageResult<(Option, Option)>; - - async fn get_cost(&self, expr_id: ExprId) -> StorageResult<(Option, Option)>; - - async fn get_attribute( - &self, - table_id: TableId, - attribute_base_index: AttrIndex, - ) -> StorageResult>; -} diff --git a/optd-persistent/src/cost_model/mod.rs b/optd-persistent/src/cost_model/mod.rs deleted file mode 100644 index 46514a1..0000000 --- a/optd-persistent/src/cost_model/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod catalog; - -pub mod interface; -pub mod orm; diff --git a/optd-persistent/src/cost_model/orm.rs b/optd-persistent/src/cost_model/orm.rs deleted file mode 100644 index 74c03f1..0000000 --- a/optd-persistent/src/cost_model/orm.rs +++ /dev/null @@ -1,1478 +0,0 @@ -#![allow(dead_code, unused_imports, unused_variables)] - -use crate::cost_model::interface::Cost; -use crate::entities::{prelude::*, *}; -use crate::{BackendError, BackendManager, CostModelStorageLayer, StorageResult}; -use sea_orm::prelude::{Expr, Json}; -use sea_orm::sea_query::{ExprTrait, Query}; -use sea_orm::{sqlx::types::chrono::Utc, EntityTrait}; -use sea_orm::{ - ActiveModelTrait, ColumnTrait, Condition, DbBackend, DbErr, DeleteResult, EntityOrSelect, - ModelTrait, QueryFilter, QueryOrder, QuerySelect, QueryTrait, RuntimeErr, TransactionTrait, -}; -use serde_json::json; - -use super::catalog::mock_catalog::{self, MockCatalog}; -use super::interface::{ - Attr, AttrId, AttrIndex, AttrType, CatalogSource, EpochId, EpochOption, ExprId, Stat, StatId, - StatType, TableId, -}; - -impl BackendManager { - /// The description is to concat `attr_ids` using commas - /// Note that `attr_ids` should be sorted before concatenation - /// e.g. [1, 2, 3] -> "1,2,3" - fn get_description_from_attr_ids(&self, mut attr_ids: Vec) -> String { - attr_ids.sort(); - attr_ids - .iter() - .map(|id| id.to_string()) - .collect::>() - .join(",") - } -} - -impl CostModelStorageLayer for BackendManager { - /// TODO: documentation - async fn create_new_epoch(&self, source: String, data: String) -> StorageResult { - let new_event = event::ActiveModel { - source_variant: sea_orm::ActiveValue::Set(source), - timestamp: sea_orm::ActiveValue::Set(Utc::now()), - data: sea_orm::ActiveValue::Set(sea_orm::JsonValue::String(data)), - ..Default::default() - }; - let insert_res = Event::insert(new_event).exec(&self.db).await?; - Ok(insert_res.last_insert_id) - } - - /// TODO: documentation - async fn update_stats_from_catalog(&self, c: CatalogSource) -> StorageResult { - let transaction = self.db.begin().await?; - let source = match c { - CatalogSource::Mock => "Mock", - CatalogSource::Iceberg() => "Iceberg", - }; - let new_event = event::ActiveModel { - source_variant: sea_orm::ActiveValue::Set(source.to_string()), - timestamp: sea_orm::ActiveValue::Set(Utc::now()), - data: sea_orm::ActiveValue::Set(sea_orm::JsonValue::String( - "Update stats from catalog".to_string(), - )), - ..Default::default() - }; - let epoch_id = Event::insert(new_event) - .exec(&transaction) - .await? - .last_insert_id; - match c { - CatalogSource::Mock => { - let mock_catalog = MockCatalog::new(); - DatabaseMetadata::insert_many(mock_catalog.databases.iter().map(|database| { - database_metadata::ActiveModel { - name: sea_orm::ActiveValue::Set(database.name.clone()), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - NamespaceMetadata::insert_many(mock_catalog.namespaces.iter().map(|namespace| { - namespace_metadata::ActiveModel { - name: sea_orm::ActiveValue::Set(namespace.name.clone()), - database_id: sea_orm::ActiveValue::Set(namespace.database_id), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - TableMetadata::insert_many(mock_catalog.tables.iter().map(|table| { - table_metadata::ActiveModel { - name: sea_orm::ActiveValue::Set(table.name.clone()), - namespace_id: sea_orm::ActiveValue::Set(table.namespace_id), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - Attribute::insert_many(mock_catalog.attributes.iter().map(|attr| { - attribute::ActiveModel { - table_id: sea_orm::ActiveValue::Set(attr.table_id), - name: sea_orm::ActiveValue::Set(attr.name.clone()), - compression_method: sea_orm::ActiveValue::Set( - attr.compression_method.to_string(), - ), - variant_tag: sea_orm::ActiveValue::Set(attr.attr_type), - base_attribute_number: sea_orm::ActiveValue::Set(attr.attr_index), - is_not_null: sea_orm::ActiveValue::Set(attr.is_not_null), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - Statistic::insert_many(mock_catalog.statistics.iter().map(|stat| { - statistic::ActiveModel { - name: sea_orm::ActiveValue::Set(stat.name.clone()), - table_id: sea_orm::ActiveValue::Set(stat.table_id), - number_of_attributes: sea_orm::ActiveValue::Set(stat.attr_ids.len() as i32), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - variant_tag: sea_orm::ActiveValue::Set(stat.stat_type), - description: sea_orm::ActiveValue::Set( - self.get_description_from_attr_ids(stat.attr_ids.clone()), - ), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - VersionedStatistic::insert_many(mock_catalog.statistics.iter().map(|stat| { - versioned_statistic::ActiveModel { - epoch_id: sea_orm::ActiveValue::Set(epoch_id), - statistic_id: sea_orm::ActiveValue::Set(stat.id), - statistic_value: sea_orm::ActiveValue::Set(stat.stat_value.clone()), - ..Default::default() - } - })) - .exec(&transaction) - .await?; - StatisticToAttributeJunction::insert_many(mock_catalog.statistics.iter().flat_map( - |stat| { - stat.attr_ids.iter().map(move |attr_id| { - statistic_to_attribute_junction::ActiveModel { - statistic_id: sea_orm::ActiveValue::Set(stat.id), - attribute_id: sea_orm::ActiveValue::Set(*attr_id), - } - }) - }, - )) - .exec(&transaction) - .await?; - IndexMetadata::insert_many( - mock_catalog - .indexes - .iter() - .map(|index| index_metadata::ActiveModel { - name: sea_orm::ActiveValue::Set(index.name.clone()), - table_id: sea_orm::ActiveValue::Set(index.table_id), - number_of_attributes: sea_orm::ActiveValue::Set( - index.attr_ids.len() as i32 - ), - variant_tag: sea_orm::ActiveValue::Set(index.index_type), - is_unique: sea_orm::ActiveValue::Set(index.is_unique), - nulls_not_distinct: sea_orm::ActiveValue::Set(index.nulls_not_distinct), - is_primary: sea_orm::ActiveValue::Set(index.is_primary), - is_clustered: sea_orm::ActiveValue::Set(index.is_clustered), - is_exclusion: sea_orm::ActiveValue::Set(index.is_exclusion), - description: sea_orm::ActiveValue::Set( - self.get_description_from_attr_ids(index.attr_ids.clone()), - ), - ..Default::default() - }), - ) - .exec(&transaction) - .await?; - // TODO: initialize constraints - } - CatalogSource::Iceberg() => todo!(), - } - transaction.commit().await?; - Ok(epoch_id) - } - - /// TODO: improve the documentation - /* Update the statistics in the database. - * The statistic can be newly inserted or updated. If the statistic value - * is the same as the latest existing one, the update will be ignored, and - * the return value will be None. - * If `epoch_option` is `EpochOption::Existed(epoch_id)`, the new statistic - * will be associated with the given epoch_id. If `epoch_option` is - * `EpochOption::New(source, data)`, a new epoch will be created with the - * given source and data, and the new statistic will be associated with the - * new epoch. And return the new epoch_id. - * If the statistic value is the same as the latest existing one, this function - * won't create a new epoch. - * - * For batch updates, the caller can directly call this function with - * New epoch option at the first time, and if the epoch_id is returned, the - * caller can use the returned epoch_id for the rest of the updates. - * But if the epoch_id is not returned, the caller should continue using - * the New epoch option for the next statistic update. - */ - async fn update_stats( - &self, - stat: Stat, - epoch_option: EpochOption, - ) -> StorageResult> { - let transaction = self.db.begin().await?; - // 0. Check if the stat already exists. If exists, get stat_id, else insert into statistic table. - let stat_id = match stat.table_id { - Some(table_id) => { - // TODO: only select needed fields - let res = Statistic::find() - .filter(statistic::Column::TableId.eq(table_id)) - .inner_join(versioned_statistic::Entity) - .select_also(versioned_statistic::Entity) - .order_by_desc(versioned_statistic::Column::EpochId) - .one(&transaction) - .await?; - match res { - Some(stat_data) => { - if stat_data.1.unwrap().statistic_value == stat.stat_value { - return Ok(None); - } - stat_data.0.id - } - None => { - let new_stat = statistic::ActiveModel { - name: sea_orm::ActiveValue::Set(stat.name.clone()), - table_id: sea_orm::ActiveValue::Set(Some(table_id)), - number_of_attributes: sea_orm::ActiveValue::Set( - stat.attr_ids.len() as i32 - ), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - variant_tag: sea_orm::ActiveValue::Set(stat.stat_type as i32), - description: sea_orm::ActiveValue::Set("".to_string()), - ..Default::default() - }; - let res = Statistic::insert(new_stat).exec(&transaction).await; - match res { - Ok(insert_res) => insert_res.last_insert_id, - Err(_) => { - return Err(BackendError::CostModel( - format!( - "failed to insert statistic {:?} into statistic table", - stat - ) - .into(), - )) - } - } - } - } - } - None => { - let description = self.get_description_from_attr_ids(stat.attr_ids.clone()); - let res = Statistic::find() - .filter(statistic::Column::NumberOfAttributes.eq(stat.attr_ids.len() as i32)) - .filter(statistic::Column::Description.eq(description.clone())) - .filter(statistic::Column::VariantTag.eq(stat.stat_type as i32)) - .inner_join(versioned_statistic::Entity) - .select_also(versioned_statistic::Entity) - .order_by_desc(versioned_statistic::Column::EpochId) - .one(&transaction) - .await?; - match res { - Some(stat_data) => { - if stat_data.1.unwrap().statistic_value == stat.stat_value { - return Ok(None); - } - stat_data.0.id - } - None => { - let new_stat = statistic::ActiveModel { - name: sea_orm::ActiveValue::Set(stat.name.clone()), - number_of_attributes: sea_orm::ActiveValue::Set( - stat.attr_ids.len() as i32 - ), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - variant_tag: sea_orm::ActiveValue::Set(stat.stat_type as i32), - description: sea_orm::ActiveValue::Set(description), - ..Default::default() - }; - // TODO(lanlou): we should not clone here maybe... - let insert_res = Statistic::insert(new_stat.clone()) - .exec(&transaction) - .await?; - for attr_id in stat.attr_ids { - let new_junction = statistic_to_attribute_junction::ActiveModel { - statistic_id: sea_orm::ActiveValue::Set(insert_res.last_insert_id), - attribute_id: sea_orm::ActiveValue::Set(attr_id), - }; - let res = StatisticToAttributeJunction::insert(new_junction) - .exec(&transaction) - .await?; - } - insert_res.last_insert_id - } - } - } - }; - // 1. Insert into attr_stats and related junction tables. - let epoch_id = match epoch_option { - EpochOption::Existed(e) => e, - EpochOption::New(source, data) => { - let new_event = event::ActiveModel { - source_variant: sea_orm::ActiveValue::Set(source), - timestamp: sea_orm::ActiveValue::Set(Utc::now()), - data: sea_orm::ActiveValue::Set(sea_orm::JsonValue::String(data)), - ..Default::default() - }; - let insert_res = Event::insert(new_event).exec(&transaction).await?; - insert_res.last_insert_id - } - }; - let new_stats = versioned_statistic::ActiveModel { - epoch_id: sea_orm::ActiveValue::Set(epoch_id), - statistic_id: sea_orm::ActiveValue::Set(stat_id), - statistic_value: sea_orm::ActiveValue::Set(stat.stat_value), - ..Default::default() - }; - let _ = VersionedStatistic::insert(new_stats) - .exec(&transaction) - .await?; - - // 2. Invalidate all the related cost. - let _ = plan_cost::Entity::update_many() - .col_expr(plan_cost::Column::IsValid, Expr::value(false)) - .filter(plan_cost::Column::IsValid.eq(true)) - .filter(plan_cost::Column::EpochId.lt(epoch_id)) - .filter( - plan_cost::Column::PhysicalExpressionId.in_subquery( - Query::select() - .column( - physical_expression_to_statistic_junction::Column::PhysicalExpressionId, - ) - .from(physical_expression_to_statistic_junction::Entity) - .cond_where( - physical_expression_to_statistic_junction::Column::StatisticId - .eq(stat_id), - ) - .to_owned(), - ), - ) - .exec(&transaction) - .await?; - - transaction.commit().await?; - Ok(Some(epoch_id)) - } - - /// TODO: documentation - async fn store_expr_stats_mappings( - &self, - expr_id: ExprId, - stat_ids: Vec, - ) -> StorageResult<()> { - let to_insert_mappings = stat_ids - .iter() - .map( - |stat_id| physical_expression_to_statistic_junction::ActiveModel { - physical_expression_id: sea_orm::ActiveValue::Set(expr_id), - statistic_id: sea_orm::ActiveValue::Set(*stat_id), - }, - ) - .collect::>(); - let _ = PhysicalExpressionToStatisticJunction::insert_many(to_insert_mappings) - .exec(&self.db) - .await?; - Ok(()) - } - - /// TODO: documentation - async fn get_stats_for_table( - &self, - table_id: TableId, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult> { - match epoch_id { - Some(epoch_id) => Ok(VersionedStatistic::find() - .filter(versioned_statistic::Column::EpochId.eq(epoch_id)) - .inner_join(statistic::Entity) - .filter(statistic::Column::TableId.eq(table_id)) - .filter(statistic::Column::VariantTag.eq(stat_type as i32)) - .one(&self.db) - .await? - .map(|stat| stat.statistic_value)), - - None => Ok(VersionedStatistic::find() - .inner_join(statistic::Entity) - .filter(statistic::Column::TableId.eq(table_id)) - .filter(statistic::Column::VariantTag.eq(stat_type as i32)) - .order_by_desc(versioned_statistic::Column::EpochId) - .one(&self.db) - .await? - .map(|stat| stat.statistic_value)), - } - } - - /// TODO: documentation - async fn get_stats_for_attr( - &self, - mut attr_ids: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult> { - let attr_num = attr_ids.len() as i32; - attr_ids.sort(); - let description = self.get_description_from_attr_ids(attr_ids); - - // We don't join with junction table here for faster lookup. - match epoch_id { - Some(epoch_id) => Ok(VersionedStatistic::find() - .filter(versioned_statistic::Column::EpochId.eq(epoch_id)) - .inner_join(statistic::Entity) - .filter(statistic::Column::NumberOfAttributes.eq(attr_num)) - .filter(statistic::Column::Description.eq(description)) - .filter(statistic::Column::VariantTag.eq(stat_type as i32)) - .one(&self.db) - .await? - .map(|stat| stat.statistic_value)), - - None => Ok(VersionedStatistic::find() - .inner_join(statistic::Entity) - .filter(statistic::Column::NumberOfAttributes.eq(attr_num)) - .filter(statistic::Column::Description.eq(description)) - .filter(statistic::Column::VariantTag.eq(stat_type as i32)) - .order_by_desc(versioned_statistic::Column::EpochId) - .one(&self.db) - .await? - .map(|stat| stat.statistic_value)), - } - } - - async fn get_stats_for_attr_indices_based( - &self, - table_id: TableId, - attr_base_indices: Vec, - stat_type: StatType, - epoch_id: Option, - ) -> StorageResult> { - // Get the attribute ids based on table id and attribute base indices - let mut condition = Condition::any(); - for attr_base_index in &attr_base_indices { - condition = condition.add(attribute::Column::BaseAttributeNumber.eq(*attr_base_index)); - } - let attr_ids = Attribute::find() - .filter(attribute::Column::TableId.eq(table_id)) - .filter(condition) - .all(&self.db) - .await? - .iter() - .map(|attr| attr.id) - .collect::>(); - - if attr_ids.len() != attr_base_indices.len() { - return Err(BackendError::CostModel( - format!( - "Not all attributes found for table_id {} and base indices {:?}", - table_id, attr_base_indices - ) - .into(), - )); - } - - self.get_stats_for_attr(attr_ids, stat_type, epoch_id).await - } - - /// TODO: documentation - /// Each record in the `plan_cost` table can contain either the cost or the estimated statistic - /// or both, but never neither. - /// The name can be misleading, since it can also return the estimated statistic. - async fn get_cost_analysis( - &self, - expr_id: ExprId, - epoch_id: EpochId, - ) -> StorageResult<(Option, Option)> { - let cost = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(expr_id)) - .filter(plan_cost::Column::EpochId.eq(epoch_id)) - .one(&self.db) - .await?; - // When this cost is not found, we should return None - if cost.is_none() { - return Ok((None, None)); - } - - let real_cost = cost.as_ref().and_then(|c| c.cost.as_ref()).map(|c| Cost { - compute_cost: c.get("compute_cost").unwrap().as_f64().unwrap(), - io_cost: c.get("io_cost").unwrap().as_f64().unwrap(), - }); - - Ok((real_cost, cost.unwrap().estimated_statistic)) - } - - /// TODO: documentation - /// It returns the cost and estimated statistic if applicable. - /// Each record in the `plan_cost` table can contain either the cost or the estimated statistic - /// or both, but never neither. - /// The name can be misleading, since it can also return the estimated statistic. - async fn get_cost(&self, expr_id: ExprId) -> StorageResult<(Option, Option)> { - let cost = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(expr_id)) - .order_by_desc(plan_cost::Column::EpochId) - .one(&self.db) - .await?; - // When this cost is invalid or not found, we should return None - if cost.is_none() || !cost.clone().unwrap().is_valid { - return Ok((None, None)); - } - - let real_cost = cost.as_ref().and_then(|c| c.cost.as_ref()).map(|c| Cost { - compute_cost: c.get("compute_cost").unwrap().as_f64().unwrap(), - io_cost: c.get("io_cost").unwrap().as_f64().unwrap(), - }); - - Ok((real_cost, cost.unwrap().estimated_statistic)) - } - - /// This method should handle the case when the cost is already stored. - /// The name maybe misleading, since it can also store the estimated statistic. - /// If epoch_id is none, we pick the latest epoch_id. - /// - /// TODO: consider whether we need to pass the epoch_id here. When the epoch is - /// stale because someone else updates the stats while we're still computing cost, - /// what is the expected behavior? - /// - /// TODO: documentation - async fn store_cost( - &self, - physical_expression_id: ExprId, - cost: Option, - estimated_statistic: Option, - epoch_id: Option, - ) -> StorageResult<()> { - assert!(cost.is_some() || estimated_statistic.is_some()); - // TODO: we shouldn't do the following checks in the production environment. - let expr_exists = PhysicalExpression::find_by_id(physical_expression_id) - .one(&self.db) - .await?; - if expr_exists.is_none() { - return Err(BackendError::CostModel( - format!( - "physical expression id {} not found when storing cost", - physical_expression_id - ) - .into(), - )); - } - // Check if epoch_id exists in Event table - if epoch_id.is_some() { - let epoch_exists = Event::find() - .filter(event::Column::EpochId.eq(epoch_id.unwrap())) - .one(&self.db) - .await - .unwrap(); - if epoch_exists.is_none() { - return Err(BackendError::CostModel( - format!("epoch id {} not found when storing cost", epoch_id.unwrap()).into(), - )); - } - } - - let transaction = self.db.begin().await?; - - /* - The `store_cost` logic is as follows: - 1. If the epoch_id is provided, we should update the cost with the corresponding epoch_id, - or insert a new record if it doesn't exist. - 2. If the epoch_id is not provided, we cannot directly use the latest epoch_id, since in the - plan_cost table, for the current physical expression, there may be a valid cost with a lower - epoch_id, since the update_stats function updates unrelated stats. So we need to handle the - epoch_id in following logics: - 1) If a valid cost is already in the plan_cost table, we use the same epoch_id. - 2) If there is no valid cost in the plan_cost table, or there is no record, we use the - latest epoch_id. - */ - // TODO: We should add some integration tests to fully test the above logic - let epoch_id_data; - let existed_cost; - if let Some(epoch_id) = epoch_id { - epoch_id_data = epoch_id; - existed_cost = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(physical_expression_id)) - .filter(plan_cost::Column::EpochId.eq(epoch_id)) - .one(&transaction) - .await?; - } else { - existed_cost = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(physical_expression_id)) - .filter(plan_cost::Column::IsValid.eq(true)) - .order_by_desc(plan_cost::Column::EpochId) - .one(&transaction) - .await?; - if existed_cost.is_none() { - epoch_id_data = { - // When init, please make sure there is at least one epoch in the Event table. - let latest_epoch_id = Event::find() - .order_by_desc(event::Column::EpochId) - .one(&self.db) - .await? - .unwrap(); - latest_epoch_id.epoch_id - } - } else { - epoch_id_data = existed_cost.clone().unwrap().epoch_id; - } - } - - if existed_cost.is_some() { - let mut new_cost: plan_cost::ActiveModel = existed_cost.unwrap().into(); - let mut update = false; - if cost.is_some() { - let input_cost = sea_orm::ActiveValue::Set(Some(json!({ - "compute_cost": cost.clone().unwrap().compute_cost, - "io_cost": cost.clone().unwrap().io_cost - }))); - if new_cost.cost != input_cost { - update = true; - new_cost.cost = input_cost; - } - } - if estimated_statistic.is_some() { - let input_estimated_statistic = sea_orm::ActiveValue::Set(estimated_statistic); - if new_cost.estimated_statistic != input_estimated_statistic { - update = true; - new_cost.estimated_statistic = input_estimated_statistic; - } - } - if update { - assert!(new_cost.epoch_id.is_unchanged()); - let _ = PlanCost::update(new_cost).exec(&transaction).await?; - } - } else { - // TODO: we shouldn't do the following checks in the production environment. - // This check may be easy to violate, so consider removing epoch_id input parameter. - let latest_cost = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(physical_expression_id)) - .order_by_desc(plan_cost::Column::EpochId) - .one(&transaction) - .await?; - if latest_cost.is_some() { - assert!(latest_cost.clone().unwrap().epoch_id < epoch_id_data); - assert!(!latest_cost.clone().unwrap().is_valid); - } - - let new_cost = plan_cost::ActiveModel { - physical_expression_id: sea_orm::ActiveValue::Set(physical_expression_id), - epoch_id: sea_orm::ActiveValue::Set(epoch_id_data), - cost: sea_orm::ActiveValue::Set( - cost.map(|c| json!({"compute_cost": c.compute_cost, "io_cost": c.io_cost})), - ), - estimated_statistic: sea_orm::ActiveValue::Set(estimated_statistic), - is_valid: sea_orm::ActiveValue::Set(true), - ..Default::default() - }; - let _ = PlanCost::insert(new_cost).exec(&transaction).await?; - } - - transaction.commit().await?; - Ok(()) - } - - async fn get_attribute( - &self, - table_id: TableId, - attribute_base_index: AttrIndex, - ) -> StorageResult> { - let attr_res = Attribute::find() - .filter(attribute::Column::TableId.eq(table_id)) - .filter(attribute::Column::BaseAttributeNumber.eq(attribute_base_index)) - .one(&self.db) - .await?; - match attr_res { - Some(attr) => match AttrType::try_from(attr.variant_tag) { - Ok(attr_type) => Ok(Some(Attr { - table_id: attr.table_id, - name: attr.name, - compression_method: attr.compression_method, - attr_type, - base_index: attr.base_attribute_number, - nullable: attr.is_not_null, - })), - Err(_) => Err(BackendError::BackendError(format!( - "Failed to convert variant tag {} to AttrType", - attr.variant_tag - ))), - }, - None => Ok(None), - } - } -} - -// TODO: add integration tests -#[cfg(test)] -mod tests { - use crate::cost_model::interface::{Cost, EpochOption, StatType}; - use crate::{cost_model::interface::Stat, migrate, CostModelStorageLayer}; - use crate::{get_sqlite_url, TEST_DATABASE_FILE}; - use sea_orm::sqlx::database; - use sea_orm::sqlx::types::chrono::Utc; - use sea_orm::Statement; - use sea_orm::{ - ColumnTrait, ConnectionTrait, Database, DbBackend, EntityTrait, ModelTrait, QueryFilter, - QuerySelect, QueryTrait, - }; - use sea_orm_migration::schema::json; - use serde_json::{de, json}; - - use crate::entities::{prelude::*, *}; - - async fn run_migration(db_file: &str) -> String { - let database_url = get_sqlite_url(http://github.com/db_file); - remove_db_file(db_file); - - let db = Database::connect(database_url.clone()) - .await - .expect("Unable to connect to the database"); - - migrate(&db) - .await - .expect("Something went wrong during migration"); - - db.execute(sea_orm::Statement::from_string( - sea_orm::DatabaseBackend::Sqlite, - "PRAGMA foreign_keys = ON;".to_owned(), - )) - .await - .expect("Unable to enable foreign keys"); - database_url.clone() - } - - fn remove_db_file(db_file: &str) { - let database_file = format!("./{}", db_file); - let _ = std::fs::remove_file(database_file); - } - - async fn copy_init_db(db_file: &str) -> String { - let _ = std::fs::copy(TEST_DATABASE_FILE.clone(), db_file); - get_sqlite_url(http://github.com/db_file) - } - - #[tokio::test] - async fn test_create_new_epoch() { - const DATABASE_FILE: &str = "test_create_new_epoch.db"; - let database_url = run_migration(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let res = backend_manager - .create_new_epoch("source".to_string(), "data".to_string()) - .await; - println!("{:?}", res); - assert!(res.is_ok()); - let inserted_id = res.unwrap(); - let lookup_res = Event::find_by_id(inserted_id) - .all(&backend_manager.db) - .await - .unwrap(); - println!("{:?}", lookup_res); - assert_eq!(lookup_res.len(), 1); - assert_eq!(lookup_res[0].source_variant, "source"); - assert_eq!( - lookup_res[0].data, - serde_json::Value::String("data".to_string()) - ); - assert_eq!(lookup_res[0].epoch_id, inserted_id); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_update_stats_from_catalog() { - const DATABASE_FILE: &str = "test_update_stats_from_catalog.db"; - let database_url = run_migration(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let res = backend_manager - .update_stats_from_catalog(super::CatalogSource::Mock) - .await; - println!("{:?}", res); - assert!(res.is_ok()); - let epoch_id = res.unwrap(); - assert_eq!(epoch_id, 1); - - let lookup_res = Statistic::find().all(&backend_manager.db).await.unwrap(); - println!("{:?}", lookup_res); - assert_eq!(lookup_res.len(), 3); - - let stat_res = backend_manager - .get_stats_for_table(1, StatType::TableRowCount, Some(epoch_id)) - .await; - assert!(stat_res.is_ok()); - assert_eq!(stat_res.unwrap().unwrap(), json!(300)); - let stat_res = backend_manager - .get_stats_for_attr([2].to_vec(), StatType::NonNullCount, None) - .await; - assert!(stat_res.is_ok()); - assert_eq!(stat_res.unwrap().unwrap(), json!(200)); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_update_attr_stats() { - const DATABASE_FILE: &str = "test_update_attr_stats.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - // 1. Update non-existed stat - let epoch_id1 = backend_manager - .create_new_epoch("test".to_string(), "test_update_attr_stats".to_string()) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::NonNullCount, - stat_value: json!(100), - attr_ids: vec![1], - table_id: None, - name: "countattr1".to_string(), - }; - let res = backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id1)) - .await; - assert!(res.is_ok()); - let stat_res = Statistic::find() - .filter(statistic::Column::Name.eq("countattr1")) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(stat_res.len(), 1); - println!("{:?}", stat_res); - assert_eq!(stat_res[0].number_of_attributes, 1); - assert_eq!(stat_res[0].description, "1".to_string()); - assert_eq!(stat_res[0].variant_tag, StatType::NonNullCount as i32); - let stat_attr_res = StatisticToAttributeJunction::find() - .filter(statistic_to_attribute_junction::Column::StatisticId.eq(stat_res[0].id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(stat_attr_res.len(), 1); - assert_eq!(stat_attr_res[0].attribute_id, 1); - let versioned_stat_res = VersionedStatistic::find() - .filter(versioned_statistic::Column::StatisticId.eq(stat_res[0].id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(versioned_stat_res.len(), 1); - assert_eq!(versioned_stat_res[0].statistic_value, json!(100)); - assert_eq!(versioned_stat_res[0].epoch_id, epoch_id1); - - // 2. Normal update - // 2.1 Insert some costs - let res = PhysicalExpression::insert(physical_expression::ActiveModel { - group_id: sea_orm::ActiveValue::Set(1), - fingerprint: sea_orm::ActiveValue::Set(12346), - variant_tag: sea_orm::ActiveValue::Set(1), - data: sea_orm::ActiveValue::Set(serde_json::Value::String("data".to_string())), - ..Default::default() - }); - let expr_id = res.exec(&backend_manager.db).await.unwrap().last_insert_id; - let res = PhysicalExpressionToStatisticJunction::insert( - physical_expression_to_statistic_junction::ActiveModel { - physical_expression_id: sea_orm::ActiveValue::Set(expr_id), - statistic_id: sea_orm::ActiveValue::Set(stat_res[0].id), - }, - ) - .exec(&backend_manager.db) - .await - .unwrap(); - backend_manager - .store_cost( - expr_id, - Some(Cost { - compute_cost: 42.0, - io_cost: 42.0, - }), - Some(42.0), - Some(versioned_stat_res[0].epoch_id), - ) - .await - .unwrap(); - let cost_res = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(expr_id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(cost_res.len(), 1); - assert!(cost_res[0].is_valid); - // 2.2 Normal update - let epoch_id2 = backend_manager - .create_new_epoch("test".to_string(), "test_update_attr_stats".to_string()) - .await - .unwrap(); - let stat2 = Stat { - stat_type: StatType::NonNullCount, - stat_value: json!(200), - attr_ids: vec![1], - table_id: None, - name: "countattr1".to_string(), - }; - let res = backend_manager - .update_stats(stat2, EpochOption::Existed(epoch_id2)) - .await; - assert!(res.is_ok()); - // 2.3 Check statistic table - let stat_res = Statistic::find() - .filter(statistic::Column::Name.eq("countattr1")) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(stat_res.len(), 1); - assert_eq!(stat_res[0].description, "1".to_string()); - // 2.4 Check statistic_to_attribute_junction table - let stat_attr_res = StatisticToAttributeJunction::find() - .filter(statistic_to_attribute_junction::Column::StatisticId.eq(stat_res[0].id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(stat_attr_res.len(), 1); - assert_eq!(stat_attr_res[0].attribute_id, 1); - // 2.5 Check versioned_statistic table - let versioned_stat_res = VersionedStatistic::find() - .filter(versioned_statistic::Column::StatisticId.eq(stat_res[0].id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(versioned_stat_res.len(), 2); - assert_eq!(versioned_stat_res[0].statistic_value, json!(100)); - assert_eq!(versioned_stat_res[0].epoch_id, epoch_id1); - assert_eq!(versioned_stat_res[0].statistic_id, stat_res[0].id); - assert_eq!(versioned_stat_res[1].statistic_value, json!(200)); - assert_eq!(versioned_stat_res[1].epoch_id, epoch_id2); - assert_eq!(versioned_stat_res[1].statistic_id, stat_res[0].id); - assert!(epoch_id1 < epoch_id2); - // 2.6 Check plan_cost table (cost invalidation) - let cost_res = PlanCost::find() - .filter(plan_cost::Column::PhysicalExpressionId.eq(expr_id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(cost_res.len(), 1); - assert_eq!( - cost_res[0].cost, - Some(json!({"compute_cost": 42.0, "io_cost": 42.0})) - ); - assert_eq!(cost_res[0].epoch_id, epoch_id1); - assert!(!cost_res[0].is_valid); - - // 3. Update existed stat with the same value - let epoch_num = Event::find().all(&backend_manager.db).await.unwrap().len(); - let stat3 = Stat { - stat_type: StatType::NonNullCount, - stat_value: json!(200), - attr_ids: vec![1], - table_id: None, - name: "CountAttr1".to_string(), - }; - let res = backend_manager - .update_stats( - stat3, - EpochOption::New("source".to_string(), "data".to_string()), - ) - .await; - assert!(res.is_ok()); - assert!(res.unwrap().is_none()); - let epoch_num2 = Event::find().all(&backend_manager.db).await.unwrap().len(); - assert_eq!(epoch_num, epoch_num2); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_update_table_stats() { - // Simulate batch updates, first insert an existed same stat with none epoch_id, - // then insert some non-existed or different stats with New epoch_option. - const DATABASE_FILE: &str = "test_update_table_stats.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - - let table_inserted_res = TableMetadata::insert(table_metadata::ActiveModel { - name: sea_orm::ActiveValue::Set("Table2".to_string()), - namespace_id: sea_orm::ActiveValue::Set(1), - creation_time: sea_orm::ActiveValue::Set(Utc::now()), - ..Default::default() - }) - .exec(&backend_manager.db) - .await - .unwrap(); - - let statistics: Vec = vec![ - Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(0), - attr_ids: vec![], - table_id: Some(1), - name: "row_count".to_string(), - }, - Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(20), - attr_ids: vec![], - table_id: Some(1), - name: "row_count".to_string(), - }, - Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(100), - attr_ids: vec![], - table_id: Some(table_inserted_res.last_insert_id), - name: "Table2Count1".to_string(), - }, - ]; - - let mut epoch_id: Option = None; - for stat in statistics { - match epoch_id { - Some(e) => { - let res = backend_manager - .update_stats(stat.clone(), EpochOption::Existed(e)) - .await; - assert!(res.is_ok()); - assert!(stat.name == "Table2Count1"); - let res = res.unwrap(); - assert!(res.is_some()); - assert!(res.unwrap() == e); - let stat_res = Statistic::find() - .filter(statistic::Column::Name.eq(stat.name.clone())) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(stat_res.len(), 1); - let versioned_stat_res = VersionedStatistic::find() - .filter(versioned_statistic::Column::StatisticId.eq(stat_res[0].id)) - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(versioned_stat_res.len(), 1); - assert_eq!(versioned_stat_res[0].statistic_value, stat.stat_value); - assert_eq!(versioned_stat_res[0].epoch_id, e); - } - None => { - let res = backend_manager - .update_stats( - stat.clone(), - EpochOption::New("source".to_string(), "data".to_string()), - ) - .await; - assert!(res.is_ok()); - if stat.stat_value == json!(0) { - assert!(res.unwrap().is_none()); - } else { - assert!(stat.stat_value == json!(20)); - let res = res.unwrap(); - assert!(res.is_some()); - epoch_id = Some(res.unwrap()); - } - } - } - } - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_store_cost() { - const DATABASE_FILE: &str = "test_store_cost.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = backend_manager - .create_new_epoch("source".to_string(), "data".to_string()) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(10), - attr_ids: vec![], - table_id: Some(1), - name: "row_count".to_owned(), - }; - let res = backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id)) - .await; - assert!(res.is_ok()); - - let physical_expression_id = 1; - let cost = Cost { - compute_cost: 42.0, - io_cost: 42.0, - }; - let mut estimated_statistic = 42.0; - backend_manager - .store_cost( - physical_expression_id, - Some(cost.clone()), - Some(estimated_statistic), - Some(epoch_id), - ) - .await - .unwrap(); - let costs = super::PlanCost::find() - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(costs.len(), 2); // The first row one is the initialized data - assert_eq!(costs[1].epoch_id, epoch_id); - assert_eq!(costs[1].physical_expression_id, physical_expression_id); - assert_eq!( - costs[1].cost, - Some(json!({"compute_cost": cost.compute_cost, "io_cost": cost.io_cost})) - ); - assert_eq!(costs[1].estimated_statistic.unwrap(), estimated_statistic); - - estimated_statistic = 50.0; - backend_manager - .store_cost( - physical_expression_id, - None, - Some(estimated_statistic), - None, - ) - .await - .unwrap(); - let costs = super::PlanCost::find() - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(costs.len(), 2); // We should not insert a new row - assert_eq!(costs[1].epoch_id, epoch_id); - assert_eq!(costs[1].physical_expression_id, physical_expression_id); - assert_eq!( - costs[1].cost, - Some(json!({"compute_cost": cost.compute_cost, "io_cost": cost.io_cost})) - ); - assert_eq!( - costs[1].estimated_statistic.unwrap(), - estimated_statistic // The estimated_statistic should be update - ); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_cost() { - const DATABASE_FILE: &str = "test_get_cost.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = backend_manager - .create_new_epoch("source".to_string(), "data".to_string()) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(10), - attr_ids: vec![], - table_id: Some(1), - name: "row_count".to_owned(), - }; - let res = backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id)) - .await; - assert!(res.is_ok()); - - let physical_expression_id = 1; - let cost = Cost { - compute_cost: 42.0, - io_cost: 42.0, - }; - let _ = backend_manager - .store_cost( - physical_expression_id, - Some(cost.clone()), - None, - Some(epoch_id), - ) - .await; - let costs = super::PlanCost::find() - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(costs.len(), 2); // The first row one is the initialized data - assert_eq!(costs[1].epoch_id, epoch_id); - assert_eq!(costs[1].physical_expression_id, physical_expression_id); - assert_eq!( - costs[1].cost, - Some(json!({"compute_cost": cost.compute_cost, "io_cost": cost.io_cost})) - ); - assert_eq!(costs[1].estimated_statistic, None); - - let res = backend_manager - .get_cost(physical_expression_id) - .await - .unwrap(); - assert_eq!(res.0.unwrap(), cost); - assert_eq!(res.1, None); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_cost_analysis() { - const DATABASE_FILE: &str = "test_get_cost_analysis.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = backend_manager - .create_new_epoch("source".to_string(), "data".to_string()) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(10), - attr_ids: vec![], - table_id: Some(1), - name: "row_count".to_owned(), - }; - let res = backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id)) - .await; - assert!(res.is_ok()); - - let physical_expression_id = 1; - let estimated_statistic = 42.0; - let _ = backend_manager - .store_cost( - physical_expression_id, - None, - Some(estimated_statistic), - Some(epoch_id), - ) - .await; - let costs = super::PlanCost::find() - .all(&backend_manager.db) - .await - .unwrap(); - assert_eq!(costs.len(), 2); // The first row one is the initialized data - assert_eq!(costs[1].epoch_id, epoch_id); - assert_eq!(costs[1].physical_expression_id, physical_expression_id); - assert_eq!(costs[1].cost, None); - assert_eq!(costs[1].estimated_statistic.unwrap(), estimated_statistic); - println!("{:?}", costs); - - // Retrieve physical_expression_id 1 and epoch_id 1 - let res = backend_manager - .get_cost_analysis(physical_expression_id, 1) - .await - .unwrap(); - - // The cost in the dummy data is 10 - assert_eq!( - res.0.unwrap(), - Cost { - compute_cost: 10.0, - io_cost: 10.0, - } - ); - assert_eq!(res.1.unwrap(), 10.0); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_stats_for_table() { - const DATABASE_FILE: &str = "test_get_stats_for_table.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = 1; - let table_id = 1; - let stat_type = StatType::TableRowCount; - - // Get initial stats - let res = backend_manager - .get_stats_for_table(table_id, stat_type, None) - .await - .unwrap() - .unwrap(); - let row_count = res.as_i64().unwrap(); - assert_eq!(row_count, 0); - - // Update stats - let epoch_id2 = backend_manager - .create_new_epoch("test".to_string(), "test_get_stats_for_table".to_string()) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::TableRowCount, - stat_value: json!(100), - attr_ids: vec![], - table_id: Some(table_id), - name: "row_count".to_string(), - }; - backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id2)) - .await - .unwrap(); - - // Get updated stats - let res = backend_manager - .get_stats_for_table(table_id, stat_type, None) - .await - .unwrap() - .unwrap(); - let row_count = res.as_i64().unwrap(); - assert_eq!(row_count, 100); - - // Get stats for a specific epoch - let res = backend_manager - .get_stats_for_table(table_id, stat_type, Some(epoch_id)) - .await - .unwrap() - .unwrap(); - let row_count = res.as_i64().unwrap(); - assert_eq!(row_count, 0); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_stats_for_single_attr() { - const DATABASE_FILE: &str = "test_get_stats_for_single_attr.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = 1; - let attr_ids = vec![1]; - let stat_type = StatType::Cardinality; - - // Get initial stats - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, None) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 0); - - // Update stats - let epoch_id2 = backend_manager - .create_new_epoch( - "test".to_string(), - "test_get_stats_for_single_attr".to_string(), - ) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::Cardinality, - stat_value: json!(100), - attr_ids: attr_ids.clone(), - table_id: None, - name: "cardinality".to_string(), - }; - backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id2)) - .await - .unwrap(); - - // Get updated stats - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, None) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 100); - - // Get stats for a specific epoch - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, Some(epoch_id)) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 0); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_stats_for_multiple_attrs() { - const DATABASE_FILE: &str = "test_get_stats_for_multiple_attrs.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = 1; - let attr_ids = vec![2, 1]; - let stat_type = StatType::Cardinality; - - // Get initial stats - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, None) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 0); - - // Update stats - let epoch_id2 = backend_manager - .create_new_epoch( - "test".to_string(), - "test_get_stats_for_multiple_attrs".to_string(), - ) - .await - .unwrap(); - let stat = Stat { - stat_type: StatType::Cardinality, - stat_value: json!(111), - attr_ids: attr_ids.clone(), - table_id: None, - name: "cardinality".to_string(), - }; - backend_manager - .update_stats(stat, EpochOption::Existed(epoch_id2)) - .await - .unwrap(); - - // Get updated stats - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, None) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 111); - - // Get stats for a specific epoch - let res = backend_manager - .get_stats_for_attr(attr_ids.clone(), stat_type, Some(epoch_id)) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 0); - - remove_db_file(DATABASE_FILE); - } - - #[tokio::test] - async fn test_get_stats_for_attr_indices_based() { - const DATABASE_FILE: &str = "test_get_stats_for_attr_indices_based.db"; - let database_url = copy_init_db(DATABASE_FILE).await; - let mut binding = super::BackendManager::new(Some(&database_url)).await; - let backend_manager = binding.as_mut().unwrap(); - let epoch_id = 1; - let table_id = 1; - let attr_base_indices = vec![0, 1]; - let stat_type = StatType::Cardinality; - - // Statistics exist in the database - let res = backend_manager - .get_stats_for_attr_indices_based(table_id, attr_base_indices.clone(), stat_type, None) - .await - .unwrap() - .unwrap(); - let cardinality = res.as_i64().unwrap(); - assert_eq!(cardinality, 0); - - // Statistics do not exist in the database - let attr_base_indices = vec![1]; - let res = backend_manager - .get_stats_for_attr_indices_based(table_id, attr_base_indices.clone(), stat_type, None) - .await - .unwrap(); - assert!(res.is_none()); - - // Attribute base indices not valid. - let attr_base_indices = vec![1, 2]; - let res = backend_manager - .get_stats_for_attr_indices_based(table_id, attr_base_indices.clone(), stat_type, None) - .await; - assert!(res.is_err()); - - remove_db_file(DATABASE_FILE); - } -} diff --git a/optd-persistent/src/db/init.db b/optd-persistent/src/db/init.db deleted file mode 100644 index 0c3d71c..0000000 Binary files a/optd-persistent/src/db/init.db and /dev/null differ diff --git a/optd-persistent/src/entities/attribute.rs b/optd-persistent/src/entities/attribute.rs deleted file mode 100644 index aa312c0..0000000 --- a/optd-persistent/src/entities/attribute.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "attribute")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub table_id: i32, - pub name: String, - pub compression_method: String, - pub variant_tag: i32, - pub base_attribute_number: i32, - pub is_not_null: bool, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::attribute_constraint_junction::Entity")] - AttributeConstraintJunction, - #[sea_orm(has_many = "super::attribute_foreign_constraint_junction::Entity")] - AttributeForeignConstraintJunction, - #[sea_orm(has_many = "super::statistic_to_attribute_junction::Entity")] - StatisticToAttributeJunction, - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::TableId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::AttributeConstraintJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::AttributeForeignConstraintJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::StatisticToAttributeJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::TableMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::statistic_to_attribute_junction::Relation::Statistic.def() - } - fn via() -> Option { - Some( - super::statistic_to_attribute_junction::Relation::Attribute - .def() - .rev(), - ) - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/attribute_constraint_junction.rs b/optd-persistent/src/entities/attribute_constraint_junction.rs deleted file mode 100644 index 7c61c72..0000000 --- a/optd-persistent/src/entities/attribute_constraint_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "attribute_constraint_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub attribute_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub constraint_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::attribute::Entity", - from = "Column::AttributeId", - to = "super::attribute::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Attribute, - #[sea_orm( - belongs_to = "super::constraint_metadata::Entity", - from = "Column::ConstraintId", - to = "super::constraint_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - ConstraintMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Attribute.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ConstraintMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/attribute_foreign_constraint_junction.rs b/optd-persistent/src/entities/attribute_foreign_constraint_junction.rs deleted file mode 100644 index f219a39..0000000 --- a/optd-persistent/src/entities/attribute_foreign_constraint_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "attribute_foreign_constraint_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub attribute_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub constraint_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::attribute::Entity", - from = "Column::AttributeId", - to = "super::attribute::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Attribute, - #[sea_orm( - belongs_to = "super::constraint_metadata::Entity", - from = "Column::ConstraintId", - to = "super::constraint_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - ConstraintMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Attribute.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ConstraintMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/constraint_metadata.rs b/optd-persistent/src/entities/constraint_metadata.rs deleted file mode 100644 index 8adf1d7..0000000 --- a/optd-persistent/src/entities/constraint_metadata.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "constraint_metadata")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub variant_tag: i32, - pub table_id: Option, - pub index_id: Option, - pub foreign_ref_id: Option, - pub check_src: String, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::attribute_constraint_junction::Entity")] - AttributeConstraintJunction, - #[sea_orm(has_many = "super::attribute_foreign_constraint_junction::Entity")] - AttributeForeignConstraintJunction, - #[sea_orm( - belongs_to = "super::index_metadata::Entity", - from = "Column::IndexId", - to = "super::index_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - IndexMetadata, - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::ForeignRefId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata2, - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::TableId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata1, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::AttributeConstraintJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::AttributeForeignConstraintJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::IndexMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/database_metadata.rs b/optd-persistent/src/entities/database_metadata.rs deleted file mode 100644 index 98106d6..0000000 --- a/optd-persistent/src/entities/database_metadata.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "database_metadata")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub creation_time: DateTimeUtc, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::namespace_metadata::Entity")] - NamespaceMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::NamespaceMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/event.rs b/optd-persistent/src/entities/event.rs deleted file mode 100644 index ad9157d..0000000 --- a/optd-persistent/src/entities/event.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "event")] -pub struct Model { - #[sea_orm(primary_key)] - pub epoch_id: i32, - pub timestamp: DateTimeUtc, - pub source_variant: String, - pub data: Json, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::group_winner::Entity")] - GroupWinner, - #[sea_orm(has_many = "super::plan_cost::Entity")] - PlanCost, - #[sea_orm(has_many = "super::versioned_statistic::Entity")] - VersionedStatistic, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::GroupWinner.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PlanCost.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::VersionedStatistic.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/group_winner.rs b/optd-persistent/src/entities/group_winner.rs deleted file mode 100644 index 32cbcb4..0000000 --- a/optd-persistent/src/entities/group_winner.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "group_winner")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub group_id: i32, - pub physical_expression_id: i32, - pub cost_id: i32, - pub epoch_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::cascades_group::Entity", - from = "Column::GroupId", - to = "super::cascades_group::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - CascadesGroup, - #[sea_orm( - belongs_to = "super::event::Entity", - from = "Column::EpochId", - to = "super::event::Column::EpochId", - on_update = "Cascade", - on_delete = "Cascade" - )] - Event, - #[sea_orm( - belongs_to = "super::physical_expression::Entity", - from = "Column::PhysicalExpressionId", - to = "super::physical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PhysicalExpression, - #[sea_orm( - belongs_to = "super::plan_cost::Entity", - from = "Column::CostId", - to = "super::plan_cost::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PlanCost, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::CascadesGroup.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Event.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpression.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PlanCost.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/index_metadata.rs b/optd-persistent/src/entities/index_metadata.rs deleted file mode 100644 index 47263b7..0000000 --- a/optd-persistent/src/entities/index_metadata.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "index_metadata")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub table_id: i32, - pub name: String, - pub number_of_attributes: i32, - pub variant_tag: i32, - pub is_unique: bool, - pub nulls_not_distinct: bool, - pub is_primary: bool, - pub is_clustered: bool, - pub is_exclusion: bool, - pub description: String, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::constraint_metadata::Entity")] - ConstraintMetadata, - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::TableId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ConstraintMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::TableMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/mod.rs b/optd-persistent/src/entities/mod.rs deleted file mode 100644 index cd2d9d0..0000000 --- a/optd-persistent/src/entities/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -pub mod prelude; - -pub mod attribute; -pub mod attribute_constraint_junction; -pub mod attribute_foreign_constraint_junction; -pub mod cascades_group; -pub mod constraint_metadata; -pub mod database_metadata; -pub mod event; -pub mod group_winner; -pub mod index_metadata; -pub mod logical_children; -pub mod logical_expression; -pub mod logical_property; -pub mod namespace_metadata; -pub mod physical_children; -pub mod physical_expression; -pub mod physical_expression_to_statistic_junction; -pub mod physical_property; -pub mod plan_cost; -pub mod predicate; -pub mod predicate_children; -pub mod predicate_logical_expression_junction; -pub mod predicate_physical_expression_junction; -pub mod statistic; -pub mod statistic_to_attribute_junction; -pub mod table_metadata; -pub mod trigger; -pub mod versioned_statistic; diff --git a/optd-persistent/src/entities/namespace_metadata.rs b/optd-persistent/src/entities/namespace_metadata.rs deleted file mode 100644 index 8f63146..0000000 --- a/optd-persistent/src/entities/namespace_metadata.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "namespace_metadata")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub database_id: i32, - pub creation_time: DateTimeUtc, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::database_metadata::Entity", - from = "Column::DatabaseId", - to = "super::database_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - DatabaseMetadata, - #[sea_orm(has_many = "super::table_metadata::Entity")] - TableMetadata, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::DatabaseMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::TableMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/physical_expression.rs b/optd-persistent/src/entities/physical_expression.rs deleted file mode 100644 index 4876d35..0000000 --- a/optd-persistent/src/entities/physical_expression.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "physical_expression")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub group_id: i32, - pub fingerprint: i64, - pub variant_tag: i16, - pub data: Json, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::cascades_group::Entity", - from = "Column::GroupId", - to = "super::cascades_group::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - CascadesGroup, - #[sea_orm(has_many = "super::group_winner::Entity")] - GroupWinner, - #[sea_orm(has_many = "super::physical_children::Entity")] - PhysicalChildren, - #[sea_orm(has_many = "super::physical_expression_to_statistic_junction::Entity")] - PhysicalExpressionToStatisticJunction, - #[sea_orm(has_many = "super::physical_property::Entity")] - PhysicalProperty, - #[sea_orm(has_many = "super::plan_cost::Entity")] - PlanCost, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::GroupWinner.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalChildren.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpressionToStatisticJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalProperty.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PlanCost.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::physical_children::Relation::CascadesGroup.def() - } - fn via() -> Option { - Some( - super::physical_children::Relation::PhysicalExpression - .def() - .rev(), - ) - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::physical_expression_to_statistic_junction::Relation::Statistic.def() - } - fn via() -> Option { - Some( - super::physical_expression_to_statistic_junction::Relation::PhysicalExpression - .def() - .rev(), - ) - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/physical_expression_to_statistic_junction.rs b/optd-persistent/src/entities/physical_expression_to_statistic_junction.rs deleted file mode 100644 index f8020bd..0000000 --- a/optd-persistent/src/entities/physical_expression_to_statistic_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "physical_expression_to_statistic_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub physical_expression_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub statistic_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::physical_expression::Entity", - from = "Column::PhysicalExpressionId", - to = "super::physical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PhysicalExpression, - #[sea_orm( - belongs_to = "super::statistic::Entity", - from = "Column::StatisticId", - to = "super::statistic::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Statistic, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpression.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Statistic.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/physical_property.rs b/optd-persistent/src/entities/physical_property.rs deleted file mode 100644 index 51d98dc..0000000 --- a/optd-persistent/src/entities/physical_property.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "physical_property")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub physical_expression_id: i32, - pub variant_tag: i16, - pub data: Json, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::physical_expression::Entity", - from = "Column::PhysicalExpressionId", - to = "super::physical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PhysicalExpression, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpression.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/plan_cost.rs b/optd-persistent/src/entities/plan_cost.rs deleted file mode 100644 index 5d7e24b..0000000 --- a/optd-persistent/src/entities/plan_cost.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] -#[sea_orm(table_name = "plan_cost")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub physical_expression_id: i32, - pub epoch_id: i32, - pub cost: Option, - #[sea_orm(column_type = "Float", nullable)] - pub estimated_statistic: Option, - pub is_valid: bool, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::event::Entity", - from = "Column::EpochId", - to = "super::event::Column::EpochId", - on_update = "Cascade", - on_delete = "Cascade" - )] - Event, - #[sea_orm(has_many = "super::group_winner::Entity")] - GroupWinner, - #[sea_orm( - belongs_to = "super::physical_expression::Entity", - from = "Column::PhysicalExpressionId", - to = "super::physical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PhysicalExpression, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Event.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::GroupWinner.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpression.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/predicate.rs b/optd-persistent/src/entities/predicate.rs deleted file mode 100644 index e142a21..0000000 --- a/optd-persistent/src/entities/predicate.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "predicate")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub data: Json, - pub variant: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::predicate_logical_expression_junction::Entity")] - PredicateLogicalExpressionJunction, - #[sea_orm(has_many = "super::predicate_physical_expression_junction::Entity")] - PredicatePhysicalExpressionJunction, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PredicateLogicalExpressionJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PredicatePhysicalExpressionJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::predicate_logical_expression_junction::Relation::LogicalExpression.def() - } - fn via() -> Option { - Some( - super::predicate_logical_expression_junction::Relation::Predicate - .def() - .rev(), - ) - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::predicate_physical_expression_junction::Relation::PhysicalExpression.def() - } - fn via() -> Option { - Some( - super::predicate_physical_expression_junction::Relation::Predicate - .def() - .rev(), - ) - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/predicate_children.rs b/optd-persistent/src/entities/predicate_children.rs deleted file mode 100644 index 93ef3eb..0000000 --- a/optd-persistent/src/entities/predicate_children.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "predicate_children")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub parent_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub child_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::predicate::Entity", - from = "Column::ChildId", - to = "super::predicate::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Predicate2, - #[sea_orm( - belongs_to = "super::predicate::Entity", - from = "Column::ParentId", - to = "super::predicate::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Predicate1, -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/predicate_logical_expression_junction.rs b/optd-persistent/src/entities/predicate_logical_expression_junction.rs deleted file mode 100644 index 520da03..0000000 --- a/optd-persistent/src/entities/predicate_logical_expression_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "predicate_logical_expression_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub logical_expr_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub predicate_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::logical_expression::Entity", - from = "Column::LogicalExprId", - to = "super::logical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - LogicalExpression, - #[sea_orm( - belongs_to = "super::predicate::Entity", - from = "Column::PredicateId", - to = "super::predicate::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Predicate, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::LogicalExpression.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Predicate.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/predicate_physical_expression_junction.rs b/optd-persistent/src/entities/predicate_physical_expression_junction.rs deleted file mode 100644 index 263abc8..0000000 --- a/optd-persistent/src/entities/predicate_physical_expression_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "predicate_physical_expression_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub physical_expr_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub predicate_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::physical_expression::Entity", - from = "Column::PhysicalExprId", - to = "super::physical_expression::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - PhysicalExpression, - #[sea_orm( - belongs_to = "super::predicate::Entity", - from = "Column::PredicateId", - to = "super::predicate::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Predicate, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpression.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Predicate.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/prelude.rs b/optd-persistent/src/entities/prelude.rs deleted file mode 100644 index 753e58b..0000000 --- a/optd-persistent/src/entities/prelude.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -pub use super::attribute::Entity as Attribute; -pub use super::attribute_constraint_junction::Entity as AttributeConstraintJunction; -pub use super::attribute_foreign_constraint_junction::Entity as AttributeForeignConstraintJunction; -pub use super::cascades_group::Entity as CascadesGroup; -pub use super::constraint_metadata::Entity as ConstraintMetadata; -pub use super::database_metadata::Entity as DatabaseMetadata; -pub use super::event::Entity as Event; -pub use super::group_winner::Entity as GroupWinner; -pub use super::index_metadata::Entity as IndexMetadata; -pub use super::logical_children::Entity as LogicalChildren; -pub use super::logical_expression::Entity as LogicalExpression; -pub use super::logical_property::Entity as LogicalProperty; -pub use super::namespace_metadata::Entity as NamespaceMetadata; -pub use super::physical_children::Entity as PhysicalChildren; -pub use super::physical_expression::Entity as PhysicalExpression; -pub use super::physical_expression_to_statistic_junction::Entity as PhysicalExpressionToStatisticJunction; -pub use super::physical_property::Entity as PhysicalProperty; -pub use super::plan_cost::Entity as PlanCost; -pub use super::statistic::Entity as Statistic; -pub use super::statistic_to_attribute_junction::Entity as StatisticToAttributeJunction; -pub use super::table_metadata::Entity as TableMetadata; -pub use super::trigger::Entity as Trigger; -pub use super::versioned_statistic::Entity as VersionedStatistic; diff --git a/optd-persistent/src/entities/statistic.rs b/optd-persistent/src/entities/statistic.rs deleted file mode 100644 index 1eaf96b..0000000 --- a/optd-persistent/src/entities/statistic.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "statistic")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub table_id: Option, - pub creation_time: DateTimeUtc, - pub number_of_attributes: i32, - pub variant_tag: i32, - pub description: String, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::physical_expression_to_statistic_junction::Entity")] - PhysicalExpressionToStatisticJunction, - #[sea_orm(has_many = "super::statistic_to_attribute_junction::Entity")] - StatisticToAttributeJunction, - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::TableId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata, - #[sea_orm(has_many = "super::versioned_statistic::Entity")] - VersionedStatistic, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::PhysicalExpressionToStatisticJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::StatisticToAttributeJunction.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::TableMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::VersionedStatistic.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::statistic_to_attribute_junction::Relation::Attribute.def() - } - fn via() -> Option { - Some( - super::statistic_to_attribute_junction::Relation::Statistic - .def() - .rev(), - ) - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::physical_expression_to_statistic_junction::Relation::PhysicalExpression.def() - } - fn via() -> Option { - Some( - super::physical_expression_to_statistic_junction::Relation::Statistic - .def() - .rev(), - ) - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/statistic_to_attribute_junction.rs b/optd-persistent/src/entities/statistic_to_attribute_junction.rs deleted file mode 100644 index 63d23fb..0000000 --- a/optd-persistent/src/entities/statistic_to_attribute_junction.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "statistic_to_attribute_junction")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub statistic_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub attribute_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::attribute::Entity", - from = "Column::AttributeId", - to = "super::attribute::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Attribute, - #[sea_orm( - belongs_to = "super::statistic::Entity", - from = "Column::StatisticId", - to = "super::statistic::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Statistic, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Attribute.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Statistic.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/table_metadata.rs b/optd-persistent/src/entities/table_metadata.rs deleted file mode 100644 index 35ea923..0000000 --- a/optd-persistent/src/entities/table_metadata.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "table_metadata")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub namespace_id: i32, - pub creation_time: DateTimeUtc, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::attribute::Entity")] - Attribute, - #[sea_orm(has_many = "super::index_metadata::Entity")] - IndexMetadata, - #[sea_orm( - belongs_to = "super::namespace_metadata::Entity", - from = "Column::NamespaceId", - to = "super::namespace_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - NamespaceMetadata, - #[sea_orm(has_many = "super::statistic::Entity")] - Statistic, - #[sea_orm(has_many = "super::trigger::Entity")] - Trigger, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Attribute.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::IndexMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::NamespaceMetadata.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Statistic.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Trigger.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/trigger.rs b/optd-persistent/src/entities/trigger.rs deleted file mode 100644 index a5f9de8..0000000 --- a/optd-persistent/src/entities/trigger.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "trigger")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub name: String, - pub table_id: i32, - pub parent_trigger_id: i32, - pub function: Json, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::table_metadata::Entity", - from = "Column::TableId", - to = "super::table_metadata::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - TableMetadata, - #[sea_orm( - belongs_to = "Entity", - from = "Column::ParentTriggerId", - to = "Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - SelfRef, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::TableMetadata.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/entities/versioned_statistic.rs b/optd-persistent/src/entities/versioned_statistic.rs deleted file mode 100644 index c4533bf..0000000 --- a/optd-persistent/src/entities/versioned_statistic.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "versioned_statistic")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub epoch_id: i32, - pub statistic_id: i32, - pub statistic_value: Json, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::event::Entity", - from = "Column::EpochId", - to = "super::event::Column::EpochId", - on_update = "Cascade", - on_delete = "Cascade" - )] - Event, - #[sea_orm( - belongs_to = "super::statistic::Entity", - from = "Column::StatisticId", - to = "super::statistic::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Statistic, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Event.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Statistic.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/optd-persistent/src/lib.rs b/optd-persistent/src/lib.rs deleted file mode 100644 index dd95da2..0000000 --- a/optd-persistent/src/lib.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![allow(dead_code)] - -use std::sync::LazyLock; - -use sea_orm::*; -use sea_orm_migration::prelude::*; - -use migrator::Migrator; - -pub mod entities; -mod migrator; - -pub mod cost_model; -pub use cost_model::interface::CostModelStorageLayer; - -mod memo; -pub use memo::interface::Memo; - -/// The filename of the SQLite database for migration. -pub const DATABASE_FILENAME: &str = "sqlite.db"; -/// The URL of the SQLite database for migration. -pub const DATABASE_URL: &str = "sqlite:./sqlite.db?mode=rwc"; - -/// The filename of the SQLite database for testing. -pub const TEST_DATABASE_FILENAME: &str = "init.db"; -/// The URL of the SQLite database for testing. -pub static TEST_DATABASE_FILE: LazyLock = LazyLock::new(|| { - std::env::current_dir() - .unwrap() - .join("src") - .join("db") - .join(TEST_DATABASE_FILENAME) - .to_str() - .unwrap() - .to_owned() -}); -/// The URL of the SQLite database for testing. -pub static TEST_DATABASE_URL: LazyLock = - LazyLock::new(|| get_sqlite_url(http://github.com/TEST_DATABASE_FILE.as_str())); - -fn get_sqlite_url(/service/file:///%20&str) -> String { - format!("sqlite:{}?mode=rwc", file) -} - -#[derive(Debug)] -pub enum CostModelError { - // TODO: Add more error types - UnknownStatisticType, - VersionedStatisticNotFound, - CustomError(String), -} - -/// TODO convert this to `thiserror` -#[derive(Debug)] -/// The different kinds of errors that might occur while running operations on a memo table. -pub enum MemoError { - UnknownGroup, - UnknownLogicalExpression, - UnknownPhysicalExpression, - InvalidExpression, -} - -/// TODO convert this to `thiserror` -#[derive(Debug)] -pub enum BackendError { - Memo(MemoError), - DatabaseError(DbErr), - CostModel(CostModelError), - BackendError(String), -} - -impl From for CostModelError { - fn from(value: String) -> Self { - CostModelError::CustomError(value) - } -} - -impl From for BackendError { - fn from(value: CostModelError) -> Self { - BackendError::CostModel(value) - } -} - -impl From for BackendError { - fn from(value: MemoError) -> Self { - BackendError::Memo(value) - } -} - -impl From for BackendError { - fn from(value: DbErr) -> Self { - BackendError::DatabaseError(value) - } -} - -/// A type alias for a result with [`BackendError`] as the error type. -pub type StorageResult = Result; - -pub struct BackendManager { - db: DatabaseConnection, -} - -impl BackendManager { - /// Creates a new `BackendManager`. - pub async fn new(database_url: Option<&str>) -> StorageResult { - Ok(Self { - db: Database::connect(database_url.unwrap_or(DATABASE_URL)).await?, - }) - } -} - -pub async fn migrate(db: &DatabaseConnection) -> Result<(), DbErr> { - Migrator::refresh(db).await -} diff --git a/optd-persistent/src/main.rs b/optd-persistent/src/main.rs deleted file mode 100644 index 165189e..0000000 --- a/optd-persistent/src/main.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Very basic demo of using the ORM for optd-persistent. -//! -//! You may run into errors when you first clone this repository. -//! See the `README.md` for setup instructions. - -#![allow(dead_code, unused_imports)] - -use sea_orm::*; -use sea_orm_migration::prelude::*; -use serde_json::json; - -mod entities; -mod migrator; - -use entities::{prelude::*, *}; -use optd_persistent::DATABASE_URL; - -#[tokio::main] -async fn main() { - basic_demo().await; - memo_demo().await; -} - -async fn memo_demo() { - let _db = Database::connect(DATABASE_URL).await.unwrap(); - - todo!() -} - -async fn basic_demo() { - let db = Database::connect(DATABASE_URL).await.unwrap(); - - // Create a new `CascadesGroup`. - let group = cascades_group::ActiveModel { - latest_winner: ActiveValue::Set(None), - in_progress: ActiveValue::Set(false), - is_optimized: ActiveValue::Set(false), - ..Default::default() - } - .save(&db) - .await - .unwrap(); - - // Create a new logical expression. - let l_expr = logical_expression::ActiveModel { - group_id: group.id.clone(), - fingerprint: ActiveValue::Set(42), // Example fingerprint - variant_tag: ActiveValue::Set(1), // Example variant tag - data: ActiveValue::Set(json!({ // Example operator - "type": "Scan", - "table": "lineitem", - "predicate": "l_quantity < 10", - })), - ..Default::default() - } - .save(&db) - .await - .unwrap(); - - // Create a link between the group and the logical expression in the junction table. - let _link = logical_children::ActiveModel { - group_id: group.id.clone(), - logical_expression_id: l_expr.id.clone(), - } - .insert(&db) - .await - .unwrap(); - - // Basic lookup test on each table. - { - let groups: Vec = CascadesGroup::find().all(&db).await.unwrap(); - assert_eq!(groups.len(), 1); - - let l_expressions: Vec = - LogicalExpression::find().all(&db).await.unwrap(); - assert_eq!(l_expressions.len(), 1); - } - - // Retrieve all logical expressions that belong to this group with lazy loading. - { - let group = CascadesGroup::find_by_id(*group.id.try_as_ref().unwrap()) - .one(&db) - .await - .unwrap() - .unwrap(); - - let group_expressions: Vec = group - .find_related(LogicalExpression) - .all(&db) - .await - .unwrap(); - assert_eq!(group_expressions.len(), 1); - } - - // Retrieve all logical expressions that belong to this group with eager loading. - { - let group_with_expressions: Vec<(cascades_group::Model, Vec)> = - CascadesGroup::find() - .find_with_related(LogicalExpression) - .all(&db) - .await - .unwrap(); - assert_eq!(group_with_expressions.len(), 1); - assert_eq!(group_with_expressions[0].1.len(), 1); - } - - // Clean up everything. Since everything is cascading, we only need to manually delete the group - // and then SeaORM will take care of the expression and the junction. - group.delete(&db).await.unwrap(); - - println!("Demo Finished!"); -} diff --git a/optd-persistent/src/memo/expression.rs b/optd-persistent/src/memo/expression.rs deleted file mode 100644 index ff1590c..0000000 --- a/optd-persistent/src/memo/expression.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::entities::*; -use std::hash::{DefaultHasher, Hash, Hasher}; - -/// All of the different types of fixed logical operators. -/// -/// Note that there could be more operators that the memo table must support that are not enumerated -/// in this enum, as there can be up to `2^16` different types of operators. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[non_exhaustive] -#[repr(i16)] -pub enum LogicalOperator { - Scan, - Join, -} - -/// All of the different types of fixed physical operators. -/// -/// Note that there could be more operators that the memo table must support that are not enumerated -/// in this enum, as there can be up to `2^16` different types of operators. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[non_exhaustive] -#[repr(i16)] -pub enum PhysicalOperator { - TableScan, - IndexScan, - NestedLoopJoin, - HashJoin, -} - -/// A method to generate a fingerprint used to efficiently check if two -/// expressions are equivalent. -/// -/// TODO actually make efficient. -fn fingerprint(variant_tag: i16, data: &serde_json::Value) -> i64 { - let mut hasher = DefaultHasher::new(); - - variant_tag.hash(&mut hasher); - data.hash(&mut hasher); - - hasher.finish() as i64 -} - -impl logical_expression::Model { - /// Creates a new logical expression with an unset `id` and `group_id`. - pub fn new(variant_tag: LogicalOperator, data: serde_json::Value) -> Self { - let tag = variant_tag as i16; - let fingerprint = fingerprint(tag, &data); - - Self { - id: 0, - group_id: 0, - fingerprint, - variant_tag: tag, - data, - } - } -} - -impl physical_expression::Model { - /// Creates a new physical expression with an unset `id` and `group_id`. - pub fn new(variant_tag: PhysicalOperator, data: serde_json::Value) -> Self { - let tag = variant_tag as i16; - let fingerprint = fingerprint(tag, &data); - - Self { - id: 0, - group_id: 0, - fingerprint, - variant_tag: tag, - data, - } - } -} diff --git a/optd-persistent/src/memo/interface.rs b/optd-persistent/src/memo/interface.rs deleted file mode 100644 index 2d2240e..0000000 --- a/optd-persistent/src/memo/interface.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::StorageResult; - -/// A trait representing an implementation of a memoization table. -/// -/// Note that we use [`trait_variant`] here in order to add bounds on every method. -/// See this [blog post]( -/// https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#async-fn-in-public-traits) -/// for more information. -/// -/// TODO Figure out for each when to get the ID of a record or the entire record itself. -#[trait_variant::make(Send)] -pub trait Memo { - /// A type representing a group in the Cascades framework. - type Group; - /// A type representing a unique identifier for a group. - type GroupId; - /// A type representing a logical expression. - type LogicalExpression; - /// A type representing a unique identifier for a logical expression. - type LogicalExpressionId; - /// A type representing a physical expression. - type PhysicalExpression; - /// A type representing a unique identifier for a physical expression. - type PhysicalExpressionId; - - /// Retrieves a [`Self::Group`] given a [`Self::GroupId`]. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn get_group(&self, group_id: Self::GroupId) -> StorageResult; - - /// Retrieves all group IDs that are stored in the memo table. - async fn get_all_groups(&self) -> StorageResult>; - - /// Retrieves a [`Self::LogicalExpression`] given a [`Self::LogicalExpressionId`]. - /// - /// If the logical expression does not exist, returns a [`MemoError::UnknownLogicalExpression`] - /// error. - async fn get_logical_expression( - &self, - logical_expression_id: Self::LogicalExpressionId, - ) -> StorageResult; - - /// Retrieves a [`Self::PhysicalExpression`] given a [`Self::PhysicalExpressionId`]. - /// - /// If the physical expression does not exist, returns a - /// [`MemoError::UnknownPhysicalExpression`] error. - async fn get_physical_expression( - &self, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult; - - /// Retrieves the parent group ID of a logical expression given its expression ID. - /// - /// If the logical expression does not exist, returns a [`MemoError::UnknownLogicalExpression`] - /// error. - async fn get_group_from_logical_expression( - &self, - logical_expression_id: Self::LogicalExpressionId, - ) -> StorageResult; - - /// Retrieves the parent group ID of a logical expression given its expression ID. - /// - /// If the physical expression does not exist, returns a - /// [`MemoError::UnknownPhysicalExpression`] error. - async fn get_group_from_physical_expression( - &self, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult; - - /// Retrieves all of the logical expression "children" of a group. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn get_group_logical_expressions( - &self, - group_id: Self::GroupId, - ) -> StorageResult>; - - /// Retrieves all of the physical expression "children" of a group. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn get_group_physical_expressions( - &self, - group_id: Self::GroupId, - ) -> StorageResult>; - - /// Retrieves the best physical query plan (winner) for a given group. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn get_winner( - &self, - group_id: Self::GroupId, - ) -> StorageResult>; - - /// Updates / replaces a group's best physical plan (winner). Optionally returns the previous - /// winner's physical expression ID. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn update_group_winner( - &self, - group_id: Self::GroupId, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult>; - - /// Adds a logical expression to an existing group via its [`Self::GroupId`]. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn add_logical_expression_to_group( - &self, - group_id: Self::GroupId, - logical_expression: Self::LogicalExpression, - children: Vec, - ) -> StorageResult<()>; - - /// Adds a physical expression to an existing group via its [`Self::GroupId`]. - /// - /// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. - async fn add_physical_expression_to_group( - &self, - group_id: Self::GroupId, - physical_expression: Self::PhysicalExpression, - children: Vec, - ) -> StorageResult<()>; - - /// Adds a new logical expression into the memo table, creating a new group if the expression - /// does not already exist. - /// - /// The [`Self::LogicalExpression`] type should have some sort of mechanism for checking if - /// the expression has been seen before, and if it has already been created, then the parent - /// group ID should also be retrievable. - /// - /// If the expression already exists, then this function will return the [`Self::GroupId`] of - /// the parent group and the corresponding (already existing) [`Self::LogicalExpressionId`]. - /// - /// If the expression does not exist, this function will create a new group and a new - /// expression, returning brand new IDs for both. - async fn add_logical_expression( - &self, - expression: Self::LogicalExpression, - children: Vec, - ) -> StorageResult<(Self::GroupId, Self::LogicalExpressionId)>; -} diff --git a/optd-persistent/src/memo/mod.rs b/optd-persistent/src/memo/mod.rs deleted file mode 100644 index c455782..0000000 --- a/optd-persistent/src/memo/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod expression; - -pub mod interface; -pub mod orm; diff --git a/optd-persistent/src/memo/orm.rs b/optd-persistent/src/memo/orm.rs deleted file mode 100644 index 6d4ec31..0000000 --- a/optd-persistent/src/memo/orm.rs +++ /dev/null @@ -1,213 +0,0 @@ -use crate::{ - entities::{prelude::*, *}, - BackendManager, {Memo, MemoError, StorageResult}, -}; -use sea_orm::*; - -impl Memo for BackendManager { - type Group = cascades_group::Model; - type GroupId = i32; - type LogicalExpression = logical_expression::Model; - type LogicalExpressionId = i32; - type PhysicalExpression = physical_expression::Model; - type PhysicalExpressionId = i32; - - async fn get_group(&self, group_id: Self::GroupId) -> StorageResult { - Ok(CascadesGroup::find_by_id(group_id) - .one(&self.db) - .await? - .ok_or(MemoError::UnknownGroup)?) - } - - async fn get_all_groups(&self) -> StorageResult> { - Ok(CascadesGroup::find().all(&self.db).await?) - } - - async fn get_logical_expression( - &self, - logical_expression_id: Self::LogicalExpressionId, - ) -> StorageResult { - Ok(LogicalExpression::find_by_id(logical_expression_id) - .one(&self.db) - .await? - .ok_or(MemoError::UnknownLogicalExpression)?) - } - - async fn get_physical_expression( - &self, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult { - Ok(PhysicalExpression::find_by_id(physical_expression_id) - .one(&self.db) - .await? - .ok_or(MemoError::UnknownPhysicalExpression)?) - } - - async fn get_group_from_logical_expression( - &self, - logical_expression_id: Self::LogicalExpressionId, - ) -> StorageResult { - // Find the logical expression and then look up the field. - Ok(self - .get_logical_expression(logical_expression_id) - .await? - .group_id) - } - - async fn get_group_from_physical_expression( - &self, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult { - Ok(self - .get_physical_expression(physical_expression_id) - .await? - .group_id) - } - - async fn get_group_logical_expressions( - &self, - group_id: Self::GroupId, - ) -> StorageResult> { - // First retrieve the group record, and then find all related logical expressions. - Ok(self - .get_group(group_id) - .await? - .find_related(LogicalExpression) - .all(&self.db) - .await?) - } - - async fn get_group_physical_expressions( - &self, - group_id: Self::GroupId, - ) -> StorageResult> { - // First retrieve the group record, and then find all related physical expressions. - Ok(self - .get_group(group_id) - .await? - .find_related(PhysicalExpression) - .all(&self.db) - .await?) - } - - async fn get_winner( - &self, - group_id: Self::GroupId, - ) -> StorageResult> { - Ok(self.get_group(group_id).await?.latest_winner) - } - - async fn update_group_winner( - &self, - group_id: Self::GroupId, - physical_expression_id: Self::PhysicalExpressionId, - ) -> StorageResult> { - // First retrieve the group record, and then use an `ActiveModel` to update it. - let mut group = self.get_group(group_id).await?.into_active_model(); - let old_id = group.latest_winner; - - group.latest_winner = Set(Some(physical_expression_id)); - group.update(&self.db).await?; - - // The old value must be set (`None` still means it has been set). - let old = old_id.unwrap(); - Ok(old) - } - - async fn add_logical_expression_to_group( - &self, - group_id: Self::GroupId, - logical_expression: Self::LogicalExpression, - _children: Vec, - ) -> StorageResult<()> { - if logical_expression.group_id != group_id { - Err(MemoError::InvalidExpression)? - } - - // Check if the group actually exists. - let _ = self.get_group(group_id).await?; - - // Insert the expression. - let _ = logical_expression - .into_active_model() - .insert(&self.db) - .await?; - - todo!("add the children of the logical expression into the children table") - } - - async fn add_physical_expression_to_group( - &self, - group_id: Self::GroupId, - physical_expression: Self::PhysicalExpression, - _children: Vec, - ) -> StorageResult<()> { - if physical_expression.group_id != group_id { - Err(MemoError::InvalidExpression)? - } - - // Check if the group actually exists. - let _ = self.get_group(group_id).await?; - - // Insert the expression. - let _ = physical_expression - .into_active_model() - .insert(&self.db) - .await?; - - todo!("add the children of the logical expression into the children table") - } - - /// Note that in this function, we ignore the group ID that the logical expression contains. - async fn add_logical_expression( - &self, - expression: Self::LogicalExpression, - _children: Vec, - ) -> StorageResult<(Self::GroupId, Self::LogicalExpressionId)> { - // Lookup all expressions that have the same fingerprint. There may be false positives, but - // we will check for those later. - let fingerprint = expression.fingerprint; - let potential_matches = LogicalExpression::find() - .filter(logical_expression::Column::Fingerprint.eq(fingerprint)) - .all(&self.db) - .await?; - - // Of the expressions that have the same fingerprint, check if there already exists an - // expression that is exactly identical to the input expression. - let mut matches: Vec<_> = potential_matches - .into_iter() - .filter(|expr| expr == &expression) - .collect(); - assert!( - matches.len() <= 1, - "there cannot be more than 1 exact logical expression match" - ); - - // The expression already exists, so return its data. - if !matches.is_empty() { - let existing_expression = matches - .pop() - .expect("we just checked that an element exists"); - - return Ok((existing_expression.group_id, existing_expression.id)); - } - - // The expression does not exist yet, so we need to create a new group and new expression. - let group = cascades_group::ActiveModel { - latest_winner: Set(None), - in_progress: Set(false), - is_optimized: Set(false), - ..Default::default() - }; - - // Insert a new group. - let res = cascades_group::Entity::insert(group).exec(&self.db).await?; - - // Insert the input expression with the correct `group_id`. - let mut new_expr = expression.into_active_model(); - new_expr.group_id = Set(res.last_insert_id); - let new_expr = new_expr.insert(&self.db).await?; - - Ok((new_expr.group_id, new_expr.id)) - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_attribute.rs deleted file mode 100644 index 543c745..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::migrator::catalog::table_metadata::TableMetadata; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum Attribute { - Table, - Id, - TableId, - Name, - CompressionMethod, - VariantTag, - BaseAttributeNumber, - IsNotNull, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Attribute::Table) - .if_not_exists() - .col(pk_auto(Attribute::Id)) - .col(integer(Attribute::TableId)) - .foreign_key( - ForeignKey::create() - .from(Attribute::Table, Attribute::TableId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(string(Attribute::Name)) - .col(char(Attribute::CompressionMethod)) - .col(integer(Attribute::VariantTag)) - .col(integer(Attribute::BaseAttributeNumber)) - .col(boolean(Attribute::IsNotNull)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Attribute::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_constraint_junction.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_constraint_junction.rs deleted file mode 100644 index c97ff99..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_constraint_junction.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! An entity representing the relationship between [`attribute`] and [`constraint`]. -//! -//! If a constraint is a table constraint (including foreign keys, but not constraint triggers), -//! the attributes that are constrained on are stored in the [`attribute_constraint_junction`]. -//! -//! One constraint might be associated with multiple attributes, for example, a composite primary key. - -use crate::migrator::catalog::{attribute::Attribute, constraint_metadata::ConstraintMetadata}; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum AttributeConstraintJunction { - Table, - AttributeId, - ConstraintId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(AttributeConstraintJunction::Table) - .if_not_exists() - .col(integer(AttributeConstraintJunction::AttributeId)) - .col(integer(AttributeConstraintJunction::ConstraintId)) - .primary_key( - Index::create() - .col(AttributeConstraintJunction::AttributeId) - .col(AttributeConstraintJunction::ConstraintId), - ) - .foreign_key( - ForeignKey::create() - .from( - AttributeConstraintJunction::Table, - AttributeConstraintJunction::AttributeId, - ) - .to(Attribute::Table, Attribute::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .foreign_key( - ForeignKey::create() - .from( - AttributeConstraintJunction::Table, - AttributeConstraintJunction::ConstraintId, - ) - .to(ConstraintMetadata::Table, ConstraintMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(AttributeConstraintJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_foreign_constraint_junction.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_foreign_constraint_junction.rs deleted file mode 100644 index 7b95600..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_attribute_foreign_constraint_junction.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! An entity representing the relationship between [`attribute`] and [`constraint`]. -//! -//! If a constraint is a foreign key constraint, the attributes that are referenced by the foreign -//! key are stored in the [`attribute_foreign_constraint_junction`]. Note that this is different from -//! the [`attribute_constraint_junction`] table, which stores the attributes that are constrained on. -//! In the case of a foreign key constraint, this refers to the attributes that are referecing from the -//! foreign key. -//! -//! One foreign key constraint might be associated with multiple attributes, for example, a composite -//! foreign key. - -use crate::migrator::catalog::{attribute::Attribute, constraint_metadata::ConstraintMetadata}; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum AttributeForeignConstraintJunction { - Table, - AttributeId, - ConstraintId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(AttributeForeignConstraintJunction::Table) - .if_not_exists() - .col(integer(AttributeForeignConstraintJunction::AttributeId)) - .col(integer(AttributeForeignConstraintJunction::ConstraintId)) - .primary_key( - Index::create() - .col(AttributeForeignConstraintJunction::AttributeId) - .col(AttributeForeignConstraintJunction::ConstraintId), - ) - .foreign_key( - ForeignKey::create() - .from( - AttributeForeignConstraintJunction::Table, - AttributeForeignConstraintJunction::AttributeId, - ) - .to(Attribute::Table, Attribute::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .foreign_key( - ForeignKey::create() - .from( - AttributeForeignConstraintJunction::Table, - AttributeForeignConstraintJunction::ConstraintId, - ) - .to(ConstraintMetadata::Table, ConstraintMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(AttributeForeignConstraintJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_constraint_metadata.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_constraint_metadata.rs deleted file mode 100644 index f6435eb..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_constraint_metadata.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::migrator::catalog::{index_metadata::IndexMetadata, table_metadata::TableMetadata}; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum ConstraintMetadata { - Table, - Id, - Name, - VariantTag, - TableId, - IndexId, - ForeignRefId, - CheckSrc, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(ConstraintMetadata::Table) - .if_not_exists() - .col(pk_auto(ConstraintMetadata::Id)) - .col(string(ConstraintMetadata::Name)) - .col(integer(ConstraintMetadata::VariantTag)) - .col(integer_null(ConstraintMetadata::TableId)) - .foreign_key( - ForeignKey::create() - .from(ConstraintMetadata::Table, ConstraintMetadata::TableId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer_null(ConstraintMetadata::IndexId)) - .foreign_key( - ForeignKey::create() - .from(ConstraintMetadata::Table, ConstraintMetadata::IndexId) - .to(IndexMetadata::Table, IndexMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer_null(ConstraintMetadata::ForeignRefId)) - .foreign_key( - ForeignKey::create() - .from(ConstraintMetadata::Table, ConstraintMetadata::ForeignRefId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(string(ConstraintMetadata::CheckSrc)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(ConstraintMetadata::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_database_metadata.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_database_metadata.rs deleted file mode 100644 index 4423557..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_database_metadata.rs +++ /dev/null @@ -1,35 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum DatabaseMetadata { - Table, - Id, - Name, - CreationTime, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(DatabaseMetadata::Table) - .if_not_exists() - .col(pk_auto(DatabaseMetadata::Id)) - .col(string(DatabaseMetadata::Name)) - .col(timestamp(DatabaseMetadata::CreationTime)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(DatabaseMetadata::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_index_metadata.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_index_metadata.rs deleted file mode 100644 index 1d51a6f..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_index_metadata.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::migrator::catalog::table_metadata::TableMetadata; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum IndexMetadata { - Table, - Id, - TableId, - Name, - NumberOfAttributes, - VariantTag, - IsUnique, - NullsNotDistinct, - IsPrimary, - IsClustered, - IsExclusion, - Description, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(IndexMetadata::Table) - .if_not_exists() - .col(pk_auto(IndexMetadata::Id)) - .col(integer(IndexMetadata::TableId)) - .foreign_key( - ForeignKey::create() - .from(IndexMetadata::Table, IndexMetadata::TableId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(string(IndexMetadata::Name)) - .col(integer(IndexMetadata::NumberOfAttributes)) - .col(integer(IndexMetadata::VariantTag)) - .col(boolean(IndexMetadata::IsUnique)) - .col(boolean(IndexMetadata::NullsNotDistinct)) - .col(boolean(IndexMetadata::IsPrimary)) - .col(boolean(IndexMetadata::IsClustered)) - .col(boolean(IndexMetadata::IsExclusion)) - .col(string(IndexMetadata::Description)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(IndexMetadata::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_table_metadata.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_table_metadata.rs deleted file mode 100644 index 66a0ec3..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_table_metadata.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::migrator::catalog::namespace_metadata::NamespaceMetadata; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum TableMetadata { - Table, - Id, - Name, - NamespaceId, - CreationTime, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(TableMetadata::Table) - .if_not_exists() - .col(pk_auto(TableMetadata::Id)) - .col(string(TableMetadata::Name)) - .col(integer(TableMetadata::NamespaceId)) - .foreign_key( - ForeignKey::create() - .from(TableMetadata::Table, TableMetadata::NamespaceId) - .to(NamespaceMetadata::Table, NamespaceMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(timestamp(TableMetadata::CreationTime)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(TableMetadata::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/m20241029_000001_trigger.rs b/optd-persistent/src/migrator/catalog/m20241029_000001_trigger.rs deleted file mode 100644 index c2bf0eb..0000000 --- a/optd-persistent/src/migrator/catalog/m20241029_000001_trigger.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::migrator::catalog::table_metadata::TableMetadata; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum Trigger { - Table, - Id, - Name, - TableId, - ParentTriggerId, - Function, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Trigger::Table) - .if_not_exists() - .col(pk_auto(Trigger::Id)) - .col(string(Trigger::Name)) - .col(integer(Trigger::TableId)) - .foreign_key( - ForeignKey::create() - .from(Trigger::Table, Trigger::TableId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(Trigger::ParentTriggerId)) - .foreign_key( - ForeignKey::create() - .from(Trigger::Table, Trigger::ParentTriggerId) - .to(Trigger::Table, Trigger::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(json(Trigger::Function)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Trigger::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/catalog/mod.rs b/optd-persistent/src/migrator/catalog/mod.rs deleted file mode 100644 index bef234a..0000000 --- a/optd-persistent/src/migrator/catalog/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub(crate) mod m20241029_000001_attribute; -pub(crate) mod m20241029_000001_attribute_constraint_junction; -pub(crate) mod m20241029_000001_attribute_foreign_constraint_junction; -pub(crate) mod m20241029_000001_constraint_metadata; -pub(crate) mod m20241029_000001_database_metadata; -pub(crate) mod m20241029_000001_index_metadata; -pub(crate) mod m20241029_000001_namespace_metadata; -pub(crate) mod m20241029_000001_table_metadata; -pub(crate) mod m20241029_000001_trigger; - -pub(crate) use m20241029_000001_attribute as attribute; -pub(crate) use m20241029_000001_attribute_constraint_junction as attribute_constraint_junction; -pub(crate) use m20241029_000001_attribute_foreign_constraint_junction as attribute_foreign_constraint_junction; -pub(crate) use m20241029_000001_constraint_metadata as constraint_metadata; -pub(crate) use m20241029_000001_database_metadata as database_metadata; -pub(crate) use m20241029_000001_index_metadata as index_metadata; -pub(crate) use m20241029_000001_namespace_metadata as namespace_metadata; -pub(crate) use m20241029_000001_table_metadata as table_metadata; -pub(crate) use m20241029_000001_trigger as trigger; diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_event.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_event.rs deleted file mode 100644 index 9fe326f..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_event.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Every time we insert/update statistics, we need to insert a new -//! row into this table to record the event. - -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum Event { - Table, - EpochId, - Timestamp, - SourceVariant, - Data, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Event::Table) - .if_not_exists() - .col(pk_auto(Event::EpochId)) - .col(timestamp(Event::Timestamp)) - .col(string(Event::SourceVariant)) - .col(json(Event::Data)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Event::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_physical_expression_to_statistic_junction.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_physical_expression_to_statistic_junction.rs deleted file mode 100644 index 06b8ac4..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_physical_expression_to_statistic_junction.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! This table stores for a physical expression, which statistics are used, so we -//! don't need to compute it again. It is especially useful for update_stats, where -//! we need to invalidate all the costs based on the physical_expression_id, so we -//! need to use this table to get the physical_expression_id via statistic_id. -//! -//! **NOTE:** When we compute the cost for a physical expression, we should also -//! insert related mappings into this table. - -use crate::migrator::cost_model::statistic::Statistic; -use crate::migrator::memo::physical_expression::PhysicalExpression; - -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum PhysicalExpressionToStatisticJunction { - Table, - PhysicalExpressionId, - StatisticId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PhysicalExpressionToStatisticJunction::Table) - .if_not_exists() - .col(integer( - PhysicalExpressionToStatisticJunction::PhysicalExpressionId, - )) - .col(integer(PhysicalExpressionToStatisticJunction::StatisticId)) - .primary_key( - Index::create() - .col(PhysicalExpressionToStatisticJunction::PhysicalExpressionId) - .col(PhysicalExpressionToStatisticJunction::StatisticId), - ) - .foreign_key( - ForeignKey::create() - .from( - PhysicalExpressionToStatisticJunction::Table, - PhysicalExpressionToStatisticJunction::PhysicalExpressionId, - ) - .to(PhysicalExpression::Table, PhysicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .foreign_key( - ForeignKey::create() - .from( - PhysicalExpressionToStatisticJunction::Table, - PhysicalExpressionToStatisticJunction::StatisticId, - ) - .to(Statistic::Table, Statistic::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(PhysicalExpressionToStatisticJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_plan_cost.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_plan_cost.rs deleted file mode 100644 index fdd2fef..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_plan_cost.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! When a statistic is updated, then all the related costs should be invalidated. (IsValid is set to false) -//! This design (using IsValid flag) is based on the assumption that update_stats will not be called very frequently. -//! It favors the compute_cost performance over the update_stats performance. -//! -//! This file stores cost like compute_cost, io_cost, network_cost, etc. for each physical expression. It also -//! stores the estimated output row count (estimated statistic) of each physical expression. -//! Sometimes we only have one of them to store, so we make Cost and EstimatedStatistic optional. But -//! one record must have at least one of them. -//! -//! TODO: Ideally, we can separate them since sometimes we only have the estimated output row count to store, -//! (when calling `derive_statistic`) but we don't have the detailed cost. - -use crate::migrator::cost_model::event::Event; -use crate::migrator::memo::physical_expression::PhysicalExpression; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum PlanCost { - Table, - Id, - PhysicalExpressionId, - EpochId, - // It is json type, including computation cost, I/O cost, etc. - Cost, - // Raw estimated output row count of this expression - EstimatedStatistic, - // Whether the cost is valid or not. If the latest cost for an expr is invalid, then we need to recompute the cost. - // We need to invalidate the cost when the related stats are updated. - IsValid, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PlanCost::Table) - .if_not_exists() - .col(pk_auto(PlanCost::Id)) - .col(integer(PlanCost::PhysicalExpressionId)) - .foreign_key( - ForeignKey::create() - .from(PlanCost::Table, PlanCost::PhysicalExpressionId) - .to(PhysicalExpression::Table, PhysicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(PlanCost::EpochId)) - .foreign_key( - ForeignKey::create() - .from(PlanCost::Table, PlanCost::EpochId) - .to(Event::Table, Event::EpochId) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(json_null(PlanCost::Cost)) - .col(float_null(PlanCost::EstimatedStatistic)) - .col(boolean(PlanCost::IsValid)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(PlanCost::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic.rs deleted file mode 100644 index 3b2bb3c..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! This table stores the statistic infos. One sole statistic only has one row in this table. -//! -//! If we want to insert a new statistic, we should first insert one row into this table, then add a new -//! event, and finally insert the statistic value into the versioned_statistic table. -//! If we want to update a statistic, we should first find the real statistic id from this table, then -//! add a new event, and finally insert the statistic value into the versioned_statistic table. - -use crate::migrator::catalog::m20241029_000001_table_metadata::TableMetadata; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum Statistic { - Table, - Id, - Name, - // null if not a table statistic. - TableId, - CreationTime, - // 0 if a table statistic. - NumberOfAttributes, - VariantTag, - // Store the sorted attribute ids of this statistic, to support quick lookup (OR we can use junction table to look up) - // For example, if we want to store the statistic of attributes [1, 2, 3], we can store it as "1,2,3". - // During lookup, we should first sort the attribute ids, and then look up. - // OR we can use statistic_to_attribute_junction table to look up. - Description, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Statistic::Table) - .if_not_exists() - .col(pk_auto(Statistic::Id)) - .col(string(Statistic::Name)) - .col(integer_null(Statistic::TableId)) - .foreign_key( - ForeignKey::create() - .from(Statistic::Table, Statistic::TableId) - .to(TableMetadata::Table, TableMetadata::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(timestamp(Statistic::CreationTime)) - .col(integer(Statistic::NumberOfAttributes)) - .col(integer(Statistic::VariantTag)) - .col(string(Statistic::Description)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Statistic::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic_to_attribute_junction.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic_to_attribute_junction.rs deleted file mode 100644 index 739675b..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_statistic_to_attribute_junction.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! An entity representing the relationship between [`statistic`] and [`attribute`]. -//! -//! One [`statistic`] can be associated with multiple [`attribute`]s, which denotes a joint -//! statistic for the attributes. On the other hand, one [`attribute`] can be associated with -//! multiple [`statistic`]s, since the attribute can be used in multiple statistics. - -use crate::migrator::catalog::attribute::Attribute; -use crate::migrator::cost_model::statistic::Statistic; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum StatisticToAttributeJunction { - Table, - StatisticId, - AttributeId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(StatisticToAttributeJunction::Table) - .if_not_exists() - .col(integer(StatisticToAttributeJunction::StatisticId)) - .col(integer(StatisticToAttributeJunction::AttributeId)) - .primary_key( - Index::create() - .col(StatisticToAttributeJunction::StatisticId) - .col(StatisticToAttributeJunction::AttributeId), - ) - .foreign_key( - ForeignKey::create() - .from( - StatisticToAttributeJunction::Table, - StatisticToAttributeJunction::StatisticId, - ) - .to(Statistic::Table, Statistic::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .foreign_key( - ForeignKey::create() - .from( - StatisticToAttributeJunction::Table, - StatisticToAttributeJunction::AttributeId, - ) - .to(Attribute::Table, Attribute::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(StatisticToAttributeJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/m20241029_000001_versioned_statistic.rs b/optd-persistent/src/migrator/cost_model/m20241029_000001_versioned_statistic.rs deleted file mode 100644 index f31d011..0000000 --- a/optd-persistent/src/migrator/cost_model/m20241029_000001_versioned_statistic.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! This table stores the versioned statistics. It includes all the histories of the statistics. -//! -//! If a statistic is updated/inserted, please insert one new row into this table. - -use crate::migrator::cost_model::{event::Event, statistic::Statistic}; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum VersionedStatistic { - Table, - Id, - EpochId, - // Real statistic id. - StatisticId, - StatisticValue, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(VersionedStatistic::Table) - .if_not_exists() - .col(pk_auto(VersionedStatistic::Id)) - .col(integer(VersionedStatistic::EpochId)) - .foreign_key( - ForeignKey::create() - .from(VersionedStatistic::Table, VersionedStatistic::EpochId) - .to(Event::Table, Event::EpochId) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(VersionedStatistic::StatisticId)) - .foreign_key( - ForeignKey::create() - .from(VersionedStatistic::Table, VersionedStatistic::StatisticId) - .to(Statistic::Table, Statistic::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(json(VersionedStatistic::StatisticValue)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(VersionedStatistic::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/cost_model/mod.rs b/optd-persistent/src/migrator/cost_model/mod.rs deleted file mode 100644 index 5f8dad1..0000000 --- a/optd-persistent/src/migrator/cost_model/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub(crate) mod m20241029_000001_event; -pub(crate) mod m20241029_000001_physical_expression_to_statistic_junction; -pub(crate) mod m20241029_000001_plan_cost; -pub(crate) mod m20241029_000001_statistic; -pub(crate) mod m20241029_000001_statistic_to_attribute_junction; -pub(crate) mod m20241029_000001_versioned_statistic; - -pub(crate) use m20241029_000001_event as event; -pub(crate) use m20241029_000001_physical_expression_to_statistic_junction as physical_expression_to_statistic_junction; -pub(crate) use m20241029_000001_plan_cost as plan_cost; -pub(crate) use m20241029_000001_statistic as statistic; -pub(crate) use m20241029_000001_statistic_to_attribute_junction as statistic_to_attribute_junction; -pub(crate) use m20241029_000001_versioned_statistic as versioned_statistic; diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_group_winner.rs b/optd-persistent/src/migrator/memo/m20241029_000001_group_winner.rs deleted file mode 100644 index bd952c9..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_group_winner.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! An entity representing a the best physical plan (or "winner") of a Cascades group. -//! -//! In the Cascades framework, query optimization is done through dynamic programming that is based -//! on the assumption that the cost model satisfies the _principle of optimality_. Quoted from the -//! Microsoft article _Extensible query optimizers in practice_: -//! -//! > ... in the search space of linear sequence of joins, the optimal plan for a join of n -//! > relations can be found by extending the optimal plan of a sub-expression of n - 1 joins with -//! > an additional join. -//! -//! By storing the best sub-plans / [`physical_expression`]s of smaller Cascades groups, we can -//! build up an optimal query plan. -//! -//! This entity represents the best plan sub-tree for a specific group. However, we store multiple -//! winners over different epochs, as changes to the database may require us to re-evaluate what the -//! optimal sub-plan is. -//! -//! # Columns -//! -//! Other than the primary key, all of the columns in this relation are foreign keys to other -//! tables. -//! -//! A group winner is defined by the [`cascades_group`] it belongs to (`group_id`), the unique ID of -//! the [`physical_expression`] (`physical_expression_id`), the ID of the cost record in the -//! [`plan_cost`] table (`cost_id`), and the monotonically-increasing epoch ID in the [`event`] -//! table (`epoch_id`). -//! -//! [`cascades_group`]: super::cascades_group -//! [`physical_expression`]: super::physical_expression -//! [`plan_cost`]: super::super::cost_model::plan_cost -//! [`event`]: super::super::cost_model::event - -use crate::migrator::cost_model::{event::Event, plan_cost::PlanCost}; -use crate::migrator::memo::{ - cascades_group::CascadesGroup, physical_expression::PhysicalExpression, -}; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(Iden)] -pub enum GroupWinner { - Table, - Id, - GroupId, - PhysicalExpressionId, - CostId, - EpochId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(GroupWinner::Table) - .if_not_exists() - .col(pk_auto(GroupWinner::Id)) - .col(integer(GroupWinner::GroupId)) - .foreign_key( - ForeignKey::create() - .from(GroupWinner::Table, GroupWinner::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(GroupWinner::PhysicalExpressionId)) - .foreign_key( - ForeignKey::create() - .from(GroupWinner::Table, GroupWinner::PhysicalExpressionId) - .to(PhysicalExpression::Table, PhysicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(GroupWinner::CostId)) - .foreign_key( - ForeignKey::create() - .from(GroupWinner::Table, GroupWinner::CostId) - .to(PlanCost::Table, PlanCost::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(GroupWinner::EpochId)) - .foreign_key( - ForeignKey::create() - .from(GroupWinner::Table, GroupWinner::EpochId) - .to(Event::Table, Event::EpochId) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(GroupWinner::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_logical_property.rs b/optd-persistent/src/migrator/memo/m20241029_000001_logical_property.rs deleted file mode 100644 index 4b10da6..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_logical_property.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! An entity representing a logical property of a Cascades group. -//! -//! TODO what exactly are we storing in here? -//! TODO why is it linked to only cascades groups and not logical expressions? - -use crate::migrator::memo::cascades_group::CascadesGroup; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveIden)] -pub enum LogicalProperty { - Table, - Id, - GroupId, - VariantTag, - Data, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(LogicalProperty::Table) - .if_not_exists() - .col(pk_auto(LogicalProperty::Id)) - .col(integer(LogicalProperty::GroupId)) - .foreign_key( - ForeignKey::create() - .from(LogicalProperty::Table, LogicalProperty::GroupId) - .to(CascadesGroup::Table, CascadesGroup::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(small_integer(LogicalProperty::VariantTag)) - .col(json(LogicalProperty::Data)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(LogicalProperty::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_physical_property.rs b/optd-persistent/src/migrator/memo/m20241029_000001_physical_property.rs deleted file mode 100644 index 262ae41..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_physical_property.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! An entity representing a physical property of a physical expression in the Cascades framework. -//! -//! TODO what exactly are we storing in here? -//! TODO why is it linked to only physical expressions and not cascades groups? - -use crate::migrator::memo::physical_expression::PhysicalExpression; -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveIden)] -pub enum PhysicalProperty { - Table, - Id, - PhysicalExpressionId, - VariantTag, - Data, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PhysicalProperty::Table) - .if_not_exists() - .col(pk_auto(PhysicalProperty::Id)) - .col(integer(PhysicalProperty::PhysicalExpressionId)) - .foreign_key( - ForeignKey::create() - .from( - PhysicalProperty::Table, - PhysicalProperty::PhysicalExpressionId, - ) - .to(PhysicalExpression::Table, PhysicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(small_integer(PhysicalProperty::VariantTag)) - .col(json(PhysicalProperty::Data)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(PhysicalProperty::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_predicate.rs b/optd-persistent/src/migrator/memo/m20241029_000001_predicate.rs deleted file mode 100644 index b4a58b9..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_predicate.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* -Table predicate { - id integer [pk] - data json - variant integer -} -*/ - -use sea_orm_migration::{ - prelude::*, - schema::{integer, json, pk_auto}, -}; - -#[derive(Iden)] -pub enum Predicate { - Table, - Id, - Data, - Variant, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Predicate::Table) - .if_not_exists() - .col(pk_auto(Predicate::Id)) - .col(json(Predicate::Data)) - .col(integer(Predicate::Variant)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Predicate::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_children.rs b/optd-persistent/src/migrator/memo/m20241029_000001_predicate_children.rs deleted file mode 100644 index f3c0d10..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_children.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* -Table predicate_children { - parent_id integer [ref: > predicate.id] - child_id integer [ref: > predicate.id] -} - */ - -use sea_orm_migration::{prelude::*, schema::integer}; - -use super::m20241029_000001_predicate::Predicate; - -#[derive(Iden)] -pub enum PredicateChildren { - Table, - ParentId, - ChildId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PredicateChildren::Table) - .if_not_exists() - .col(integer(PredicateChildren::ParentId)) - .foreign_key( - ForeignKey::create() - .from(PredicateChildren::Table, PredicateChildren::ParentId) - .to(Predicate::Table, Predicate::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(PredicateChildren::ChildId)) - .foreign_key( - ForeignKey::create() - .from(PredicateChildren::Table, PredicateChildren::ChildId) - .to(Predicate::Table, Predicate::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .primary_key( - Index::create() - .col(PredicateChildren::ParentId) - .col(PredicateChildren::ChildId), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(PredicateChildren::Table).to_owned()) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_logical_expression_junction.rs b/optd-persistent/src/migrator/memo/m20241029_000001_predicate_logical_expression_junction.rs deleted file mode 100644 index ab901d6..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_logical_expression_junction.rs +++ /dev/null @@ -1,72 +0,0 @@ -/* -Table predicate_logical_expression_junction { - logical_expr_id integer [ref: > logical_expression.id] - predicate_id integer [ref: > predicate.id] -} - */ - -use sea_orm_migration::{prelude::*, schema::integer}; - -use super::{ - m20241029_000001_logical_expression::LogicalExpression, m20241029_000001_predicate::Predicate, -}; - -#[derive(Iden)] -pub enum PredicateLogicalExpressionJunction { - Table, - LogicalExprId, - PredicateId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PredicateLogicalExpressionJunction::Table) - .col(integer(PredicateLogicalExpressionJunction::LogicalExprId)) - .foreign_key( - ForeignKey::create() - .from( - PredicateLogicalExpressionJunction::Table, - PredicateLogicalExpressionJunction::LogicalExprId, - ) - .to(LogicalExpression::Table, LogicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(PredicateLogicalExpressionJunction::PredicateId)) - .foreign_key( - ForeignKey::create() - .from( - PredicateLogicalExpressionJunction::Table, - PredicateLogicalExpressionJunction::PredicateId, - ) - .to(Predicate::Table, Predicate::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .primary_key( - Index::create() - .col(PredicateLogicalExpressionJunction::LogicalExprId) - .col(PredicateLogicalExpressionJunction::PredicateId), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(PredicateLogicalExpressionJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_physical_expression_junction.rs b/optd-persistent/src/migrator/memo/m20241029_000001_predicate_physical_expression_junction.rs deleted file mode 100644 index 8d82831..0000000 --- a/optd-persistent/src/migrator/memo/m20241029_000001_predicate_physical_expression_junction.rs +++ /dev/null @@ -1,74 +0,0 @@ -/* -Table predicate_physical_expression_junction { - physical_expr_id integer [ref: > physical_expression.id] - predicate_id integer [ref: > predicate.id] -} - */ - -use sea_orm_migration::{prelude::*, schema::integer}; - -use super::{ - m20241029_000001_physical_expression::PhysicalExpression, m20241029_000001_predicate::Predicate, -}; - -#[derive(Iden)] -pub enum PredicatePhysicalExpressionJunction { - Table, - PhysicalExprId, - PredicateId, -} - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(PredicatePhysicalExpressionJunction::Table) - .col(integer(PredicatePhysicalExpressionJunction::PhysicalExprId)) - .foreign_key( - ForeignKey::create() - .name("predicate_physical_expression_junction_physical_expr_id_fkey") - .from( - PredicatePhysicalExpressionJunction::Table, - PredicatePhysicalExpressionJunction::PhysicalExprId, - ) - .to(PhysicalExpression::Table, PhysicalExpression::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .col(integer(PredicatePhysicalExpressionJunction::PredicateId)) - .foreign_key( - ForeignKey::create() - .name("predicate_physical_expression_junction_predicate_id_fkey") - .from( - PredicatePhysicalExpressionJunction::Table, - PredicatePhysicalExpressionJunction::PredicateId, - ) - .to(Predicate::Table, Predicate::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .primary_key( - Index::create() - .col(PredicatePhysicalExpressionJunction::PhysicalExprId) - .col(PredicatePhysicalExpressionJunction::PredicateId), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table( - Table::drop() - .table(PredicatePhysicalExpressionJunction::Table) - .to_owned(), - ) - .await - } -} diff --git a/optd-persistent/src/migrator/memo/mod.rs b/optd-persistent/src/migrator/memo/mod.rs deleted file mode 100644 index b4caabf..0000000 --- a/optd-persistent/src/migrator/memo/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Entities related to the memo table used for dynamic programming in the Cascades query -//! optimization framework. - -pub(crate) mod m20241029_000001_cascades_group; -pub(crate) mod m20241029_000001_group_winner; -pub(crate) mod m20241029_000001_logical_children; -pub(crate) mod m20241029_000001_logical_expression; -pub(crate) mod m20241029_000001_logical_property; -pub(crate) mod m20241029_000001_physical_children; -pub(crate) mod m20241029_000001_physical_expression; -pub(crate) mod m20241029_000001_physical_property; -pub(crate) mod m20241029_000001_predicate; -pub(crate) mod m20241029_000001_predicate_children; -pub(crate) mod m20241029_000001_predicate_logical_expression_junction; -pub(crate) mod m20241029_000001_predicate_physical_expression_junction; - -pub(crate) use m20241029_000001_cascades_group as cascades_group; -pub(crate) use m20241029_000001_group_winner as group_winner; -pub(crate) use m20241029_000001_logical_children as logical_children; -pub(crate) use m20241029_000001_logical_expression as logical_expression; -pub(crate) use m20241029_000001_logical_property as logical_property; -pub(crate) use m20241029_000001_physical_children as physical_children; -pub(crate) use m20241029_000001_physical_expression as physical_expression; -pub(crate) use m20241029_000001_physical_property as physical_property; -pub(crate) use m20241029_000001_predicate as predicate; -pub(crate) use m20241029_000001_predicate_children as predicate_children; -pub(crate) use m20241029_000001_predicate_logical_expression_junction as predicate_logical_expression_junction; -pub(crate) use m20241029_000001_predicate_physical_expression_junction as predicate_physical_expression_junction; diff --git a/optd-persistent/src/migrator/mod.rs b/optd-persistent/src/migrator/mod.rs deleted file mode 100644 index 468f7d0..0000000 --- a/optd-persistent/src/migrator/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -use sea_orm_migration::prelude::*; - -mod catalog; -mod cost_model; -mod memo; - -pub struct Migrator; - -#[async_trait::async_trait] -impl MigratorTrait for Migrator { - fn migrations() -> Vec> { - vec![ - Box::new(catalog::database_metadata::Migration), - Box::new(catalog::namespace_metadata::Migration), - Box::new(catalog::table_metadata::Migration), - Box::new(catalog::attribute::Migration), - Box::new(catalog::attribute_constraint_junction::Migration), - Box::new(catalog::attribute_foreign_constraint_junction::Migration), - Box::new(catalog::index_metadata::Migration), - Box::new(catalog::trigger::Migration), - Box::new(catalog::constraint_metadata::Migration), - Box::new(cost_model::statistic::Migration), - Box::new(cost_model::versioned_statistic::Migration), - Box::new(cost_model::statistic_to_attribute_junction::Migration), - Box::new(cost_model::physical_expression_to_statistic_junction::Migration), - Box::new(cost_model::event::Migration), - Box::new(cost_model::plan_cost::Migration), - Box::new(memo::cascades_group::Migration), - Box::new(memo::group_winner::Migration), - Box::new(memo::logical_expression::Migration), - Box::new(memo::logical_children::Migration), - Box::new(memo::logical_property::Migration), - Box::new(memo::physical_expression::Migration), - Box::new(memo::physical_children::Migration), - Box::new(memo::physical_property::Migration), - Box::new(memo::predicate::Migration), - Box::new(memo::predicate_children::Migration), - Box::new(memo::predicate_logical_expression_junction::Migration), - Box::new(memo::predicate_physical_expression_junction::Migration), - ] - } -} diff --git a/schema/all_tables.dbml b/schema/all_tables.dbml deleted file mode 100644 index 29a2136..0000000 --- a/schema/all_tables.dbml +++ /dev/null @@ -1,216 +0,0 @@ -// Use DBML to define your database structure -// Docs: https://dbml.dbdiagram.io/docs - -Table database_metadata { - id integer PK - name varchar - creation_time timestamp -} - -Table namespace_metadata { - id integer PK - database_id integer [ref: > database_metadata.id] - name varchar - creation_time timestamp -} - -Table table_metadata { - id integer PK - namespace_id integer [ref: > namespace_metadata.id] - name varchar - creation_time timestamp -} - -Table attribute { - id integer PK // global index - table_id integer [ref: > table_metadata.id] - name varchar - compression_method char - variant_tag integer // Data type of this attribute. Should we make another table to explain the type mapping? - base_attribute_number integer // local index within the table - is_not_null boolean // physical property -} - -Table statistic { - id integer PK - name varchar - table_id integer [ref: > table_metadata.id, null] // null if not a table statistic - creation_time timestamp - number_of_attributes integer // 0 if a table statistic - variant_tag integer // Should we make another table to explain the type mapping? - description varchar // Store the sorted attribute ids of this statistic, to support quick lookup (OR we can use junction table to look up) -} - -Table versioned_statistic { - id integer PK - epoch_id integer [ref: > event.epoch_id] - statistic_id integer [ref: > statistic.id] - statistic_value json -} - -Table event { - epoch_id integer PK - source_variant varchar - create_timestamp timestamp - data json -} - -Table plan_cost { - id integer PK - physical_expression_id integer [ref: > physical_expression.id] - epoch_id integer [ref: > event.epoch_id] - // It is json type, including computation cost, I/O cost, etc. - cost json [null] - // Raw estimated output row count of this expression - estimated_statistic float [null] - // Whether the cost is valid or not. If the latest cost for an expr is invalid, then we need to recompute the cost. - // We need to invalidate the cost when the related stats are updated. - is_valid boolean -} - -Table index { - id integer PK - name varchar - table_id integer [ref: > table_metadata.id] - // Whether it is an unique index. - is_unique boolean - // Only valid for unique index, if true, then null value is equal, if false, null value is distinct. - nulls_not_distinct boolean - // Whether the attribute is primary. - is_primary boolean - // If true, the table was last clustered on this index - is_clustered boolean - // More fields might be added in the future for expressiveness on exclusion constraint. - is_exclusion boolean - // Do we need it? - number_of_attributes integer - // Stores the related attribute ids. - data json -} - -Table trigger { - id integer PK - name varchar - table_id integer [ref: > table_metadata.id] - // This field is only valid if it is triggered by another parent trigger. - parent_trigger_id integer [ref: > trigger.id] - function json -} - -// Not-null is handled directly in `attribute`. See `is_not_null` field. -// Constraint trigger is handled directly in `trigger`. -Table constraint { - id integer PK - name varchar - variant_tag integer // pk, fk, unique, check, exclusion - table_id integer [ref: > table_metadata.id, null] // null if not a table constraint - index_id integer [ref: > index.id, null] // The index supporting this constraint, if it's a unique, primary key, foreign key, or exclusion constraint; else null - foreign_ref_id integer [ref: > table_metadata.id, null] // If a foreign key, the referenced table; else null - check_src varchar // the expression tree for a check constraint, which provides a textual representation of the constraint expression -} - -// The constrained attributes (columns) if a constraint is a table constraint (including foreign keys, but not constraint triggers) -Table attribute_constraint_junction { - attribute_id integer [ref: > attribute.id] - constraint_id integer [ref: > constraint.id] -} - -// The referenced attributes (columns) if the constraint is a foreign key -Table attribute_foreign_constraint_junction { - attribute_id integer [ref: > attribute.id] - constraint_id integer [ref: > constraint.id] -} - -Table statistic_to_attribute_junction { - statistic_id integer [ref: > statistic.id] - attribute_id integer [ref: > attribute.id] -} - -Table physical_expression_to_statistic_junction { - physical_expression_id integer [ref: > physical_expression.id] - statistic_id integer [ref: > statistic.id] -} - -// Logical expressions and groups -Table logical_expression { - id integer [pk] - group_id integer [ref: > cascades_group.id] - fingerprint integer - variant_tag integer - predicate integer [ref: > predicate.id] -} - -Table cascades_group { - id integer [pk] - latest_winner integer [ref: > physical_expression.id, null] - in_progress boolean - is_optimized boolean - parent integer [ref: > cascades_group.id] -} - -// Physical expressions and properties -Table physical_expression { - id integer [pk] - group_id integer [ref: > cascades_group.id] - fingerprint integer - variant_tag integer - predicate integer [ref: > predicate.id] -} - -Table physical_property { - id integer [pk] - physical_expression_id integer [ref: > physical_expression.id] - variant_tag integer - data json -} - -// Junction tables -Table logical_group_junction { - group_id integer [ref: > cascades_group.id] - logical_expression_id integer [ref: > logical_expression.id] -} - -Table physical_group_junction { - group_id integer [ref: > cascades_group.id] - physical_expression_id integer [ref: > physical_expression.id] -} - -// Properties -Table logical_property { - id integer [pk] - group_id integer [ref: > cascades_group.id] - variant_tag integer - data json -} - -// Winners tracking -Table group_winner { - id integer [pk] - group_id integer [ref: > cascades_group.id] - physical_expression_id integer [ref: > physical_expression.id] - cost integer - epoch_id integer [ref: > event.epoch_id] -} - -Table predicate { - id integer [pk] - data json - variant integer -} - -Table predicate_children { - parent_id integer [ref: > predicate.id] - child_id integer [ref: > predicate.id] -} - -Table predicate_logical_expression_junction { - logical_expr_id integer [ref: > logical_expression.id] - predicate_id integer [ref: > predicate.id] -} - -Table predicate_physical_expression_junction { - physical_expr_id integer [ref: > physical_expression.id] - predicate_id integer [ref: > predicate.id] -} - -