From a472c1c51f79f1431e359354787b54b5a4725677 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sat, 4 Oct 2025 22:57:07 +0200 Subject: [PATCH 01/82] install unixodbc before cargo publish --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e67936fd..e32cf37e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -150,5 +150,6 @@ jobs: - uses: actions/checkout@v4 - name: Set up cargo cache uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + - run: sudo apt-get update && sudo apt-get install -y unixodbc-dev - name: Publish to crates.io run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} From 2f37d2ddd1e43d6efc4df1506b6944dbb1df8d92 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sat, 4 Oct 2025 23:18:35 +0200 Subject: [PATCH 02/82] add lambda-web feature and update CI to test with odbc-static --- .github/workflows/ci.yml | 4 ++-- Cargo.toml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87bae98b..7eb315db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 - run: cargo fmt --all -- --check - run: cargo clippy --all-targets --all-features -- -D warnings - - run: cargo test --all-features + - run: cargo test --features odbc-static - name: Upload Linux binary uses: actions/upload-artifact@v4 with: @@ -70,7 +70,7 @@ jobs: run: docker compose logs ${{ matrix.container }} - name: Run tests against ${{ matrix.database }} timeout-minutes: 5 - run: cargo test --all-features + run: cargo test --features odbc-static env: DATABASE_URL: ${{ matrix.db_url }} RUST_BACKTRACE: 1 diff --git a/Cargo.toml b/Cargo.toml index 62f86d3c..3b496eb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ odbc-sys = { version = "0.27", features = [], optional = false } [features] default = [] odbc-static = ["odbc-sys/static"] +lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] From cf1e58534010c2cef4fc5024bc96a746c47d1bb7 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 09:26:05 +0200 Subject: [PATCH 03/82] update feature and compatibility sections in homepage template with IDs for improved accessibility --- .../official-site/sqlpage/templates/shell-home.handlebars | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/official-site/sqlpage/templates/shell-home.handlebars b/examples/official-site/sqlpage/templates/shell-home.handlebars index 095c6b73..b4203fa4 100644 --- a/examples/official-site/sqlpage/templates/shell-home.handlebars +++ b/examples/official-site/sqlpage/templates/shell-home.handlebars @@ -1375,7 +1375,7 @@ -
+

More scalable than a spreadsheet

@@ -1391,7 +1391,7 @@
-
+

More dynamic than a dashboard

@@ -1411,7 +1411,7 @@
-
+
Database Compatibility
From bac0ffc14ee75b373b9eb2a1023df182cb014a3e Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 09:40:47 +0200 Subject: [PATCH 04/82] fromascasing --- lambda.Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lambda.Dockerfile b/lambda.Dockerfile index fcd476d4..50b71423 100644 --- a/lambda.Dockerfile +++ b/lambda.Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.90-alpine as builder +FROM rust:1.90-alpine AS builder RUN rustup component add clippy rustfmt RUN apk add --no-cache musl-dev zip WORKDIR /usr/src/sqlpage @@ -13,7 +13,7 @@ RUN mv target/release/sqlpage bootstrap && \ ldd bootstrap && \ zip -9 -r deploy.zip bootstrap index.sql -FROM public.ecr.aws/lambda/provided:al2 as runner +FROM public.ecr.aws/lambda/provided:al2 AS runner COPY --from=builder /usr/src/sqlpage/bootstrap /main COPY --from=builder /usr/src/sqlpage/index.sql ./index.sql ENTRYPOINT ["/main"] \ No newline at end of file From 05b7a55f48f4577de3352de815498fdd4bfabd7e Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 09:45:54 +0200 Subject: [PATCH 05/82] Dockerfile: statically link odbc --- Dockerfile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5d83e202..4f617bb8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update && \ if [ "$TARGETARCH" = "$BUILDARCH" ]; then \ rustup target list --installed > TARGET && \ echo gcc > LINKER && \ - apt-get install -y gcc libgcc-s1 cmake unixodbc-dev libltdl-dev pkg-config && \ + apt-get install -y gcc libgcc-s1 cmake pkg-config && \ LIBMULTIARCH=$(gcc -print-multiarch); \ LIBDIR="/lib/$LIBMULTIARCH"; \ USRLIBDIR="/usr/lib/$LIBMULTIARCH"; \ @@ -16,7 +16,7 @@ RUN apt-get update && \ echo aarch64-unknown-linux-gnu > TARGET && \ echo aarch64-linux-gnu-gcc > LINKER && \ dpkg --add-architecture arm64 && apt-get update && \ - apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross unixodbc-dev:arm64 libltdl-dev:arm64 pkg-config && \ + apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config && \ LIBDIR="/lib/aarch64-linux-gnu"; \ USRLIBDIR="/usr/lib/aarch64-linux-gnu"; \ HOST_TRIPLE="aarch64-linux-gnu"; \ @@ -24,7 +24,7 @@ RUN apt-get update && \ echo armv7-unknown-linux-gnueabihf > TARGET && \ echo arm-linux-gnueabihf-gcc > LINKER && \ dpkg --add-architecture armhf && apt-get update && \ - apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang unixodbc-dev:armhf libltdl-dev:armhf pkg-config && \ + apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang pkg-config && \ cargo install --force --locked bindgen-cli && \ SYSROOT=$(arm-linux-gnueabihf-gcc -print-sysroot); \ echo "--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/usr/include/arm-linux-gnueabihf" > BINDGEN_EXTRA_CLANG_ARGS; \ @@ -35,7 +35,6 @@ RUN apt-get update && \ echo "Unsupported cross compilation target: $TARGETARCH"; \ exit 1; \ fi && \ - echo $USRLIBDIR > ODBC_LIBDIR && \ cp $LIBDIR/libgcc_s.so.1 /opt/sqlpage-libs/ && \ rustup target add $(cat TARGET) && \ cargo init . @@ -43,19 +42,19 @@ RUN apt-get update && \ # Build dependencies (creates a layer that avoids recompiling dependencies on every build) COPY Cargo.toml Cargo.lock ./ RUN BINDGEN_EXTRA_CLANG_ARGS=$(cat BINDGEN_EXTRA_CLANG_ARGS || true) \ - RS_ODBC_LINK_SEARCH=$(cat ODBC_LIBDIR) \ cargo build \ --target $(cat TARGET) \ --config target.$(cat TARGET).linker='"'$(cat LINKER)'"' \ + --features odbc-static \ --profile superoptimized # Build the project COPY . . RUN touch src/main.rs && \ - RS_ODBC_LINK_SEARCH=$(cat ODBC_LIBDIR) \ cargo build \ --target $(cat TARGET) \ --config target.$(cat TARGET).linker='"'$(cat LINKER)'"' \ + --features odbc-static \ --profile superoptimized && \ mv target/$(cat TARGET)/superoptimized/sqlpage sqlpage.bin From 656c73f86df8e4f2869f26458e472ae2fa7aa3ed Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 10:22:37 +0200 Subject: [PATCH 06/82] Dockerfile: update library paths for aarch64 and arm architectures --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4f617bb8..4f6a89d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && \ dpkg --add-architecture arm64 && apt-get update && \ apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config && \ LIBDIR="/lib/aarch64-linux-gnu"; \ - USRLIBDIR="/usr/lib/aarch64-linux-gnu"; \ + USRLIBDIR="/usr/aarch64-linux-gnu/lib"; \ HOST_TRIPLE="aarch64-linux-gnu"; \ elif [ "$TARGETARCH" = "arm" ]; then \ echo armv7-unknown-linux-gnueabihf > TARGET && \ @@ -29,7 +29,7 @@ RUN apt-get update && \ SYSROOT=$(arm-linux-gnueabihf-gcc -print-sysroot); \ echo "--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/usr/include/arm-linux-gnueabihf" > BINDGEN_EXTRA_CLANG_ARGS; \ LIBDIR="/lib/arm-linux-gnueabihf"; \ - USRLIBDIR="/usr/lib/arm-linux-gnueabihf"; \ + USRLIBDIR="/usr/arm-linux-gnueabihf/lib"; \ HOST_TRIPLE="arm-linux-gnueabihf"; \ else \ echo "Unsupported cross compilation target: $TARGETARCH"; \ From b278764b18f35b3283eda168ca3beb42427f9100 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 10:41:13 +0200 Subject: [PATCH 07/82] Dockerfile: extract scripts to separate files --- Dockerfile | 63 ++++++------------------------ scripts/README.md | 20 ++++++++++ scripts/build-dependencies.sh | 16 ++++++++ scripts/build-project.sh | 19 +++++++++ scripts/setup-cross-compilation.sh | 55 ++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 50 deletions(-) create mode 100644 scripts/README.md create mode 100755 scripts/build-dependencies.sh create mode 100755 scripts/build-project.sh create mode 100755 scripts/setup-cross-compilation.sh diff --git a/Dockerfile b/Dockerfile index 4f6a89d0..f3ea20f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,62 +1,25 @@ FROM --platform=$BUILDPLATFORM rust:1.90-slim AS builder + WORKDIR /usr/src/sqlpage ARG TARGETARCH ARG BUILDARCH -RUN apt-get update && \ - mkdir -p /opt/sqlpage-libs && \ - if [ "$TARGETARCH" = "$BUILDARCH" ]; then \ - rustup target list --installed > TARGET && \ - echo gcc > LINKER && \ - apt-get install -y gcc libgcc-s1 cmake pkg-config && \ - LIBMULTIARCH=$(gcc -print-multiarch); \ - LIBDIR="/lib/$LIBMULTIARCH"; \ - USRLIBDIR="/usr/lib/$LIBMULTIARCH"; \ - HOST_TRIPLE=$(gcc -dumpmachine); \ - elif [ "$TARGETARCH" = "arm64" ]; then \ - echo aarch64-unknown-linux-gnu > TARGET && \ - echo aarch64-linux-gnu-gcc > LINKER && \ - dpkg --add-architecture arm64 && apt-get update && \ - apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config && \ - LIBDIR="/lib/aarch64-linux-gnu"; \ - USRLIBDIR="/usr/aarch64-linux-gnu/lib"; \ - HOST_TRIPLE="aarch64-linux-gnu"; \ - elif [ "$TARGETARCH" = "arm" ]; then \ - echo armv7-unknown-linux-gnueabihf > TARGET && \ - echo arm-linux-gnueabihf-gcc > LINKER && \ - dpkg --add-architecture armhf && apt-get update && \ - apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang pkg-config && \ - cargo install --force --locked bindgen-cli && \ - SYSROOT=$(arm-linux-gnueabihf-gcc -print-sysroot); \ - echo "--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/usr/include/arm-linux-gnueabihf" > BINDGEN_EXTRA_CLANG_ARGS; \ - LIBDIR="/lib/arm-linux-gnueabihf"; \ - USRLIBDIR="/usr/arm-linux-gnueabihf/lib"; \ - HOST_TRIPLE="arm-linux-gnueabihf"; \ - else \ - echo "Unsupported cross compilation target: $TARGETARCH"; \ - exit 1; \ - fi && \ - cp $LIBDIR/libgcc_s.so.1 /opt/sqlpage-libs/ && \ - rustup target add $(cat TARGET) && \ - cargo init . + +# Copy build scripts +COPY scripts/ /usr/local/bin/ + +# Initialize cargo project +RUN cargo init . + +# Setup cross-compilation environment +RUN /usr/local/bin/setup-cross-compilation.sh "$TARGETARCH" "$BUILDARCH" # Build dependencies (creates a layer that avoids recompiling dependencies on every build) COPY Cargo.toml Cargo.lock ./ -RUN BINDGEN_EXTRA_CLANG_ARGS=$(cat BINDGEN_EXTRA_CLANG_ARGS || true) \ - cargo build \ - --target $(cat TARGET) \ - --config target.$(cat TARGET).linker='"'$(cat LINKER)'"' \ - --features odbc-static \ - --profile superoptimized +RUN /usr/local/bin/build-dependencies.sh # Build the project COPY . . -RUN touch src/main.rs && \ - cargo build \ - --target $(cat TARGET) \ - --config target.$(cat TARGET).linker='"'$(cat LINKER)'"' \ - --features odbc-static \ - --profile superoptimized && \ - mv target/$(cat TARGET)/superoptimized/sqlpage sqlpage.bin +RUN /usr/local/bin/build-project.sh FROM busybox:glibc RUN addgroup --gid 1000 --system sqlpage && \ @@ -69,7 +32,7 @@ ENV SQLPAGE_CONFIGURATION_DIRECTORY=/etc/sqlpage WORKDIR /var/www COPY --from=builder /usr/src/sqlpage/sqlpage.bin /usr/local/bin/sqlpage # Provide runtime helper libs in system lib directory for the glibc busybox base -COPY --from=builder /opt/sqlpage-libs/* /lib/ +COPY --from=builder /tmp/sqlpage-libs/* /lib/ USER sqlpage COPY --from=builder --chown=sqlpage:sqlpage /usr/src/sqlpage/sqlpage/sqlpage.db sqlpage/sqlpage.db EXPOSE 8080 diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..59986f41 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,20 @@ +# Docker Build Scripts + +This directory contains scripts used by the Dockerfile to build SQLPage with cross-compilation support. + +## Scripts + +- **`setup-cross-compilation.sh`**: Sets up the cross-compilation environment based on target and build architectures. Handles system dependencies, cross-compiler installation, and libgcc extraction for runtime. +- **`build-dependencies.sh`**: Builds only the project dependencies for Docker layer caching +- **`build-project.sh`**: Builds the final SQLPage binary + +## Usage + +These scripts are automatically copied and executed by the Dockerfile during the build process. They handle: + +- Cross-compilation setup for different architectures (amd64, arm64, arm) +- System dependencies installation +- Cargo build configuration with appropriate linkers +- Library extraction for runtime + +The scripts use temporary files in `/tmp/` to pass configuration between stages and export environment variables for use in subsequent build steps. diff --git a/scripts/build-dependencies.sh b/scripts/build-dependencies.sh new file mode 100755 index 00000000..e732125f --- /dev/null +++ b/scripts/build-dependencies.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euo pipefail + +# Source the environment variables set by setup-cross-compilation.sh +TARGET="$(cat /tmp/TARGET)" +LINKER="$(cat /tmp/LINKER)" +BINDGEN_EXTRA_CLANG_ARGS="$(cat /tmp/BINDGEN_EXTRA_CLANG_ARGS || true)" + +echo "Building dependencies for target: $TARGET" + +# Build dependencies only (for Docker layer caching) +cargo build \ + --target "$TARGET" \ + --config "target.$TARGET.linker=\"$LINKER\"" \ + --features odbc-static \ + --profile superoptimized diff --git a/scripts/build-project.sh b/scripts/build-project.sh new file mode 100755 index 00000000..6723fc17 --- /dev/null +++ b/scripts/build-project.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + +# Source the environment variables set by setup-cross-compilation.sh +TARGET="$(cat /tmp/TARGET)" +LINKER="$(cat /tmp/LINKER)" + +echo "Building project for target: $TARGET" + +# Build the project +touch src/main.rs +cargo build \ + --target "$TARGET" \ + --config "target.$TARGET.linker=\"$LINKER\"" \ + --features odbc-static \ + --profile superoptimized + +# Move the binary to the expected location +mv "target/$TARGET/superoptimized/sqlpage" sqlpage.bin diff --git a/scripts/setup-cross-compilation.sh b/scripts/setup-cross-compilation.sh new file mode 100755 index 00000000..5f877cbe --- /dev/null +++ b/scripts/setup-cross-compilation.sh @@ -0,0 +1,55 @@ +#!/bin/bash +set -euo pipefail + +TARGETARCH="$1" +BUILDARCH="$2" + +if [ "$TARGETARCH" = "$BUILDARCH" ]; then + # Native build + rustup target list --installed > /tmp/TARGET + echo "gcc" > /tmp/LINKER + apt-get install -y gcc libgcc-s1 cmake pkg-config + + LIBDIR="/lib/$(gcc -print-multiarch)" + +elif [ "$TARGETARCH" = "arm64" ]; then + echo "aarch64-unknown-linux-gnu" > /tmp/TARGET + echo "aarch64-linux-gnu-gcc" > /tmp/LINKER + + apt-get update + apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config + + LIBDIR="/usr/aarch64-linux-gnu/lib" + + # Also install gcc for aarch64 to get libgcc + apt-get install -y gcc-aarch64-linux-gnu + +elif [ "$TARGETARCH" = "arm" ]; then + echo "armv7-unknown-linux-gnueabihf" > /tmp/TARGET + echo "arm-linux-gnueabihf-gcc" > /tmp/LINKER + + apt-get update + apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang pkg-config + + # Ensure gcc-arm-linux-gnueabihf is available + apt-get install -y gcc-arm-linux-gnueabihf + + cargo install --force --locked bindgen-cli + + SYSROOT=$(arm-linux-gnueabihf-gcc -print-sysroot) + echo "--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/usr/include/arm-linux-gnueabihf" > /tmp/BINDGEN_EXTRA_CLANG_ARGS + + LIBDIR="/usr/arm-linux-gnueabihf/lib" +else + echo "Unsupported cross compilation target: $TARGETARCH" + exit 1 +fi + +# Copy libgcc_s.so.1 for runtime +mkdir -p /tmp/sqlpage-libs + +cp "$LIBDIR/libgcc_s.so.1" /tmp/sqlpage-libs/ + +# Add the target +rustup target add "$(cat /tmp/TARGET)" + From 0bd5a06a201af418fe31c6196a20db227fa249da Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 10:45:31 +0200 Subject: [PATCH 08/82] scripts: enhance cross-compilation setup by adding apt-get update and removing redundant installations --- scripts/setup-cross-compilation.sh | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/scripts/setup-cross-compilation.sh b/scripts/setup-cross-compilation.sh index 5f877cbe..1c01db4a 100755 --- a/scripts/setup-cross-compilation.sh +++ b/scripts/setup-cross-compilation.sh @@ -1,9 +1,11 @@ #!/bin/bash -set -euo pipefail +set -euox pipefail TARGETARCH="$1" BUILDARCH="$2" +apt-get update + if [ "$TARGETARCH" = "$BUILDARCH" ]; then # Native build rustup target list --installed > /tmp/TARGET @@ -16,24 +18,15 @@ elif [ "$TARGETARCH" = "arm64" ]; then echo "aarch64-unknown-linux-gnu" > /tmp/TARGET echo "aarch64-linux-gnu-gcc" > /tmp/LINKER - apt-get update apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config LIBDIR="/usr/aarch64-linux-gnu/lib" - - # Also install gcc for aarch64 to get libgcc - apt-get install -y gcc-aarch64-linux-gnu - elif [ "$TARGETARCH" = "arm" ]; then echo "armv7-unknown-linux-gnueabihf" > /tmp/TARGET echo "arm-linux-gnueabihf-gcc" > /tmp/LINKER - apt-get update apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang pkg-config - # Ensure gcc-arm-linux-gnueabihf is available - apt-get install -y gcc-arm-linux-gnueabihf - cargo install --force --locked bindgen-cli SYSROOT=$(arm-linux-gnueabihf-gcc -print-sysroot) From e263788ef37cc9570b88205395d8f3857c83b1bb Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 5 Oct 2025 12:01:12 +0200 Subject: [PATCH 09/82] rename deploy job --- .github/workflows/official-site.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/official-site.yml b/.github/workflows/official-site.yml index 0ec66068..3ad48ef3 100644 --- a/.github/workflows/official-site.yml +++ b/.github/workflows/official-site.yml @@ -8,7 +8,7 @@ on: concurrency: site-deploy jobs: - deploy: + deploy_official_site: runs-on: ubuntu-latest steps: - name: Cloning repo From c8b38980e2a3de6d3f8963acb06833c8afe422e8 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 7 Oct 2025 09:58:42 +0200 Subject: [PATCH 10/82] pin odbc-sys --- Cargo.lock | 21 ++++++++++++++------- Cargo.toml | 6 +++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 224be5f1..685f90ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.11.1" +version = "3.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cceded2fb55f3c4b67068fa64962e2ca59614edc5b03167de9ff82ae803da0" +checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49" dependencies = [ "actix-codec", "actix-rt", @@ -621,9 +621,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "awc" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117ec0a30fe956b77d69efff54bce923854df0437874fe4bfa701dfdddca8d5d" +checksum = "3c170039c11c7f6c0a28f7b3bd4fb0c674cbfa317fabc1560022ad3ec2d69e7c" dependencies = [ "actix-codec", "actix-http", @@ -1745,9 +1745,9 @@ checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -2720,6 +2720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -3122,7 +3123,7 @@ dependencies = [ [[package]] name = "odbc-sys" version = "0.27.0" -source = "git+https://github.com/sqlpage/odbc-sys?branch=main#0b5489e7b07d45e6b126f5a57ed6c301f022d2da" +source = "git+https://github.com/sqlpage/odbc-sys?rev=0b5489e7b07d45e6b126f5a57ed6c301f022d2da#0b5489e7b07d45e6b126f5a57ed6c301f022d2da" dependencies = [ "cc", ] @@ -4205,6 +4206,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.11" diff --git a/Cargo.toml b/Cargo.toml index 3b496eb0..71c5a7fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,17 +75,17 @@ clap = { version = "4.5.17", features = ["derive"] } tokio-util = "0.7.12" openidconnect = { version = "4.0.0", default-features = false } encoding_rs = "0.8.35" -odbc-sys = { version = "0.27", features = [], optional = false } +odbc-sys = { version = "0.27", optional = true } [features] default = [] -odbc-static = ["odbc-sys/static"] +odbc-static = ["odbc-sys", "odbc-sys/static"] lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch = "main" } # see https://github.com/pacman82/odbc-sys/pull/60 +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", rev = "0b5489e7b07d45e6b126f5a57ed6c301f022d2da" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } From dfeba164b57731d564382ce38f8fa32a9090dfe9 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 7 Oct 2025 14:35:41 +0200 Subject: [PATCH 11/82] update odbc sys --- Cargo.lock | 119 ++++++++++++++++++++++++++++++----------------------- Cargo.toml | 4 +- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 685f90ec..2cebda0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -516,7 +516,7 @@ dependencies = [ "polling", "rustix 1.1.2", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -1508,7 +1508,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -1691,7 +1691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -2584,7 +2584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.4", + "windows-targets 0.53.5", ] [[package]] @@ -3123,11 +3123,17 @@ dependencies = [ [[package]] name = "odbc-sys" version = "0.27.0" -source = "git+https://github.com/sqlpage/odbc-sys?rev=0b5489e7b07d45e6b126f5a57ed6c301f022d2da#0b5489e7b07d45e6b126f5a57ed6c301f022d2da" +source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" dependencies = [ - "cc", + "odbc-sys-core", + "unixodbc-sys", ] +[[package]] +name = "odbc-sys-core" +version = "0.27.0" +source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" + [[package]] name = "oid-registry" version = "0.7.1" @@ -3451,7 +3457,7 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -3832,7 +3838,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -3945,7 +3951,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -4510,7 +4516,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.1.2", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -4861,6 +4867,15 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unixodbc-sys" +version = "0.27.0" +source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" +dependencies = [ + "cc", + "odbc-sys-core", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -5095,14 +5110,14 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -5113,9 +5128,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -5124,9 +5139,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -5135,24 +5150,24 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -5190,14 +5205,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] @@ -5235,19 +5250,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -5264,9 +5279,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -5282,9 +5297,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -5300,9 +5315,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -5312,9 +5327,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -5330,9 +5345,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -5348,9 +5363,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -5366,9 +5381,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -5384,9 +5399,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" diff --git a/Cargo.toml b/Cargo.toml index 71c5a7fc..46ffd3c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,12 +80,12 @@ odbc-sys = { version = "0.27", optional = true } [features] default = [] -odbc-static = ["odbc-sys", "odbc-sys/static"] +odbc-static = ["odbc-sys", "odbc-sys/unixodbc-sys"] lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", rev = "0b5489e7b07d45e6b126f5a57ed6c301f022d2da" } +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } From 86f2722bdf4e22ff815df179a8a09fec8cc7d99a Mon Sep 17 00:00:00 2001 From: lovasoa Date: Wed, 8 Oct 2025 15:26:04 +0200 Subject: [PATCH 12/82] fix https://github.com/sqlpage/SQLPage/issues/1048 --- sqlpage/templates/list.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlpage/templates/list.handlebars b/sqlpage/templates/list.handlebars index f8c46431..ef3eca05 100644 --- a/sqlpage/templates/list.handlebars +++ b/sqlpage/templates/list.handlebars @@ -69,7 +69,7 @@
{{default empty_title 'No item'}} -
+
{{~empty_description~}} {{~#if empty_description_md~}}
{{{markdown empty_description_md}}}
From 189ac240d1c67fd194713e91a09a67b3a43893e8 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Wed, 8 Oct 2025 15:38:17 +0200 Subject: [PATCH 13/82] fix slight spacing issue in list's empty value --- CHANGELOG.md | 1 + sqlpage/templates/list.handlebars | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a204c38..39ed8eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Supports SHA-256 (default) and SHA-512 algorithms - Output formats: hexadecimal (default) or base64 (e.g., `sha256-base64`) - See the [function documentation](https://sql-page.com/functions.sql?function=hmac) for detailed examples + - Fixed a slight spacing issue in the list components empty value display. ## v0.37.1 - fixed decoding of UUID values diff --git a/sqlpage/templates/list.handlebars b/sqlpage/templates/list.handlebars index ef3eca05..2837f9e5 100644 --- a/sqlpage/templates/list.handlebars +++ b/sqlpage/templates/list.handlebars @@ -67,9 +67,9 @@ {{#if (eq @row_index 0)}}
-
+
{{default empty_title 'No item'}} -
+
{{~empty_description~}} {{~#if empty_description_md~}}
{{{markdown empty_description_md}}}
From 6019ab3d4ee0b924f6da83aa8ba9a71056662f08 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Thu, 9 Oct 2025 16:30:26 +0200 Subject: [PATCH 14/82] update odbc-sys --- Cargo.lock | 87 ++++++++++++++++++++++++++++++++++++++---------------- Cargo.toml | 6 ++-- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cebda0c..ddd8f67b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,6 +619,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "autotools" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" +dependencies = [ + "cc", +] + [[package]] name = "awc" version = "3.8.1" @@ -1737,6 +1746,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + [[package]] name = "find-msvc-tools" version = "0.1.3" @@ -2549,9 +2570,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libflate" @@ -3122,18 +3143,12 @@ dependencies = [ [[package]] name = "odbc-sys" -version = "0.27.0" -source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" +version = "0.27.1" +source = "git+https://github.com/sqlpage/odbc-sys?branch=static-linking-error#d90d42864f69c2addfbcbefd7c05b1a156d97c34" dependencies = [ - "odbc-sys-core", - "unixodbc-sys", + "unix-odbc", ] -[[package]] -name = "odbc-sys-core" -version = "0.27.0" -source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" - [[package]] name = "oid-registry" version = "0.7.1" @@ -3878,7 +3893,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.17", - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", "x509-parser", ] @@ -4410,7 +4425,7 @@ dependencies = [ "tokio-util", "url", "uuid", - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", "whoami", ] @@ -4457,9 +4472,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stringprep" @@ -4506,6 +4521,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.23.0" @@ -4868,12 +4894,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "unixodbc-sys" -version = "0.27.0" -source = "git+https://github.com/sqlpage/odbc-sys#14b4d0ee5f6f9ae8ff0c6ccf544161b84996219d" +name = "unix-odbc" +version = "0.1.0" +source = "git+https://github.com/sqlpage/odbc-sys?branch=static-linking-error#d90d42864f69c2addfbcbefd7c05b1a156d97c34" dependencies = [ - "cc", - "odbc-sys-core", + "autotools", + "flate2", + "tar", ] [[package]] @@ -5075,14 +5102,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] @@ -5100,9 +5127,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi-util" @@ -5481,6 +5508,16 @@ dependencies = [ "time", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.2", +] + [[package]] name = "xkbcommon-dl" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index 46ffd3c1..7c54b233 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,17 +75,17 @@ clap = { version = "4.5.17", features = ["derive"] } tokio-util = "0.7.12" openidconnect = { version = "4.0.0", default-features = false } encoding_rs = "0.8.35" -odbc-sys = { version = "0.27", optional = true } +odbc-sys = { version = "0.27.1", optional = true } [features] default = [] -odbc-static = ["odbc-sys", "odbc-sys/unixodbc-sys"] +odbc-static = ["odbc-sys", "odbc-sys/vendored-unix-odbc"] lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys" } +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="static-linking-error" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } From 2dc131ba0801f69b485ab61c99efdd890b79bc93 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Thu, 9 Oct 2025 17:24:30 +0200 Subject: [PATCH 15/82] remove unused dependencies in dockerfile --- scripts/setup-cross-compilation.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/setup-cross-compilation.sh b/scripts/setup-cross-compilation.sh index 1c01db4a..07b6a693 100755 --- a/scripts/setup-cross-compilation.sh +++ b/scripts/setup-cross-compilation.sh @@ -10,7 +10,7 @@ if [ "$TARGETARCH" = "$BUILDARCH" ]; then # Native build rustup target list --installed > /tmp/TARGET echo "gcc" > /tmp/LINKER - apt-get install -y gcc libgcc-s1 cmake pkg-config + apt-get install -y gcc libgcc-s1 make LIBDIR="/lib/$(gcc -print-multiarch)" @@ -18,14 +18,14 @@ elif [ "$TARGETARCH" = "arm64" ]; then echo "aarch64-unknown-linux-gnu" > /tmp/TARGET echo "aarch64-linux-gnu-gcc" > /tmp/LINKER - apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross pkg-config + apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross LIBDIR="/usr/aarch64-linux-gnu/lib" elif [ "$TARGETARCH" = "arm" ]; then echo "armv7-unknown-linux-gnueabihf" > /tmp/TARGET echo "arm-linux-gnueabihf-gcc" > /tmp/LINKER - apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross cmake libclang1 clang pkg-config + apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross make cargo install --force --locked bindgen-cli From f71c7ac864b5d66cd7dc68f2d63482f1be10a159 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Thu, 9 Oct 2025 17:54:22 +0200 Subject: [PATCH 16/82] add missing arm64 dep --- scripts/setup-cross-compilation.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-cross-compilation.sh b/scripts/setup-cross-compilation.sh index 07b6a693..e78be8ae 100755 --- a/scripts/setup-cross-compilation.sh +++ b/scripts/setup-cross-compilation.sh @@ -18,7 +18,7 @@ elif [ "$TARGETARCH" = "arm64" ]; then echo "aarch64-unknown-linux-gnu" > /tmp/TARGET echo "aarch64-linux-gnu-gcc" > /tmp/LINKER - apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross + apt-get install -y gcc-aarch64-linux-gnu libgcc-s1-arm64-cross make LIBDIR="/usr/aarch64-linux-gnu/lib" elif [ "$TARGETARCH" = "arm" ]; then From a8792a4e893db3a883178acffc55b94769a05e83 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Thu, 9 Oct 2025 18:26:38 +0200 Subject: [PATCH 17/82] dependency to libclang-dev on armv7 --- scripts/setup-cross-compilation.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-cross-compilation.sh b/scripts/setup-cross-compilation.sh index e78be8ae..941c99b9 100755 --- a/scripts/setup-cross-compilation.sh +++ b/scripts/setup-cross-compilation.sh @@ -25,7 +25,7 @@ elif [ "$TARGETARCH" = "arm" ]; then echo "armv7-unknown-linux-gnueabihf" > /tmp/TARGET echo "arm-linux-gnueabihf-gcc" > /tmp/LINKER - apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross make + apt-get install -y gcc-arm-linux-gnueabihf libgcc-s1-armhf-cross make cmake libclang-dev cargo install --force --locked bindgen-cli From 0757ecc946fad154ec93c68432b669567099498b Mon Sep 17 00:00:00 2001 From: lovasoa Date: Sun, 12 Oct 2025 14:53:27 +0200 Subject: [PATCH 18/82] update odbc sys --- Cargo.lock | 93 +++++++++++++++++------------------------------------- Cargo.toml | 2 +- 2 files changed, 30 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddd8f67b..e4257500 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -904,9 +904,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.40" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "jobserver", @@ -1746,23 +1746,11 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "filetime" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.60.2", -] - [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flate2" @@ -3143,8 +3131,8 @@ dependencies = [ [[package]] name = "odbc-sys" -version = "0.27.1" -source = "git+https://github.com/sqlpage/odbc-sys?branch=static-linking-error#d90d42864f69c2addfbcbefd7c05b1a156d97c34" +version = "0.27.3" +source = "git+https://github.com/sqlpage/odbc-sys?branch=main#7058cbe3db200d52811d6f3bce602c7e78f58f1d" dependencies = [ "unix-odbc", ] @@ -3325,12 +3313,12 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pem" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64 0.22.1", - "serde", + "serde_core", ] [[package]] @@ -3695,9 +3683,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.3" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" dependencies = [ "aho-corasick", "memchr", @@ -3707,9 +3695,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", @@ -3718,15 +3706,15 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" [[package]] name = "rfc6979" @@ -4130,9 +4118,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -4521,17 +4509,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "tempfile" version = "3.23.0" @@ -4718,9 +4695,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "serde_core", "serde_spanned", @@ -4731,18 +4708,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ "indexmap 2.11.4", "toml_datetime", @@ -4752,9 +4729,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -4895,12 +4872,10 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unix-odbc" -version = "0.1.0" -source = "git+https://github.com/sqlpage/odbc-sys?branch=static-linking-error#d90d42864f69c2addfbcbefd7c05b1a156d97c34" +version = "0.1.2" +source = "git+https://github.com/sqlpage/odbc-sys?branch=main#7058cbe3db200d52811d6f3bce602c7e78f58f1d" dependencies = [ "autotools", - "flate2", - "tar", ] [[package]] @@ -5508,16 +5483,6 @@ dependencies = [ "time", ] -[[package]] -name = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix 1.1.2", -] - [[package]] name = "xkbcommon-dl" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index 7c54b233..44863cb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="static-linking-error" } +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="main" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } From 68a20ebee261e66beab0fd527aeb9ea71269f5d0 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 13 Oct 2025 10:43:25 +0200 Subject: [PATCH 19/82] remove dependency to autotools https://github.com/pacman82/odbc-sys/pull/76 --- Cargo.lock | 31 +++++++++++-------------------- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4257500..a7020407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,15 +619,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "autotools" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" -dependencies = [ - "cc", -] - [[package]] name = "awc" version = "3.8.1" @@ -1953,9 +1944,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "1dc8f7d2ded5f9209535e4b3fd4d39c002f30902ff5ce9f64e2c33d549576500" dependencies = [ "typenum", "version_check", @@ -3117,9 +3108,9 @@ dependencies = [ [[package]] name = "odbc-api" -version = "19.0.2" +version = "19.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564dc5b7c737a3821f60e3b9608320098a02203ab4a38be09bcd759225329554" +checksum = "f017d3949731e436bc1bb9a1fbc34197c2f39c588cdcb60d21adb1f8dd3b8514" dependencies = [ "atoi", "log", @@ -3132,7 +3123,7 @@ dependencies = [ [[package]] name = "odbc-sys" version = "0.27.3" -source = "git+https://github.com/sqlpage/odbc-sys?branch=main#7058cbe3db200d52811d6f3bce602c7e78f58f1d" +source = "git+https://github.com/sqlpage/odbc-sys?branch=no-autotools#ae3e15446bb2c5c191f05e7c6affc37dfd6fcabe" dependencies = [ "unix-odbc", ] @@ -4254,12 +4245,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4642,7 +4633,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", "windows-sys 0.59.0", ] @@ -4873,9 +4864,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unix-odbc" version = "0.1.2" -source = "git+https://github.com/sqlpage/odbc-sys?branch=main#7058cbe3db200d52811d6f3bce602c7e78f58f1d" +source = "git+https://github.com/sqlpage/odbc-sys?branch=no-autotools#ae3e15446bb2c5c191f05e7c6affc37dfd6fcabe" dependencies = [ - "autotools", + "cc", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 44863cb6..191dc432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="main" } +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="no-autotools" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } From 5881ed7f185eb787305b45e2aeb394d901651758 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 10:57:32 +0200 Subject: [PATCH 20/82] update dependencies --- Cargo.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7020407..eb252cfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -959,9 +959,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", "clap_derive", @@ -969,9 +969,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstream", "anstyle", @@ -981,9 +981,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -993,9 +993,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cmake" @@ -1646,9 +1646,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", @@ -1944,9 +1944,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.8" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc8f7d2ded5f9209535e4b3fd4d39c002f30902ff5ce9f64e2c33d549576500" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -3674,9 +3674,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -3686,9 +3686,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -3703,9 +3703,9 @@ checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rfc6979" From 534fa422fa28557f7461c7a40421a3fef1b2b02a Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 12:14:11 +0200 Subject: [PATCH 21/82] Local execution of simple static SET commands `SET x = 'hello'` is now executed locally by SQLPage and does not send anything to the database. This completely removes the cost of extracting static values into variables for cleaner SQL files. --- CHANGELOG.md | 1 + src/webserver/database/execute_queries.rs | 38 +++++++ src/webserver/database/sql.rs | 133 ++++++++++++++-------- 3 files changed, 122 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39ed8eb8..49f35574 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Output formats: hexadecimal (default) or base64 (e.g., `sha256-base64`) - See the [function documentation](https://sql-page.com/functions.sql?function=hmac) for detailed examples - Fixed a slight spacing issue in the list components empty value display. + - Improved performance of setting a variable to a literal value. `SET x = 'hello'` is now executed locally by SQLPage and does not send anything to the database. This completely removes the cost of extracting static values into variables for cleaner SQL files. ## v0.37.1 - fixed decoding of UUID values diff --git a/src/webserver/database/execute_queries.rs b/src/webserver/database/execute_queries.rs index 9d242f55..80883e24 100644 --- a/src/webserver/database/execute_queries.rs +++ b/src/webserver/database/execute_queries.rs @@ -86,6 +86,12 @@ pub fn stream_query_results_with_conn<'a>( format!("Failed to set the {variable} variable to {value:?}") )?; }, + ParsedStatement::StaticSimpleSet { variable, value} => { + execute_set_simple_static(db_connection, request, variable, value, source_file).await + .with_context(|| + format!("Failed to set the {variable} variable to {value:?}") + )?; + }, ParsedStatement::StaticSimpleSelect(value) => { for i in parse_dynamic_rows(DbItem::Row(exec_static_simple_select(value, request, db_connection).await?)) { yield i; @@ -214,6 +220,38 @@ async fn execute_set_variable_query<'a>( Ok(()) } +async fn execute_set_simple_static<'a>( + db_connection: &'a mut DbConn, + request: &'a mut RequestInfo, + variable: &StmtParam, + value: &SimpleSelectValue, + _source_file: &Path, +) -> anyhow::Result<()> { + let value_str = match value { + SimpleSelectValue::Static(json_value) => match json_value { + serde_json::Value::Null => None, + serde_json::Value::String(s) => Some(s.clone()), + other => Some(other.to_string()), + }, + SimpleSelectValue::Dynamic(stmt_param) => { + extract_req_param(stmt_param, request, db_connection) + .await? + .map(std::borrow::Cow::into_owned) + } + }; + + let (vars, name) = vars_and_name(request, variable)?; + + if let Some(value) = value_str { + log::debug!("Setting variable {name} to static value {value:?}"); + vars.insert(name.to_owned(), SingleOrVec::Single(value)); + } else { + log::debug!("Removing variable {name} because it was set to the literal value NULL"); + vars.remove(name); + } + Ok(()) +} + fn vars_and_name<'a, 'b>( request: &'a mut RequestInfo, variable: &'b StmtParam, diff --git a/src/webserver/database/sql.rs b/src/webserver/database/sql.rs index 3502f23a..b624adcf 100644 --- a/src/webserver/database/sql.rs +++ b/src/webserver/database/sql.rs @@ -111,6 +111,10 @@ pub(super) enum ParsedStatement { variable: StmtParam, value: StmtWithParams, }, + StaticSimpleSet { + variable: StmtParam, + value: SimpleSelectValue, + }, CsvImport(CsvImport), Error(anyhow::Error), } @@ -142,6 +146,7 @@ fn parse_sql<'a>( return None; } let statement = parse_single_statement(&mut parser, db_info, sql); + log::debug!("Parsed statement: {statement:?}"); if let Some(ParsedStatement::Error(_)) = &statement { has_error = true; } @@ -182,7 +187,6 @@ fn parse_single_statement( Ok(stmt) => stmt, Err(err) => return Some(syntax_error(err, parser, source_sql)), }; - log::debug!("Parsed statement: {stmt}"); let mut semicolon = false; while parser.consume_token(&SemiColon) { semicolon = true; @@ -404,40 +408,10 @@ fn extract_static_simple_select( let mut items = Vec::with_capacity(select_items.len()); let mut params_iter = params.iter().cloned(); for select_item in select_items { - use serde_json::Value::{Bool, Null, Number, String}; - use SimpleSelectValue::{Dynamic, Static}; let sqlparser::ast::SelectItem::ExprWithAlias { expr, alias } = select_item else { return None; }; - let value = match expr { - Expr::Value(ValueWithSpan { - value: Value::Boolean(b), - .. - }) => Static(Bool(*b)), - Expr::Value(ValueWithSpan { - value: Value::Number(n, _), - .. - }) => Static(Number(n.parse().ok()?)), - Expr::Value(ValueWithSpan { - value: Value::SingleQuotedString(s), - .. - }) => Static(String(s.clone())), - Expr::Value(ValueWithSpan { - value: Value::Null, .. - }) => Static(Null), - e if is_simple_select_placeholder(e) => { - if let Some(p) = params_iter.next() { - Dynamic(p) - } else { - log::error!("Parameter not extracted for placehorder: {expr:?}"); - return None; - } - } - other => { - log::trace!("Cancelling simple select optimization because of expr: {other:?}"); - return None; - } - }; + let value = expr_to_simple_select_val(&mut params_iter, expr)?; let key = alias.value.clone(); items.push((key, value)); } @@ -448,6 +422,43 @@ fn extract_static_simple_select( Some(items) } +fn expr_to_simple_select_val( + params_iter: &mut impl Iterator, + expr: &Expr, +) -> Option { + use serde_json::Value::{Bool, Null, Number, String}; + use SimpleSelectValue::{Dynamic, Static}; + Some(match expr { + Expr::Value(ValueWithSpan { + value: Value::Boolean(b), + .. + }) => Static(Bool(*b)), + Expr::Value(ValueWithSpan { + value: Value::Number(n, _), + .. + }) => Static(Number(n.parse().ok()?)), + Expr::Value(ValueWithSpan { + value: Value::SingleQuotedString(s), + .. + }) => Static(String(s.clone())), + Expr::Value(ValueWithSpan { + value: Value::Null, .. + }) => Static(Null), + e if is_simple_select_placeholder(e) => { + if let Some(p) = params_iter.next() { + Dynamic(p) + } else { + log::error!("Parameter not extracted for placehorder: {expr:?}"); + return None; + } + } + other => { + log::trace!("Cancelling simple select optimization because of expr: {other:?}"); + return None; + } + }) +} + fn is_simple_select_placeholder(e: &Expr) -> bool { match e { Expr::Value(ValueWithSpan { @@ -485,6 +496,11 @@ fn extract_set_variable( StmtParam::PostOrGet(std::mem::take(&mut ident.value)) }; let owned_expr = std::mem::replace(value, Expr::value(Value::Null)); + let mut params_iter = params.iter().cloned(); + if let Some(value) = expr_to_simple_select_val(&mut params_iter, &owned_expr) { + return Some(ParsedStatement::StaticSimpleSet { variable, value }); + } + let mut select_stmt: Statement = expr_to_statement(owned_expr); let delayed_functions = extract_toplevel_functions(&mut select_stmt); if let Err(err) = validate_function_calls(&select_stmt) { @@ -1248,26 +1264,24 @@ mod test { } #[test] - fn test_set_variable() { + fn test_set_variable_to_other_variable() { let sql = "set x = $y"; for &(dialect, dbms) in ALL_DIALECTS { let mut parser = Parser::new(dialect).try_with_sql(sql).unwrap(); let db_info = create_test_db_info(dbms); - let stmt = parse_single_statement(&mut parser, &db_info, sql); - if let Some(ParsedStatement::SetVariable { - variable, - value: StmtWithParams { query, params, .. }, - }) = stmt - { - assert_eq!( - variable, - StmtParam::PostOrGet("x".to_string()), - "{dialect:?}" - ); - assert!(query.starts_with("SELECT ")); - assert_eq!(params, [StmtParam::PostOrGet("y".to_string())]); - } else { - panic!("Failed for dialect {dialect:?}: {stmt:#?}",); + match parse_single_statement(&mut parser, &db_info, sql) { + Some(ParsedStatement::StaticSimpleSet { variable, value }) => { + assert_eq!( + variable, + StmtParam::PostOrGet("x".to_string()), + "{dialect:?}" + ); + assert_eq!( + value, + SimpleSelectValue::Dynamic(StmtParam::PostOrGet("y".to_string())) + ); + } + other => panic!("Failed for dialect {dialect:?}: {other:#?}"), } } } @@ -1398,7 +1412,7 @@ mod test { #[test] fn test_extract_set_variable() { - let sql = "set x = 42"; + let sql = "set x = CURRENT_TIMESTAMP"; for &(dialect, dbms) in ALL_DIALECTS { let mut parser = Parser::new(dialect).try_with_sql(sql).unwrap(); let db_info = create_test_db_info(dbms); @@ -1413,7 +1427,7 @@ mod test { StmtParam::PostOrGet("x".to_string()), "{dialect:?}" ); - assert_eq!(query, "SELECT 42 AS sqlpage_set_expr"); + assert_eq!(query, "SELECT CURRENT_TIMESTAMP AS sqlpage_set_expr"); assert!(params.is_empty()); } else { panic!("Failed for dialect {dialect:?}: {stmt:#?}",); @@ -1421,6 +1435,25 @@ mod test { } } + #[test] + fn test_extract_set_variable_static() { + let sql = "set x = 'hello'"; + for &(dialect, dbms) in ALL_DIALECTS { + let mut parser = Parser::new(dialect).try_with_sql(sql).unwrap(); + let db_info = create_test_db_info(dbms); + match parse_single_statement(&mut parser, &db_info, sql) { + Some(ParsedStatement::StaticSimpleSet { + variable: StmtParam::PostOrGet(var_name), + value: SimpleSelectValue::Static(value), + }) => { + assert_eq!(var_name, "x"); + assert_eq!(value, "hello"); + } + other => panic!("Failed for dialect {dialect:?}: {other:#?}"), + } + } + } + #[test] fn test_static_extract_doesnt_match() { assert_eq!( From 9dfbf42f56f67abdeaa49a409e58a58d1a220fe8 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 16:30:28 +0200 Subject: [PATCH 22/82] enable arbitrary precision in the internal representation of values - Enabled arbitrary precision for `serde_json` to handle large numbers without rounding. - Refactored decimal handling in `sql_to_json.rs` to utilize a new function for converting decimals to JSON format. Fixes https://github.com/sqlpage/SQLPage/issues/1052 --- CHANGELOG.md | 1 + Cargo.lock | 2 ++ Cargo.toml | 10 +++++--- src/webserver/database/sql_to_json.rs | 24 +++++++++---------- .../it_works_set_variable_large_integer.sql | 7 ++++++ 5 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 tests/sql_test_files/it_works_set_variable_large_integer.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index 49f35574..66bdae84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - See the [function documentation](https://sql-page.com/functions.sql?function=hmac) for detailed examples - Fixed a slight spacing issue in the list components empty value display. - Improved performance of setting a variable to a literal value. `SET x = 'hello'` is now executed locally by SQLPage and does not send anything to the database. This completely removes the cost of extracting static values into variables for cleaner SQL files. + - Enable arbitrary precision in the internal representation of numbers. This guarantees zero precision loss when the database returns very large or very small DECIMAL or NUMERIC values. ## v0.37.1 - fixed decoding of UUID values diff --git a/Cargo.lock b/Cargo.lock index eb252cfc..719f40fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,6 +733,8 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 191dc432..eafc920f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,11 @@ tokio = { version = "1.24.1", features = ["macros", "rt", "process", "sync"] } tokio-stream = "0.1.9" anyhow = "1" serde = "1" -serde_json = { version = "1.0.82", features = ["preserve_order", "raw_value"] } +serde_json = { version = "1.0.82", features = [ + "preserve_order", + "raw_value", + "arbitrary_precision", +] } lambda-web = { version = "0.2.1", features = ["actix4"], optional = true } sqlparser = { version = "0.59.0", default-features = false, features = [ "std", @@ -53,7 +57,7 @@ sqlparser = { version = "0.59.0", default-features = false, features = [ async-stream = "0.3" async-trait = "0.1.61" async-recursion = "1.0.0" -bigdecimal = "0.4.8" +bigdecimal = { version = "0.4.8", features = ["serde-json"] } include_dir = "0.7.2" config = { version = "0.15.4", features = ["json"] } markdown = { version = "1.0.0-alpha.23", features = ["log"] } @@ -85,7 +89,7 @@ lambda-web = ["dep:lambda-web", "odbc-static"] [patch.crates-io] -odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch="no-autotools" } +odbc-sys = { git = "https://github.com/sqlpage/odbc-sys", branch = "no-autotools" } [build-dependencies] awc = { version = "3", features = ["rustls-0_23-webpki-roots"] } diff --git a/src/webserver/database/sql_to_json.rs b/src/webserver/database/sql_to_json.rs index 6ceaac84..54d95bfd 100644 --- a/src/webserver/database/sql_to_json.rs +++ b/src/webserver/database/sql_to_json.rs @@ -1,6 +1,6 @@ use crate::utils::add_value_to_map; use crate::webserver::database::blob_to_data_url; -use bigdecimal::{BigDecimal, ToPrimitive}; +use bigdecimal::BigDecimal; use chrono::{DateTime, FixedOffset, NaiveDateTime}; use serde_json::{self, Map, Value}; use sqlx::any::{AnyColumn, AnyRow, AnyTypeInfo, AnyTypeInfoKind}; @@ -68,6 +68,13 @@ fn decode_raw<'a, T: Decode<'a, sqlx::any::Any> + Default>( } } +fn decimal_to_json(decimal: &BigDecimal) -> Value { + // to_plain_string always returns a valid JSON string + Value::Number(serde_json::Number::from_string_unchecked( + decimal.normalized().to_plain_string(), + )) +} + pub fn sql_nonnull_to_json<'r>(mut get_ref: impl FnMut() -> sqlx::any::AnyValueRef<'r>) -> Value { use AnyTypeInfoKind::{Mssql, MySql}; let raw_value = get_ref(); @@ -77,18 +84,7 @@ pub fn sql_nonnull_to_json<'r>(mut get_ref: impl FnMut() -> sqlx::any::AnyValueR let AnyTypeInfo(ref db_type) = *type_info; match type_name { "REAL" | "FLOAT" | "FLOAT4" | "FLOAT8" | "DOUBLE" => decode_raw::(raw_value).into(), - "NUMERIC" | "DECIMAL" => { - let decimal = decode_raw::(raw_value); - if decimal.is_integer() { - if let Some(int) = decimal.to_i64() { - return int.into(); - } - } - if let Some(float) = decimal.to_f64() { - return float.into(); - } - decimal.to_string().into() - } + "NUMERIC" | "DECIMAL" => decimal_to_json(&decode_raw(raw_value)), "INT8" | "BIGINT" | "SERIAL8" | "BIGSERIAL" | "IDENTITY" | "INT64" | "INTEGER8" | "BIGINT SIGNED" => decode_raw::(raw_value).into(), "INT" | "INT4" | "INTEGER" | "MEDIUMINT" | "YEAR" => decode_raw::(raw_value).into(), @@ -209,6 +205,7 @@ mod tests { 42::INT8 as big_int, 42.25::FLOAT4 as float4, 42.25::FLOAT8 as float8, + 123456789123456789123456789::NUMERIC as numeric, TRUE as boolean, '2024-03-14'::DATE as date, '13:14:15'::TIME as time, @@ -237,6 +234,7 @@ mod tests { "big_int": 42, "float4": 42.25, "float8": 42.25, + "numeric": 123456789123456789123456789_u128, "boolean": true, "date": "2024-03-14", "time": "13:14:15", diff --git a/tests/sql_test_files/it_works_set_variable_large_integer.sql b/tests/sql_test_files/it_works_set_variable_large_integer.sql new file mode 100644 index 00000000..859f89db --- /dev/null +++ b/tests/sql_test_files/it_works_set_variable_large_integer.sql @@ -0,0 +1,7 @@ +SET test_stored_number = 123456789123456789123456789; +select 'text' as component, + case $test_stored_number + when '123456789123456789123456789' then 'It works !' + else 'It failed ! Expected 123456789123456789123456789 but got ' || COALESCE($test_stored_number, 'NULL') + end +AS contents; \ No newline at end of file From 93ca430e144ec0c69e131458f1d2a3ff23afc6bb Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 16:37:23 +0200 Subject: [PATCH 23/82] add a test for simple static set that sets a variable to the value of another variable --- .../it_works_set_variable_to_other_variable.sql | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/sql_test_files/it_works_set_variable_to_other_variable.sql diff --git a/tests/sql_test_files/it_works_set_variable_to_other_variable.sql b/tests/sql_test_files/it_works_set_variable_to_other_variable.sql new file mode 100644 index 00000000..5c277a9e --- /dev/null +++ b/tests/sql_test_files/it_works_set_variable_to_other_variable.sql @@ -0,0 +1,9 @@ +SET x = 42; +SET y = $x; +SET z = $y; +select 'text' as component, + case $z + when '42' then 'It works !' + else 'It failed ! Expected 42 but got ' || COALESCE($z, 'NULL') + end +AS contents; \ No newline at end of file From e9831ab5f3f93d12664e8c7e456590893b18e68d Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 16:39:03 +0200 Subject: [PATCH 24/82] fix clippy warning --- src/webserver/database/sql_to_json.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver/database/sql_to_json.rs b/src/webserver/database/sql_to_json.rs index 54d95bfd..98a3bc08 100644 --- a/src/webserver/database/sql_to_json.rs +++ b/src/webserver/database/sql_to_json.rs @@ -234,7 +234,7 @@ mod tests { "big_int": 42, "float4": 42.25, "float8": 42.25, - "numeric": 123456789123456789123456789_u128, + "numeric": 123_456_789_123_456_789_123_456_789_u128, "boolean": true, "date": "2024-03-14", "time": "13:14:15", From 9a8bb78f5ccbf5249e9b3c289a687d7776fe3a0b Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 22:35:23 +0200 Subject: [PATCH 25/82] v0.38.0 --- Cargo.lock | 109 ++++++++++------------------------------------------- Cargo.toml | 2 +- 2 files changed, 21 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 719f40fd..6ae80844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,15 +263,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -291,7 +282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -665,31 +656,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.32.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" +checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", - "libloading", -] - -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", ] [[package]] @@ -1964,28 +1939,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.3" @@ -2367,17 +2336,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2460,7 +2418,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] @@ -2581,12 +2539,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.5", + "windows-link", ] [[package]] @@ -2733,7 +2691,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.59.0", ] @@ -3099,15 +3057,6 @@ dependencies = [ "objc2-foundation", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "odbc-api" version = "19.1.0" @@ -3603,7 +3552,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -3781,12 +3730,6 @@ dependencies = [ "ordered-multimap", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -4276,7 +4219,7 @@ dependencies = [ [[package]] name = "sqlpage" -version = "0.38.0-beta.1" +version = "0.38.0" dependencies = [ "actix-multipart", "actix-rt", @@ -4509,7 +4452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix 1.1.2", "windows-sys 0.61.2", @@ -4622,29 +4565,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -4948,15 +4888,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" diff --git a/Cargo.toml b/Cargo.toml index eafc920f..c7248abd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sqlpage" -version = "0.38.0-beta.1" +version = "0.38.0" edition = "2021" description = "Build data user interfaces entirely in SQL. A web server that takes .sql files and formats the query result using pre-made configurable professional-looking components." keywords = ["web", "sql", "framework"] From 9a383c9cd5ac9b72579ccc8fa649e848d007bed6 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 14 Oct 2025 23:35:13 +0200 Subject: [PATCH 26/82] Update README.md to clarify ODBC support and driver linking details - Added information about SQLPage's support for ODBC connections. - Clarified that Linux and MacOS binaries include a built-in statically linked ODBC driver manager (unixODBC). - Removed redundant text regarding ODBC support for specific databases. --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c25c8867..b4c99c33 100644 --- a/README.md +++ b/README.md @@ -186,15 +186,12 @@ An alternative for Mac OS users is to use [SQLPage's homebrew package](https://f ### ODBC Setup +SQLPage supports ODBC connections to connect to databases that don't have native drivers. You can skip this section if you want to use one of the built-in database drivers (SQLite, PostgreSQL, MySQL, Microsoft SQL Server). -SQLPage supports ODBC connections to connect to databases that don't have native drivers, such as Oracle, Snowflake, BigQuery, IBM DB2, and many others. - -On Linux, SQLPage supports both dynamic and static ODBC linking. The Docker image uses the system `unixODBC` (dynamic). -Linux and MacOS release binaries are built with a statically linked unixODBC. +Linux and MacOS release binaries conatain a built-in statically linked ODBC driver manager (unixODBC). You still need to install or provide the database-specific ODBC driver for the database you want to connect to. - #### Install your ODBC database driver - [DuckDB](https://duckdb.org/docs/stable/clients/odbc/overview.html) - [Snowflake](https://docs.snowflake.com/en/developer-guide/odbc/odbc) From ac4126b2af2b381f7ccace5727c0bb079e7beb25 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Tue, 14 Oct 2025 17:59:56 -0700 Subject: [PATCH 27/82] #Added support for action buttons in the table component template. * A default edit and delete button can be included by specifying an "edit_url" or "delete_url" * Custom Column based action buttons can be added in the table header using json object array in the custom_actions column. * Custom action buttons can be defined on the row level by specifying _sqlpage_actions. --- .../sqlpage/migrations/01_documentation.sql | 168 +++++++++++++++++- sqlpage/templates/table.handlebars | 45 +++++ 2 files changed, 212 insertions(+), 1 deletion(-) diff --git a/examples/official-site/sqlpage/migrations/01_documentation.sql b/examples/official-site/sqlpage/migrations/01_documentation.sql index ee2b8b51..c9630fbf 100644 --- a/examples/official-site/sqlpage/migrations/01_documentation.sql +++ b/examples/official-site/sqlpage/migrations/01_documentation.sql @@ -810,11 +810,15 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('money', 'Name of a numeric column whose values should be displayed as currency amounts, in the currency defined by the `currency` property. This argument can be repeated multiple times.', 'TEXT', TRUE, TRUE), ('currency', 'The ISO 4217 currency code (e.g., USD, EUR, GBP, etc.) to use when formatting monetary values.', 'TEXT', TRUE, TRUE), ('number_format_digits', 'Maximum number of decimal digits to display for numeric values.', 'INTEGER', TRUE, TRUE), + ('edit_url', 'If set, an edit button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the edit button will take the user to that URL.', 'TEXT', TRUE, TRUE), + ('delete_url', 'If set, a delete button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the delete button will take the user to that URL.', 'TEXT', TRUE, TRUE), + ('custom_actions', 'If set, a column of custom action buttons will be added to each row. The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', TRUE, TRUE), -- row level ('_sqlpage_css_class', 'For advanced users. Sets a css class on the table row. Added in v0.8.0.', 'TEXT', FALSE, TRUE), ('_sqlpage_color', 'Sets the background color of the row. Added in v0.8.0.', 'COLOR', FALSE, TRUE), ('_sqlpage_footer', 'Sets this row as the table footer. It is recommended that this parameter is applied to the last row. Added in v0.34.0.', 'BOOLEAN', FALSE, TRUE), - ('_sqlpage_id', 'Sets the id of the html tabler row element. Allows you to make links targeting a specific row in a table.', 'TEXT', FALSE, TRUE) + ('_sqlpage_id', 'Sets the id of the html tabler row element. Allows you to make links targeting a specific row in a table.', 'TEXT', FALSE, TRUE), + ('_sqlpage_actions', 'Sets custom action buttons for this specific row in addition to any defined at the table level, The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', FALSE, TRUE) ) x; INSERT INTO example(component, description, properties) VALUES @@ -994,9 +998,171 @@ GROUP BY This will generate a table with the stores in the first column, and the items in the following columns, with the quantity sold in each store for each item. ', NULL + ), + ( + 'table', +'# Using row based custom actions in a table + +The table has a column of buttons, each button defined by the `_sqlpage_actions` column at the table level, and by the `_sqlpage_actions` property at the row level. + +```sql + SELECT + name, vendor, product_number, facility_name, + lot_number, status, date_of_expiration, + --Use the unique identifier of the row as the _sqlpage_id property + standard_id AS _sqlpage_id, + --Build an array of objects, each object defining a button with the following properties: name, icon, link, tooltip + json_array(--SQLite specific, refer to your database documentation for the equivalent JSON functions + --The {id} placeholder in the link property will be replaced by the value of the _sqlpage_id property for that row. + json_object(''name'', ''history'', ''tooltip'', ''View Standard History'', ''link'', ''./history.sql?standard_id={id}'', ''icon'', ''history''), + json_object(''name'', ''view_coa'', ''tooltip'', ''View Certificate of Analysis'', ''link'', c_of_a_path, ''icon'', ''file-type-pdf''), + json_object(''name'', ''edit'', ''tooltip'', ''Edit Standard'', ''link'', ''./update.sql?id={id}'', ''icon'', ''pencil''), + --We want different actions based on the status of the standard, so we use a CASE statement to build the appropriate action + CASE + WHEN status = ''Available'' THEN json_object( + ''name'',''Action'', + ''tooltip'',''Set In Use'', + ''link'',''./actions/set_in_use.sql?standard_id='' || standard_id, + ''icon'',''caret-right'' + ) + WHEN status = ''In Use'' THEN json_object( + ''name'',''Action'', + ''tooltip'',''Retire Standard'', + ''link'',''./actions/retire.sql?standard_id='' || standard_id, + ''icon'',''test-pipe-off'' + ) + WHEN status = ''Retired'' THEN json_object( + ''name'',''Action'', + ''tooltip'',''Discard Standard'', + ''link'',''./actions/discard.sql?standard_id='' || standard_id, + ''icon'',''flask-off'' + ) + -- Include an action with no link or icon as a placeholder to keep the buttons aligned and make sure the header is correct. + WHEN status = ''Discarded'' THEN json_object(''name'',''Action'') + + ELSE json_object(''name'',''Action'') + END + ) + AS _sqlpage_actions + FROM standard; + + ``` + + + ' + , + json('[ + { + "component": "table" + }, + { + "name": "CalStd", + "vendor": "PharmaCo", + "product_number": "P1234", + "facility_name": "A Plant", + "lot_number": "T23523", + "status": "Available", + "date_of_expiration": "2026-10-13", + "_sqlpage_id": 32, + "_sqlpage_actions": [ + { + "name": "history", + "tooltip": "View Standard History", + "link": "./history.sql?standard_id={id}", + "icon": "history" + }, + { + "name": "view_coa", + "tooltip": "View Certificate of Analysis", + "link": "/c_of_a\\2025-09-30_22h01m21s_B69baKoz.pdf", + "icon": "file-type-pdf" + }, + { + "name": "edit", + "tooltip": "Edit Standard", + "link": "./update.sql?id={id}", + "icon": "pencil" + }, + { + "name": "Action", + "tooltip": "Set In Use", + "link": "./actions/set_in_use.sql?standard_id=32", + "icon": "caret-right" + } + ] + }, + { + "name": "CalStd", + "vendor": "PharmaCo", + "product_number": "P1234", + "facility_name": "A Plant", + "lot_number": "T2352", + "status": "In Use", + "date_of_expiration": "2026-10-14", + "_sqlpage_id": 33, + "_sqlpage_actions": [ + { + "name": "history", + "tooltip": "View Standard History", + "link": "./history.sql?standard_id={id}", + "icon": "history" + }, + { + "name": "view_coa", + "tooltip": "View Certificate of Analysis", + "link": "/c_of_a\\2025-09-30_22h05m13s_cP7gqMyi.pdf", + "icon": "file-type-pdf" + }, + { + "name": "edit", + "tooltip": "Edit Standard", + "link": "./update.sql?id={id}", + "icon": "pencil" + }, + { + "name": "Action", + "tooltip": "Retire Standard", + "link": "./actions/retire.sql?standard_id=33", + "icon": "test-pipe-off" + } + ] + }, + { + "name": "CalStd", + "vendor": "PharmaCo", + "product_number": "P1234", + "facility_name": "A Plant", + "lot_number": "A123", + "status": "Discarded", + "date_of_expiration": "2026-09-30", + "_sqlpage_id": 31, + "_sqlpage_actions": [ + { + "name": "history", + "tooltip": "View Standard History", + "link": "./history.sql?standard_id={id}", + "icon": "history" + }, + { + "name": "view_coa", + "tooltip": "View Certificate of Analysis", + "link": "#", + "icon": "file-type-pdf" + }, + { + "name": "edit", + "tooltip": "Edit Standard", + "link": "./update.sql?id={id}", + "icon": "pencil" + }, + null + ] + } +]') ); + INSERT INTO component(name, icon, description) VALUES ('csv', 'download', 'Lets the user download data as a CSV file. Each column from the items in the component will map to a column in the resulting CSV. diff --git a/sqlpage/templates/table.handlebars b/sqlpage/templates/table.handlebars index 90958dfe..639f9341 100644 --- a/sqlpage/templates/table.handlebars +++ b/sqlpage/templates/table.handlebars @@ -3,6 +3,7 @@ {{#if (or search initial_search_value)}}
{{/if}} {{/each}} + {{#if ../edit_url}}Edit{{/if}} + {{#if ../delete_url}}Delete{{/if}} + {{#if ../custom_actions}} + {{#each ../custom_actions}} + {{this.name}} + {{/each}} + {{/if}} + {{#if _sqlpage_actions}} + {{#each _sqlpage_actions}} + {{this.name}} + {{/each}} + {{/if}} {{#delay}}{{/delay}} @@ -78,6 +91,38 @@ {{/if~}} {{~/each~}} + {{#if ../edit_url}} + + + {{~icon_img 'edit'~}} + + + {{/if}} + {{#if ../delete_url}} + + + {{~icon_img 'trash'~}} + + + {{/if}} + {{#if ../custom_actions}} + {{#each ../custom_actions}} + + {{!Title property sets the tooltip text}} + {{~icon_img this.icon~}} + + + {{/each}} + {{/if}} + {{#if _sqlpage_actions}} + {{#each _sqlpage_actions}} + + + {{~icon_img this.icon~}} + + + {{/each}} + {{/if}} {{!~ After this has been rendered, if this was a footer, we need to reopen a new From be67d3e4ae990f7a2efb5b7b8676153391b5c528 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Tue, 14 Oct 2025 19:17:56 -0700 Subject: [PATCH 28/82] Modified new table example. --- .../sqlpage/migrations/01_documentation.sql | 135 ++++++------------ 1 file changed, 45 insertions(+), 90 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/01_documentation.sql b/examples/official-site/sqlpage/migrations/01_documentation.sql index c9630fbf..b9fae3d9 100644 --- a/examples/official-site/sqlpage/migrations/01_documentation.sql +++ b/examples/official-site/sqlpage/migrations/01_documentation.sql @@ -1001,88 +1001,66 @@ This will generate a table with the stores in the first column, and the items in ), ( 'table', -'# Using row based custom actions in a table +'## Using Action Buttons in a table. -The table has a column of buttons, each button defined by the `_sqlpage_actions` column at the table level, and by the `_sqlpage_actions` property at the row level. +### Preset Actions: `edit_url` & `delete_url` +Since edit and delete are common actions, the `table` component has dedicated `edit_url` and `delete_url` properties to add buttons for these actions. +The value of these properties should be a URL, containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. -```sql - SELECT - name, vendor, product_number, facility_name, - lot_number, status, date_of_expiration, - --Use the unique identifier of the row as the _sqlpage_id property - standard_id AS _sqlpage_id, - --Build an array of objects, each object defining a button with the following properties: name, icon, link, tooltip - json_array(--SQLite specific, refer to your database documentation for the equivalent JSON functions - --The {id} placeholder in the link property will be replaced by the value of the _sqlpage_id property for that row. - json_object(''name'', ''history'', ''tooltip'', ''View Standard History'', ''link'', ''./history.sql?standard_id={id}'', ''icon'', ''history''), - json_object(''name'', ''view_coa'', ''tooltip'', ''View Certificate of Analysis'', ''link'', c_of_a_path, ''icon'', ''file-type-pdf''), - json_object(''name'', ''edit'', ''tooltip'', ''Edit Standard'', ''link'', ''./update.sql?id={id}'', ''icon'', ''pencil''), - --We want different actions based on the status of the standard, so we use a CASE statement to build the appropriate action - CASE - WHEN status = ''Available'' THEN json_object( - ''name'',''Action'', - ''tooltip'',''Set In Use'', - ''link'',''./actions/set_in_use.sql?standard_id='' || standard_id, - ''icon'',''caret-right'' - ) - WHEN status = ''In Use'' THEN json_object( - ''name'',''Action'', - ''tooltip'',''Retire Standard'', - ''link'',''./actions/retire.sql?standard_id='' || standard_id, - ''icon'',''test-pipe-off'' - ) - WHEN status = ''Retired'' THEN json_object( - ''name'',''Action'', - ''tooltip'',''Discard Standard'', - ''link'',''./actions/discard.sql?standard_id='' || standard_id, - ''icon'',''flask-off'' - ) - -- Include an action with no link or icon as a placeholder to keep the buttons aligned and make sure the header is correct. - WHEN status = ''Discarded'' THEN json_object(''name'',''Action'') - - ELSE json_object(''name'',''Action'') - END - ) - AS _sqlpage_actions - FROM standard; - - ``` +### Column with fixed action buttons +You may want to add custom action buttons to your table rows, for instance to view details, download a file, or perform a custom operation. +For this, the `table` component has a `custom_actions` property that lets you define a column of buttons, each button defined by a name, an icon, a link, and an optional tooltip. - ' +### Column with variable action buttons + +The `table` component also supports the row level `_sqlpage_actions` column in your data table. +This is helpful if you want a more complex logic, for instance to disable a button on some rows, or to change the link or icon based on the row data. + +> WARNING! +> If the number of array items in `_sqlpage_actions` is not consistent across all rows, the table may not render correctly. +> You can leave blank spaces by including an object with only the `name` property. + +The table has a column of buttons, each button defined by the `_sqlpage_actions` column at the table level, and by the `_sqlpage_actions` property at the row level. +### `custom_actions` & `_sqlpage_actions` JSON properties. +Each button is defined by the following properties: +* `name`: sets the column header and the tooltip if no tooltip is provided, +* `tooltip`: text to display when hovering over the button, +* `link`: the URL to navigate to when the button is clicked, possibly containing the {id} placeholder that will be replaced by the value of the `_sqlpage_id` property for that row, +* `icon`: the tabler icon name or image link to display on the button + +### Example using all of the above +' , json('[ { - "component": "table" + "component": "table", + "edit_url": "./update.sql?id={id}", + "delete_url": "./delete.sql?id={id}", + "custom_actions": [ + { + "name": "history", + "tooltip": "View Standard History", + "link": "./history.sql?standard_id={id}", + "icon": "history" + } + ] }, { "name": "CalStd", "vendor": "PharmaCo", "product_number": "P1234", - "facility_name": "A Plant", "lot_number": "T23523", "status": "Available", "date_of_expiration": "2026-10-13", "_sqlpage_id": 32, "_sqlpage_actions": [ - { - "name": "history", - "tooltip": "View Standard History", - "link": "./history.sql?standard_id={id}", - "icon": "history" - }, { "name": "view_coa", "tooltip": "View Certificate of Analysis", - "link": "/c_of_a\\2025-09-30_22h01m21s_B69baKoz.pdf", + "link": "/c_of_a/2025-09-30_22h01m21s_B69baKoz.pdf", "icon": "file-type-pdf" }, - { - "name": "edit", - "tooltip": "Edit Standard", - "link": "./update.sql?id={id}", - "icon": "pencil" - }, { "name": "Action", "tooltip": "Set In Use", @@ -1095,30 +1073,17 @@ The table has a column of buttons, each button defined by the `_sqlpage_actions` "name": "CalStd", "vendor": "PharmaCo", "product_number": "P1234", - "facility_name": "A Plant", "lot_number": "T2352", "status": "In Use", "date_of_expiration": "2026-10-14", "_sqlpage_id": 33, "_sqlpage_actions": [ - { - "name": "history", - "tooltip": "View Standard History", - "link": "./history.sql?standard_id={id}", - "icon": "history" - }, { "name": "view_coa", "tooltip": "View Certificate of Analysis", - "link": "/c_of_a\\2025-09-30_22h05m13s_cP7gqMyi.pdf", + "link": "/c_of_a/2025-09-30_22h05m13s_cP7gqMyi.pdf", "icon": "file-type-pdf" }, - { - "name": "edit", - "tooltip": "Edit Standard", - "link": "./update.sql?id={id}", - "icon": "pencil" - }, { "name": "Action", "tooltip": "Retire Standard", @@ -1131,35 +1096,25 @@ The table has a column of buttons, each button defined by the `_sqlpage_actions` "name": "CalStd", "vendor": "PharmaCo", "product_number": "P1234", - "facility_name": "A Plant", "lot_number": "A123", "status": "Discarded", "date_of_expiration": "2026-09-30", "_sqlpage_id": 31, "_sqlpage_actions": [ - { - "name": "history", - "tooltip": "View Standard History", - "link": "./history.sql?standard_id={id}", - "icon": "history" - }, { "name": "view_coa", "tooltip": "View Certificate of Analysis", - "link": "#", + "link": "025-09-30_22h01m21s_B439baKoz.pdf", "icon": "file-type-pdf" }, { - "name": "edit", - "tooltip": "Edit Standard", - "link": "./update.sql?id={id}", - "icon": "pencil" - }, - null + "name": "Action" + } ] } -]') - ); +]' +) +); From 3654d4272bdd1b7ff0d559327b498f026fda3361 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Tue, 14 Oct 2025 19:43:02 -0700 Subject: [PATCH 29/82] Updated class settings in table.handlebars so that action buttons are centered, and _col_{name} is included in new rows. --- sqlpage/templates/table.handlebars | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sqlpage/templates/table.handlebars b/sqlpage/templates/table.handlebars index 639f9341..bf1cd3e4 100644 --- a/sqlpage/templates/table.handlebars +++ b/sqlpage/templates/table.handlebars @@ -53,16 +53,16 @@ {{/if}} {{/each}} - {{#if ../edit_url}}Edit{{/if}} - {{#if ../delete_url}}Delete{{/if}} + {{#if ../edit_url}}Edit{{/if}} + {{#if ../delete_url}}Delete{{/if}} {{#if ../custom_actions}} {{#each ../custom_actions}} - {{this.name}} + {{this.name}} {{/each}} {{/if}} {{#if _sqlpage_actions}} {{#each _sqlpage_actions}} - {{this.name}} + {{this.name}} {{/each}} {{/if}} @@ -92,14 +92,14 @@ {{/if~}} {{~/each~}} {{#if ../edit_url}} - + {{~icon_img 'edit'~}} {{/if}} {{#if ../delete_url}} - + {{~icon_img 'trash'~}} @@ -107,8 +107,8 @@ {{/if}} {{#if ../custom_actions}} {{#each ../custom_actions}} - - {{!Title property sets the tooltip text}} + + {{!Title property sets the tooltip text}} {{~icon_img this.icon~}} @@ -116,8 +116,8 @@ {{/if}} {{#if _sqlpage_actions}} {{#each _sqlpage_actions}} - - + + {{~icon_img this.icon~}} From 83be28bd60d5a94940c5357b9e74628ad7bb13a8 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Tue, 14 Oct 2025 20:23:19 -0700 Subject: [PATCH 30/82] Eliminate clippy redundant else error from src/webserver/http.rs cargo clippy Checking sqlpage v0.38.0 error: redundant else block --> src\webserver\http.rs:493:6 | 493 | } else { | ______^ 494 | | if let Some(domain) = &config.https_domain { 495 | | let mut listen_on_https = listen_on; 496 | | listen_on_https.set_port(443); ... | 511 | | } | |_____^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else note: the lint level is defined here --> src\lib.rs:1:9 | 1 | #![deny(clippy::pedantic)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::redundant_else)]` implied by `#[deny(clippy::pedantic)]` help: remove the `else` block and move the contents out | 493 ~ } 494 + if let Some(domain) = &config.https_domain { 495 + let mut listen_on_https = listen_on; 496 + listen_on_https.set_port(443); 497 + log::debug!("Will start HTTPS server on {listen_on_https}"); 498 + let config = make_auto_rustls_config(domain, config); 499 + server = server 500 + .bind_rustls_0_23(listen_on_https, config) 501 + .map_err(|e| bind_error(e, listen_on_https))?; 502 + } else if listen_on.port() == 443 { 503 + bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); 504 + } 505 + if listen_on.port() != 443 { 506 + log::debug!("Will start HTTP server on {listen_on}"); 507 + server = server 508 + .bind(listen_on) 509 + .map_err(|e| bind_error(e, listen_on))?; 510 + } | error: could not compile `sqlpage` (lib) due to 1 previous error --- src/webserver/http.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/webserver/http.rs b/src/webserver/http.rs index 88c9966e..6f163a90 100644 --- a/src/webserver/http.rs +++ b/src/webserver/http.rs @@ -490,24 +490,23 @@ pub async fn run_server(config: &AppConfig, state: AppState) -> anyhow::Result<( } #[cfg(not(target_family = "unix"))] anyhow::bail!("Unix sockets are not supported on your operating system. Use listen_on instead of unix_socket."); - } else { - if let Some(domain) = &config.https_domain { - let mut listen_on_https = listen_on; - listen_on_https.set_port(443); - log::debug!("Will start HTTPS server on {listen_on_https}"); - let config = make_auto_rustls_config(domain, config); - server = server - .bind_rustls_0_23(listen_on_https, config) - .map_err(|e| bind_error(e, listen_on_https))?; - } else if listen_on.port() == 443 { - bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); - } - if listen_on.port() != 443 { - log::debug!("Will start HTTP server on {listen_on}"); - server = server - .bind(listen_on) - .map_err(|e| bind_error(e, listen_on))?; - } + } + if let Some(domain) = &config.https_domain { + let mut listen_on_https = listen_on; + listen_on_https.set_port(443); + log::debug!("Will start HTTPS server on {listen_on_https}"); + let config = make_auto_rustls_config(domain, config); + server = server + .bind_rustls_0_23(listen_on_https, config) + .map_err(|e| bind_error(e, listen_on_https))?; + } else if listen_on.port() == 443 { + bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); + } + if listen_on.port() != 443 { + log::debug!("Will start HTTP server on {listen_on}"); + server = server + .bind(listen_on) + .map_err(|e| bind_error(e, listen_on))?; } log_welcome_message(config); From 81d2dd43e3ae85178e4dc0e65a87998174684065 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Thu, 16 Oct 2025 10:18:17 +0200 Subject: [PATCH 31/82] update deps --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ae80844..39a06518 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -899,9 +899,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -3823,9 +3823,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", From cc3faba20f1b2809ceb7fee31b3bc3bc781866df Mon Sep 17 00:00:00 2001 From: lovasoa Date: Fri, 17 Oct 2025 21:45:05 +0200 Subject: [PATCH 32/82] fix https://github.com/sqlpage/SQLPage/issues/1055 --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- src/webserver/database/sql.rs | 8 +++++++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39a06518..f33ffd2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,9 +1233,9 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] @@ -2685,14 +2685,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3782,9 +3782,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" dependencies = [ "aws-lc-rs", "log", @@ -4219,7 +4219,7 @@ dependencies = [ [[package]] name = "sqlpage" -version = "0.38.0" +version = "0.38.1" dependencies = [ "actix-multipart", "actix-rt", diff --git a/Cargo.toml b/Cargo.toml index c7248abd..373c1078 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sqlpage" -version = "0.38.0" +version = "0.38.1" edition = "2021" description = "Build data user interfaces entirely in SQL. A web server that takes .sql files and formats the query result using pre-made configurable professional-looking components." keywords = ["web", "sql", "framework"] diff --git a/src/webserver/database/sql.rs b/src/webserver/database/sql.rs index b624adcf..6403adf7 100644 --- a/src/webserver/database/sql.rs +++ b/src/webserver/database/sql.rs @@ -923,7 +923,13 @@ impl VisitorMut for ParameterExtractor { Expr::Cast { kind: kind @ CastKind::DoubleColon, .. - } if self.db_info.database_type != SupportedDatabase::Postgres => { + } if ![ + SupportedDatabase::Postgres, + SupportedDatabase::Snowflake, + SupportedDatabase::Generic, + ] + .contains(&self.db_info.database_type) => + { log::warn!("Casting with '::' is not supported on your database. \ For backwards compatibility with older SQLPage versions, we will transform it to CAST(... AS ...)."); *kind = CastKind::Cast; From 0184bb9b9a3738f73d27bb45ff0842d5f189c8d8 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Fri, 17 Oct 2025 23:42:33 +0200 Subject: [PATCH 33/82] Enhance routing to support SQL execution for non-SQL file extensions - Updated routing logic to execute SQL files when a request is made for paths with extensions other than .sql. - Added tests to verify that SQL files are executed correctly for paths with non-SQL extensions. - Updated CHANGELOG to reflect this new feature in version 0.38.1. --- CHANGELOG.md | 3 +++ src/webserver/routing.rs | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66bdae84..eada1c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG.md +## v0.38.1 + - Ability to execute sql for URL paths with another extension. If you create sitemap.xml.sql, it will be executed for example.com/sitemap.xml + ## v0.38.0 - Added support for the Open Database Connectivity (ODBC) standard. - This makes SQLPage compatible with many new databases, including: diff --git a/src/webserver/routing.rs b/src/webserver/routing.rs index 9d79e475..1f506c43 100644 --- a/src/webserver/routing.rs +++ b/src/webserver/routing.rs @@ -22,7 +22,8 @@ //! //! #### Paths with other extensions (assets): //! - If the file exists: **Serve** the static file -//! - If not found: Look for custom 404 handlers (see Error Handling below) +//! - If not found but `{path}.sql` exists: **Execute** the SQL file +//! - If neither found: Look for custom 404 handlers (see Error Handling below) //! //! #### Paths without extension: //! - First, try to find `{path}.sql` and **Execute** if found @@ -66,6 +67,13 @@ //! - If favicon.ico exists: Serve favicon.ico //! - Else if 404.sql exists: Execute 404.sql //! - Else: Default 404 +//! +//! Request: GET /api/data.json +//! - If api/data.json exists: Serve api/data.json +//! - Else if api/data.json.sql exists: Execute api/data.json.sql +//! - Else if api/404.sql exists: Execute api/404.sql +//! - Else if 404.sql exists: Execute 404.sql +//! - Else: Default 404 //! ``` use crate::filesystem::FileSystem; @@ -140,12 +148,13 @@ where C: RoutingConfig, { let result = match check_path(path_and_query, config) { - Ok(path) => match path.extension() { + Ok(path) => match path.extension().and_then(|e| e.to_str()) { + Some(SQL_EXTENSION) => find_file_or_not_found(&path, SQL_EXTENSION, store).await?, + Some(extension) => match find_file(&path, extension, store).await? { + Some(action) => action, + None => calculate_route_without_extension(path_and_query, path, store).await?, + }, None => calculate_route_without_extension(path_and_query, path, store).await?, - Some(extension) => { - let ext = extension.to_str().unwrap_or_default(); - find_file_or_not_found(&path, ext, store).await? - } }, Err(action) => action, }; @@ -189,7 +198,7 @@ where path.push(INDEX); find_file_or_not_found(&path, SQL_EXTENSION, store).await } else { - let path_with_ext = path.with_extension(SQL_EXTENSION); + let path_with_ext = PathBuf::from(format!("{}.{SQL_EXTENSION}", path.display())); match find_file_or_not_found(&path_with_ext, SQL_EXTENSION, store).await? { Execute(x) => Ok(Execute(x)), other_action => { @@ -340,6 +349,22 @@ mod tests { assert_eq!(expected, actual); } + + #[tokio::test] + async fn path_with_non_sql_extension_executes_sql_file() { + let actual = do_route("/abc.def", File("abc.def.sql"), None).await; + let expected = execute("abc.def.sql"); + + assert_eq!(expected, actual); + } + + #[tokio::test] + async fn path_with_non_sql_extension_and_site_prefix_executes_sql_file() { + let actual = do_route("/prefix/abc.def", File("abc.def.sql"), Some("/prefix/")).await; + let expected = execute("abc.def.sql"); + + assert_eq!(expected, actual); + } } mod custom_not_found { From c5c4a4fcd5d96bbb9dcd58af9890a75d90b1963d Mon Sep 17 00:00:00 2001 From: lovasoa Date: Fri, 17 Oct 2025 23:43:20 +0200 Subject: [PATCH 34/82] add llms.txt closes https://github.com/sqlpage/SQLPage/issues/980 --- examples/official-site/llms.txt.sql | 93 +++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 examples/official-site/llms.txt.sql diff --git a/examples/official-site/llms.txt.sql b/examples/official-site/llms.txt.sql new file mode 100644 index 00000000..95cd85ef --- /dev/null +++ b/examples/official-site/llms.txt.sql @@ -0,0 +1,93 @@ +select + 'http_header' as component, + 'text/markdown; charset=utf-8' as "Content-Type", + 'inline; filename="llms.txt"' as "Content-Disposition"; + +select + 'shell-empty' as component, + '# SQLPage + +> SQLPage is a SQL-only web application framework. It lets you build entire websites and web applications using nothing but SQL queries. Write `.sql` files, and SQLPage executes them, maps results to UI components (handlebars templates), and streams HTML to the browser. + +SQLPage is designed for developers who are comfortable with SQL but want to avoid the complexity of traditional web frameworks. It works with SQLite, PostgreSQL, MySQL, and Microsoft SQL Server, and through ODBC with any other database that has an ODBC driver installed. + +Key features: +- No backend code needed: Your SQL files are your backend +- Component-based UI: Built-in components for forms, tables, charts, maps, and more +- Database-first: Every HTTP request triggers a sequence of SQL queries from a .sql file, the results are rendered with built-in or custom components, defined as .handlebars files in the sqlpage/templates folder. +- Simple deployment: Single binary with no runtime dependencies +- Secure by default: Parameterized queries prevent SQL injection + +## Getting Started + +- [Introduction to SQLPage: installation, guiding principles, and a first example](/your-first-sql-website/tutorial.md): Complete beginner tutorial covering setup, database connections, forms, and deployment + +## Core Documentation + +- [Components reference](/documentation.sql): List of all ' || ( + select + count(*) + from + component + ) || ' built-in UI components with parameters and examples +- [Functions reference](/functions.sql): SQLPage built-in functions for handling requests, encoding data, and more +- [Configuration guide](https://github.com/sqlpage/SQLPage/blob/main/configuration.md): Complete list of configuration options in sqlpage.json + +## Components + +' || ( + select + group_concat ( + '### [' || name || '](/component.sql?component=' || name || ') + +' || description || ' + +', + '' + ) + from + component + order by + name + ) || ' + +## Functions + +' || ( + select + group_concat ( + '### [sqlpage.' || name || '()](/functions.sql?function=' || name || ') +' || replace ( + replace ( + description_md, + char(10) || '#', + char(10) || '###' + ), + ' ', + ' ' + ), + char(10) + ) + from + sqlpage_functions + order by + name + ) || ' + +## Examples + +- [Authentication example](https://github.com/sqlpage/SQLPage/tree/main/examples/user-authentication): Complete user registration and login system +- [CRUD application](https://github.com/sqlpage/SQLPage/tree/main/examples/CRUD%20-%20Authentication): Create, read, update, delete with authentication +- [Image gallery](https://github.com/sqlpage/SQLPage/tree/main/examples/image%20gallery%20with%20user%20uploads): File upload and image display +- [Todo application](https://github.com/sqlpage/SQLPage/tree/main/examples/todo%20application): Simple CRUD app +- [Master-detail forms](https://github.com/sqlpage/SQLPage/tree/main/examples/master-detail-forms): Working with related data +- [Charts example](https://github.com/sqlpage/SQLPage/tree/main/examples/plots%20tables%20and%20forms): Data visualization + +## Optional + +- [Custom components guide](/custom_components.sql): Create your own handlebars components +- [Safety and security](/safety.sql): Understanding SQL injection prevention +- [Docker deployment](https://github.com/sqlpage/SQLPage#with-docker): Running SQLPage in containers +- [Systemd service](https://github.com/sqlpage/SQLPage/blob/main/sqlpage.service): Production deployment setup +- [Repository structure](https://github.com/sqlpage/SQLPage/blob/main/CONTRIBUTING.md): Project organization and contribution guide +' as html; \ No newline at end of file From b577695eee172f3276c2c24dee0ac0de66d5912c Mon Sep 17 00:00:00 2001 From: lovasoa Date: Fri, 17 Oct 2025 23:51:28 +0200 Subject: [PATCH 35/82] Enhance llms.txt.sql to include detailed parameter documentation - Updated the SQL file to improve the output format for components, adding sections for top-level and row-level parameters. - Each parameter now includes its type, requirement status, and description for better clarity in the generated documentation. --- examples/official-site/llms.txt.sql | 60 +++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/examples/official-site/llms.txt.sql b/examples/official-site/llms.txt.sql index 95cd85ef..a1f5cda5 100644 --- a/examples/official-site/llms.txt.sql +++ b/examples/official-site/llms.txt.sql @@ -38,17 +38,69 @@ Key features: ' || ( select group_concat ( - '### [' || name || '](/component.sql?component=' || name || ') + '### [' || c.name || '](/component.sql?component=' || c.name || ') -' || description || ' +' || c.description || ' + +' || ( + select + case when exists ( + select + 1 + from + parameter + where + component = c.name + and top_level + ) then '#### Top-level parameters + +' || group_concat ( + '- `' || name || '` (' || type || ')' || case when not optional then ' **REQUIRED**' else '' end || ': ' || description, + char(10) + ) + else + '' + end + from + parameter + where + component = c.name + and top_level + ) || ' + +' || ( + select + case when exists ( + select + 1 + from + parameter + where + component = c.name + and not top_level + ) then '#### Row-level parameters + +' || group_concat ( + '- `' || name || '` (' || type || ')' || case when not optional then ' **REQUIRED**' else '' end || ': ' || description, + char(10) + ) + else + '' + end + from + parameter + where + component = c.name + and not top_level + ) || ' ', '' ) from - component + component c order by - name + c.name ) || ' ## Functions From 5d5d1f94d78248283d35035f8a5f12dcb852694d Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Sat, 18 Oct 2025 12:19:15 +0200 Subject: [PATCH 36/82] The login component is an authentication form for users of an application. --- .../sqlpage/migrations/68_login.sql | 52 +++++++++++ .../99_shared_id_class_attributes.sql | 6 +- sqlpage/templates/login.handlebars | 89 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 examples/official-site/sqlpage/migrations/68_login.sql create mode 100644 sqlpage/templates/login.handlebars diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql new file mode 100644 index 00000000..7230f759 --- /dev/null +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -0,0 +1,52 @@ +INSERT INTO component(name, icon, description, introduced_in_version) VALUES + ('login', 'password-user', ' +The login component is an authentication form for users of an application. + +It allows the entry of a user account consisting of a username and a password. + +It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); + +INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES + ('title','Title of the authentication form.','TEXT',TRUE,TRUE), + ('enctype','Form data encoding.','TEXT',TRUE,TRUE), + ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('username','User account identifier.','TEXT',TRUE,FALSE), + ('password','User password.','TEXT',TRUE,FALSE), + ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), + ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), + ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), + ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), + ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), + ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), + ('validate_size','The size of the validation button.','TEXT',TRUE,TRUE) +) x; + +-- Insert example(s) for the component +INSERT INTO example(component, description, properties) +VALUES ( + 'login', + 'Using the main options of the login component', + JSON( + '[ + { + "component": "login", + "action": "login.sql", + "image": "../assets/icon.webp", + "title": "Please login to your account", + "username": "Username", + "password": "Password", + "forgot_password_text": "Forgot your password?", + "forgot_password_link": "reset_password.sql", + "remember_me_text": "Remember me", + "footer_md": "Don''t have an account? [Register here](register.sql)", + "validate": "Sign in" + } + ]' + ) + ); + +-- 265707.png \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql index 47e66576..df054541 100644 --- a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql +++ b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql @@ -18,7 +18,8 @@ FROM (VALUES ('title', TRUE), ('tracking', TRUE), ('text', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); INSERT INTO parameter(component, top_level, name, description, type, optional) @@ -49,6 +50,7 @@ FROM (VALUES ('timeline', FALSE), ('title', TRUE), ('tracking', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars new file mode 100644 index 00000000..f292a18d --- /dev/null +++ b/sqlpage/templates/login.handlebars @@ -0,0 +1,89 @@ +
+
+
+
+ {{#if image}} +
+ +
+ {{/if}} + {{#if title}} +

{{title}}

+ {{/if}} + +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ {{#if remember_me_text}} + + {{/if}} +
+ +
+ {{#if (or footer footer_md)}} +
+
+ + {{#if footer}} + {{footer}} + {{else}} + {{#if footer_md}} + {{{markdown footer_md}}} + {{/if}} + {{/if}} + +
+ {{/if}} +
+
+
+
From f1375615f4457b871b94bd213bd9542949d655ab Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 20 Oct 2025 18:27:25 +0200 Subject: [PATCH 37/82] always display line info in errors https://github.com/sqlpage/SQLPage/issues/1057 --- CHANGELOG.md | 1 + Cargo.lock | 82 ++++++++++---------- src/webserver/database/error_highlighting.rs | 42 +++++----- src/webserver/database/sql.rs | 31 ++++++-- 4 files changed, 91 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eada1c2e..1cd2975a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## v0.38.1 - Ability to execute sql for URL paths with another extension. If you create sitemap.xml.sql, it will be executed for example.com/sitemap.xml + - Display source line info in errors even when the database does not return a precise error position. In this case, the entire problematic SQL statement is referenced. ## v0.38.0 - Added support for the Open Database Connectivity (ODBC) standard. diff --git a/Cargo.lock b/Cargo.lock index f33ffd2f..3d36bc87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bytes", "futures-core", "futures-sink", @@ -31,7 +31,7 @@ dependencies = [ "actix-tls", "actix-utils", "base64 0.22.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "brotli 8.0.2", "bytes", "bytestring", @@ -325,7 +325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.4", + "bitflags 2.10.0", "cc", "cesu8", "jni", @@ -699,9 +699,9 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bigdecimal" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" +checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934" dependencies = [ "autocfg", "libm", @@ -718,7 +718,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -740,11 +740,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -862,7 +862,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "log", "polling", "rustix 0.38.44", @@ -1984,7 +1984,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.11.4", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -2326,9 +2326,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -2559,7 +2559,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "redox_syscall 0.5.18", ] @@ -2701,7 +2701,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "jni-sys", "log", "ndk-sys", @@ -2815,9 +2815,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2825,9 +2825,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2876,7 +2876,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "libc", "objc2", @@ -2892,7 +2892,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-core-location", @@ -2916,7 +2916,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-foundation", @@ -2958,7 +2958,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "dispatch", "libc", @@ -2983,7 +2983,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-foundation", @@ -2995,7 +2995,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-foundation", @@ -3018,7 +3018,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-cloud-kit", @@ -3050,7 +3050,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "objc2", "objc2-core-location", @@ -3589,7 +3589,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -3695,7 +3695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.4", + "bitflags 2.10.0", "serde", "serde_derive", ] @@ -3760,7 +3760,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3773,7 +3773,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.11.0", @@ -3943,7 +3943,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4024,7 +4024,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "memchr", "ryu", @@ -4083,7 +4083,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", "schemars 1.0.4", "serde_core", @@ -4298,7 +4298,7 @@ dependencies = [ "atoi", "base64 0.22.1", "bigdecimal", - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "bytes", "chrono", @@ -4320,7 +4320,7 @@ dependencies = [ "hex", "hkdf", "hmac", - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "libc", "libsqlite3-sys", @@ -4425,9 +4425,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -4654,7 +4654,7 @@ version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "toml_datetime", "toml_parser", "winnow", @@ -5337,7 +5337,7 @@ checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" dependencies = [ "android-activity", "atomic-waker", - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "calloop", "cfg_aliases", @@ -5413,7 +5413,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "dlib", "log", "once_cell", diff --git a/src/webserver/database/error_highlighting.rs b/src/webserver/database/error_highlighting.rs index 4c1c3ef2..7c9a01eb 100644 --- a/src/webserver/database/error_highlighting.rs +++ b/src/webserver/database/error_highlighting.rs @@ -27,41 +27,47 @@ impl std::fmt::Display for NiceDatabaseError { )?; if let sqlx::error::Error::Database(db_err) = &self.db_err { let Some(mut offset) = db_err.offset() else { - return write!(f, "{}", self.query); + write!(f, "{}", self.query)?; + self.show_position_info(f)?; + return Ok(()); }; for line in self.query.lines() { if offset > line.len() { offset -= line.len() + 1; } else { highlight_line_offset(f, line, offset); - if let Some(query_position) = self.query_position { - let start_line = query_position.start.line; - let end_line = query_position.end.line; - if start_line == end_line { - write!(f, "{}: line {}", self.source_file.display(), start_line)?; - } else { - write!( - f, - "{}: lines {} to {}", - self.source_file.display(), - start_line, - end_line - )?; - } - } + self.show_position_info(f)?; break; } } Ok(()) } else { - write!(f, "{}", self.query) + write!(f, "{}", self.query)?; + self.show_position_info(f)?; + Ok(()) } } } +impl NiceDatabaseError { + fn show_position_info(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "\n{}", self.source_file.display())?; + let _: () = if let Some(query_position) = self.query_position { + let start_line = query_position.start.line; + let end_line = query_position.end.line; + if start_line == end_line { + write!(f, ": line {start_line}")?; + } else { + write!(f, ": lines {start_line} to {end_line}")?; + } + }; + Ok(()) + } +} + impl std::error::Error for NiceDatabaseError {} -/// Display a database error with a highlighted line and character offset. +/// Display a database error without any position information #[must_use] pub fn display_db_error( source_file: &Path, diff --git a/src/webserver/database/sql.rs b/src/webserver/database/sql.rs index 6403adf7..eefedbc0 100644 --- a/src/webserver/database/sql.rs +++ b/src/webserver/database/sql.rs @@ -20,8 +20,9 @@ use sqlparser::dialect::{ }; use sqlparser::parser::{Parser, ParserError}; use sqlparser::tokenizer::Token::{self, SemiColon, EOF}; -use sqlparser::tokenizer::{TokenWithSpan, Tokenizer}; +use sqlparser::tokenizer::{Location, Span, TokenWithSpan, Tokenizer}; use sqlx::any::AnyKind; +use std::fmt::Write; use std::ops::ControlFlow; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -241,11 +242,29 @@ fn extract_query_start(stmt: &impl Spanned) -> SourceSpan { } fn syntax_error(err: ParserError, parser: &Parser, sql: &str) -> ParsedStatement { - let location = parser.peek_token_no_skip().span; - ParsedStatement::Error(anyhow::Error::from(err).context(format!( - "Parsing failed: SQLPage couldn't understand the SQL file. Please check for syntax errors:\n\n{}", - quote_source_with_highlight(sql, location.start.line, location.start.column) - ))) + let Span { + start: Location { + line: start_line, + column: start_column, + }, + end: Location { line: end_line, .. }, + } = parser.peek_token_no_skip().span; + + let mut msg = String::from( + "Parsing failed: SQLPage couldn't understand the SQL file. Please check for syntax errors on ", + ); + if start_line == end_line { + write!(&mut msg, "line {start_line}:").unwrap(); + } else { + write!(&mut msg, "lines {start_line} to {end_line}:").unwrap(); + } + write!( + &mut msg, + "\n{}", + quote_source_with_highlight(sql, start_line, start_column) + ) + .unwrap(); + ParsedStatement::Error(anyhow::Error::from(err).context(msg)) } fn dialect_for_db(dbms: SupportedDatabase) -> Box { From 6729e10a01fc442eb981490440c564c50497f755 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Mon, 20 Oct 2025 09:31:36 -0700 Subject: [PATCH 38/82] Added sqlpage version number information to the new components. --- .../official-site/sqlpage/migrations/01_documentation.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/01_documentation.sql b/examples/official-site/sqlpage/migrations/01_documentation.sql index b9fae3d9..410dfe2f 100644 --- a/examples/official-site/sqlpage/migrations/01_documentation.sql +++ b/examples/official-site/sqlpage/migrations/01_documentation.sql @@ -810,15 +810,15 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('money', 'Name of a numeric column whose values should be displayed as currency amounts, in the currency defined by the `currency` property. This argument can be repeated multiple times.', 'TEXT', TRUE, TRUE), ('currency', 'The ISO 4217 currency code (e.g., USD, EUR, GBP, etc.) to use when formatting monetary values.', 'TEXT', TRUE, TRUE), ('number_format_digits', 'Maximum number of decimal digits to display for numeric values.', 'INTEGER', TRUE, TRUE), - ('edit_url', 'If set, an edit button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the edit button will take the user to that URL.', 'TEXT', TRUE, TRUE), - ('delete_url', 'If set, a delete button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the delete button will take the user to that URL.', 'TEXT', TRUE, TRUE), - ('custom_actions', 'If set, a column of custom action buttons will be added to each row. The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', TRUE, TRUE), + ('edit_url', 'If set, an edit button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the edit button will take the user to that URL. Added in v0.39.0', 'TEXT', TRUE, TRUE), + ('delete_url', 'If set, a delete button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the delete button will take the user to that URL. Added in v0.39.0', 'TEXT', TRUE, TRUE), + ('custom_actions', 'If set, a column of custom action buttons will be added to each row. The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button). Added in v0.39.0', 'JSON', TRUE, TRUE), -- row level ('_sqlpage_css_class', 'For advanced users. Sets a css class on the table row. Added in v0.8.0.', 'TEXT', FALSE, TRUE), ('_sqlpage_color', 'Sets the background color of the row. Added in v0.8.0.', 'COLOR', FALSE, TRUE), ('_sqlpage_footer', 'Sets this row as the table footer. It is recommended that this parameter is applied to the last row. Added in v0.34.0.', 'BOOLEAN', FALSE, TRUE), ('_sqlpage_id', 'Sets the id of the html tabler row element. Allows you to make links targeting a specific row in a table.', 'TEXT', FALSE, TRUE), - ('_sqlpage_actions', 'Sets custom action buttons for this specific row in addition to any defined at the table level, The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', FALSE, TRUE) + ('_sqlpage_actions', 'Sets custom action buttons for this specific row in addition to any defined at the table level, The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button). Added in v0.39.0', 'JSON', FALSE, TRUE) ) x; INSERT INTO example(component, description, properties) VALUES From 5d9df45231ab3a68e847826fcee1c30763b320ca Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Mon, 20 Oct 2025 09:53:10 -0700 Subject: [PATCH 39/82] Undo changes to http.rs since it is not part of the feature. --- src/webserver/http.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/webserver/http.rs b/src/webserver/http.rs index 88c9966e..6f163a90 100644 --- a/src/webserver/http.rs +++ b/src/webserver/http.rs @@ -490,24 +490,23 @@ pub async fn run_server(config: &AppConfig, state: AppState) -> anyhow::Result<( } #[cfg(not(target_family = "unix"))] anyhow::bail!("Unix sockets are not supported on your operating system. Use listen_on instead of unix_socket."); - } else { - if let Some(domain) = &config.https_domain { - let mut listen_on_https = listen_on; - listen_on_https.set_port(443); - log::debug!("Will start HTTPS server on {listen_on_https}"); - let config = make_auto_rustls_config(domain, config); - server = server - .bind_rustls_0_23(listen_on_https, config) - .map_err(|e| bind_error(e, listen_on_https))?; - } else if listen_on.port() == 443 { - bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); - } - if listen_on.port() != 443 { - log::debug!("Will start HTTP server on {listen_on}"); - server = server - .bind(listen_on) - .map_err(|e| bind_error(e, listen_on))?; - } + } + if let Some(domain) = &config.https_domain { + let mut listen_on_https = listen_on; + listen_on_https.set_port(443); + log::debug!("Will start HTTPS server on {listen_on_https}"); + let config = make_auto_rustls_config(domain, config); + server = server + .bind_rustls_0_23(listen_on_https, config) + .map_err(|e| bind_error(e, listen_on_https))?; + } else if listen_on.port() == 443 { + bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); + } + if listen_on.port() != 443 { + log::debug!("Will start HTTP server on {listen_on}"); + server = server + .bind(listen_on) + .map_err(|e| bind_error(e, listen_on))?; } log_welcome_message(config); From c371b23af2252dba0e8f8ffbe06601d535f26bc5 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Mon, 20 Oct 2025 10:20:02 -0700 Subject: [PATCH 40/82] Undo changes to http.rs --- src/webserver/http.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/webserver/http.rs b/src/webserver/http.rs index 6f163a90..88c9966e 100644 --- a/src/webserver/http.rs +++ b/src/webserver/http.rs @@ -490,23 +490,24 @@ pub async fn run_server(config: &AppConfig, state: AppState) -> anyhow::Result<( } #[cfg(not(target_family = "unix"))] anyhow::bail!("Unix sockets are not supported on your operating system. Use listen_on instead of unix_socket."); - } - if let Some(domain) = &config.https_domain { - let mut listen_on_https = listen_on; - listen_on_https.set_port(443); - log::debug!("Will start HTTPS server on {listen_on_https}"); - let config = make_auto_rustls_config(domain, config); - server = server - .bind_rustls_0_23(listen_on_https, config) - .map_err(|e| bind_error(e, listen_on_https))?; - } else if listen_on.port() == 443 { - bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); - } - if listen_on.port() != 443 { - log::debug!("Will start HTTP server on {listen_on}"); - server = server - .bind(listen_on) - .map_err(|e| bind_error(e, listen_on))?; + } else { + if let Some(domain) = &config.https_domain { + let mut listen_on_https = listen_on; + listen_on_https.set_port(443); + log::debug!("Will start HTTPS server on {listen_on_https}"); + let config = make_auto_rustls_config(domain, config); + server = server + .bind_rustls_0_23(listen_on_https, config) + .map_err(|e| bind_error(e, listen_on_https))?; + } else if listen_on.port() == 443 { + bail!("Please specify a value for https_domain in the configuration file. This is required when using HTTPS (port 443)"); + } + if listen_on.port() != 443 { + log::debug!("Will start HTTP server on {listen_on}"); + server = server + .bind(listen_on) + .map_err(|e| bind_error(e, listen_on))?; + } } log_welcome_message(config); From 32d6863982bfa90f953fc0f13ec706e6d4848b31 Mon Sep 17 00:00:00 2001 From: Spencer Hansen Date: Mon, 20 Oct 2025 15:48:07 -0700 Subject: [PATCH 41/82] Added checks for active status to dropdown items in shell.handlebars. --- sqlpage/templates/shell.handlebars | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlpage/templates/shell.handlebars b/sqlpage/templates/shell.handlebars index 35f31b91..0e1c7a8e 100644 --- a/sqlpage/templates/shell.handlebars +++ b/sqlpage/templates/shell.handlebars @@ -95,7 +95,7 @@ {{~#with (parse_json this)}} {{#if (or (or this.title this.icon) this.image)}}