mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-13 11:35:00 +00:00
Compare commits
No commits in common. "main" and "v0.49.0" have entirely different histories.
118 changed files with 9599 additions and 47762 deletions
38
.asf.yaml
38
.asf.yaml
|
@ -1,38 +0,0 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
# This file controls the settings of this repository
|
|
||||||
#
|
|
||||||
# See more details at
|
|
||||||
# https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
commits: commits@datafusion.apache.org
|
|
||||||
issues: github@datafusion.apache.org
|
|
||||||
pullrequests: github@datafusion.apache.org
|
|
||||||
github:
|
|
||||||
description: "Extensible SQL Lexer and Parser for Rust"
|
|
||||||
labels:
|
|
||||||
- big-data
|
|
||||||
- rust
|
|
||||||
- sql
|
|
||||||
enabled_merge_buttons:
|
|
||||||
squash: true
|
|
||||||
merge: false
|
|
||||||
rebase: false
|
|
||||||
features:
|
|
||||||
issues: true
|
|
42
.github/actions/setup-builder/action.yaml
vendored
42
.github/actions/setup-builder/action.yaml
vendored
|
@ -1,42 +0,0 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
name: Prepare Rust Builder
|
|
||||||
description: 'Prepare Rust Build Environment'
|
|
||||||
inputs:
|
|
||||||
rust-version:
|
|
||||||
description: 'version of rust to install (e.g. stable)'
|
|
||||||
required: true
|
|
||||||
default: 'stable'
|
|
||||||
targets:
|
|
||||||
description: 'The toolchain targets to add, comma-separated'
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Setup Rust Toolchain
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "Installing ${{ inputs.rust-version }}"
|
|
||||||
if [ -n "${{ inputs.targets}}" ]; then
|
|
||||||
rustup toolchain install ${{ inputs.rust-version }} -t ${{ inputs.targets }}
|
|
||||||
else
|
|
||||||
rustup toolchain install ${{ inputs.rust-version }}
|
|
||||||
fi
|
|
||||||
rustup default ${{ inputs.rust-version }}
|
|
||||||
rustup component add rustfmt clippy
|
|
17
.github/dependabot.yml
vendored
17
.github/dependabot.yml
vendored
|
@ -1,20 +1,3 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: cargo
|
- package-ecosystem: cargo
|
||||||
|
|
39
.github/workflows/license.yml
vendored
39
.github/workflows/license.yml
vendored
|
@ -1,39 +0,0 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
name: license
|
|
||||||
|
|
||||||
# trigger for all PRs and changes to main
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
rat:
|
|
||||||
name: Release Audit Tool (RAT)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: 3.8
|
|
||||||
- name: Audit licenses
|
|
||||||
run: ./dev/release/run-rat.sh .
|
|
117
.github/workflows/rust.yml
vendored
117
.github/workflows/rust.yml
vendored
|
@ -1,59 +1,38 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
name: Rust
|
name: Rust
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
codestyle:
|
codestyle:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Set up Rust
|
||||||
- name: Setup Rust Toolchain
|
uses: hecrj/setup-rust-action@v1
|
||||||
uses: ./.github/actions/setup-builder
|
with:
|
||||||
- run: cargo fmt --all -- --check
|
components: rustfmt
|
||||||
|
# Note that `nightly` is required for `license_template_path`, as
|
||||||
|
# it's an unstable feature.
|
||||||
|
rust-version: nightly
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: cargo +nightly fmt -- --check --config-path <(echo 'license_template_path = "HEADER"')
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Set up Rust
|
||||||
- name: Setup Rust Toolchain
|
uses: hecrj/setup-rust-action@v1
|
||||||
uses: ./.github/actions/setup-builder
|
with:
|
||||||
|
components: clippy
|
||||||
|
- uses: actions/checkout@v2
|
||||||
- run: cargo clippy --all-targets --all-features -- -D warnings
|
- run: cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
benchmark-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup Rust Toolchain
|
|
||||||
uses: ./.github/actions/setup-builder
|
|
||||||
- run: cd sqlparser_bench && cargo clippy --all-targets --all-features -- -D warnings
|
|
||||||
|
|
||||||
compile:
|
compile:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Set up Rust
|
||||||
- name: Setup Rust Toolchain
|
uses: hecrj/setup-rust-action@v1
|
||||||
uses: ./.github/actions/setup-builder
|
- uses: actions/checkout@master
|
||||||
- run: cargo check --all-targets --all-features
|
- run: cargo check --all-targets --all-features
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
|
@ -61,19 +40,19 @@ jobs:
|
||||||
env:
|
env:
|
||||||
RUSTDOCFLAGS: "-Dwarnings"
|
RUSTDOCFLAGS: "-Dwarnings"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Set up Rust
|
||||||
- name: Setup Rust Toolchain
|
uses: hecrj/setup-rust-action@v1
|
||||||
uses: ./.github/actions/setup-builder
|
- uses: actions/checkout@master
|
||||||
- run: cargo doc --document-private-items --no-deps --workspace --all-features
|
- run: cargo doc --document-private-items --no-deps --workspace --all-features
|
||||||
|
|
||||||
compile-no-std:
|
compile-no-std:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Set up Rust
|
||||||
- name: Setup Rust Toolchain
|
uses: hecrj/setup-rust-action@v1
|
||||||
uses: ./.github/actions/setup-builder
|
|
||||||
with:
|
with:
|
||||||
targets: 'thumbv6m-none-eabi'
|
targets: 'thumbv6m-none-eabi'
|
||||||
|
- uses: actions/checkout@master
|
||||||
- run: cargo check --no-default-features --target thumbv6m-none-eabi
|
- run: cargo check --no-default-features --target thumbv6m-none-eabi
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
@ -82,14 +61,52 @@ jobs:
|
||||||
rust: [stable, beta, nightly]
|
rust: [stable, beta, nightly]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Setup Rust
|
||||||
uses: actions/checkout@v4
|
uses: hecrj/setup-rust-action@v1
|
||||||
- name: Setup Rust Toolchain
|
|
||||||
uses: ./.github/actions/setup-builder
|
|
||||||
with:
|
with:
|
||||||
rust-version: ${{ matrix.rust }}
|
rust-version: ${{ matrix.rust }}
|
||||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
|
||||||
- name: Install Tarpaulin
|
- name: Install Tarpaulin
|
||||||
run: cargo install cargo-tarpaulin
|
uses: actions-rs/install@v0.1
|
||||||
|
with:
|
||||||
|
crate: cargo-tarpaulin
|
||||||
|
version: 0.14.2
|
||||||
|
use-tool-cache: true
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cargo test --all-features
|
run: cargo test --all-features
|
||||||
|
|
||||||
|
test-coverage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: hecrj/setup-rust-action@v1
|
||||||
|
with:
|
||||||
|
rust-version: stable
|
||||||
|
- name: Install Tarpaulin
|
||||||
|
uses: actions-rs/install@v0.1
|
||||||
|
with:
|
||||||
|
crate: cargo-tarpaulin
|
||||||
|
version: 0.14.2
|
||||||
|
use-tool-cache: true
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Coverage
|
||||||
|
run: cargo tarpaulin -o Lcov --output-dir ./coverage
|
||||||
|
- name: Coveralls
|
||||||
|
uses: coverallsapp/github-action@master
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
publish-crate:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v0')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test]
|
||||||
|
steps:
|
||||||
|
- name: Set up Rust
|
||||||
|
uses: hecrj/setup-rust-action@v1
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Publish
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cargo publish --token ${{ secrets.CRATES_TOKEN }}
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,7 +3,6 @@
|
||||||
/target/
|
/target/
|
||||||
/sqlparser_bench/target/
|
/sqlparser_bench/target/
|
||||||
/derive/target/
|
/derive/target/
|
||||||
dev/dist
|
|
||||||
|
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
||||||
|
@ -17,5 +16,3 @@ Cargo.lock
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
.DS_store
|
|
1136
CHANGELOG.md
1136
CHANGELOG.md
File diff suppressed because it is too large
Load diff
40
Cargo.toml
40
Cargo.toml
|
@ -1,29 +1,12 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "sqlparser"
|
name = "sqlparser"
|
||||||
description = "Extensible SQL Lexer and Parser with support for ANSI SQL:2011"
|
description = "Extensible SQL Lexer and Parser with support for ANSI SQL:2011"
|
||||||
version = "0.57.0"
|
version = "0.49.0"
|
||||||
authors = ["Apache DataFusion <dev@datafusion.apache.org>"]
|
authors = ["Andy Grove <andygrove73@gmail.com>"]
|
||||||
homepage = "https://github.com/apache/datafusion-sqlparser-rs"
|
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||||
documentation = "https://docs.rs/sqlparser/"
|
documentation = "https://docs.rs/sqlparser/"
|
||||||
keywords = ["ansi", "sql", "lexer", "parser"]
|
keywords = ["ansi", "sql", "lexer", "parser"]
|
||||||
repository = "https://github.com/apache/datafusion-sqlparser-rs"
|
repository = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
include = [
|
include = [
|
||||||
"src/**/*.rs",
|
"src/**/*.rs",
|
||||||
|
@ -37,9 +20,8 @@ name = "sqlparser"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "recursive-protection"]
|
default = ["std"]
|
||||||
std = []
|
std = []
|
||||||
recursive-protection = ["std", "recursive"]
|
|
||||||
# Enable JSON output in the `cli` example:
|
# Enable JSON output in the `cli` example:
|
||||||
json_example = ["serde_json", "serde"]
|
json_example = ["serde_json", "serde"]
|
||||||
visitor = ["sqlparser_derive"]
|
visitor = ["sqlparser_derive"]
|
||||||
|
@ -47,20 +29,24 @@ visitor = ["sqlparser_derive"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bigdecimal = { version = "0.4.1", features = ["serde"], optional = true }
|
bigdecimal = { version = "0.4.1", features = ["serde"], optional = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
recursive = { version = "0.1.1", optional = true}
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
|
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true }
|
|
||||||
# serde_json is only used in examples/cli, but we have to put it outside
|
# serde_json is only used in examples/cli, but we have to put it outside
|
||||||
# of dev-dependencies because of
|
# of dev-dependencies because of
|
||||||
# https://github.com/rust-lang/cargo/issues/1596
|
# https://github.com/rust-lang/cargo/issues/1596
|
||||||
serde_json = { version = "1.0", optional = true }
|
serde_json = { version = "1.0", optional = true }
|
||||||
sqlparser_derive = { version = "0.3.0", path = "derive", optional = true }
|
sqlparser_derive = { version = "0.2.0", path = "derive", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
simple_logger = "5.0"
|
simple_logger = "5.0"
|
||||||
matches = "0.1"
|
matches = "0.1"
|
||||||
pretty_assertions = "1"
|
pretty_assertions = "1"
|
||||||
|
|
||||||
|
[package.metadata.release]
|
||||||
|
# Instruct `cargo release` to not run `cargo publish` locally:
|
||||||
|
# https://github.com/sunng87/cargo-release/blob/master/docs/reference.md#config-fields
|
||||||
|
# See docs/releasing.md for details.
|
||||||
|
publish = false
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
# Document these features on docs.rs
|
# Document these features on docs.rs
|
||||||
features = ["serde", "visitor"]
|
features = ["serde", "visitor"]
|
||||||
|
|
23
HEADER
23
HEADER
|
@ -1,16 +1,11 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
75
README.md
75
README.md
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Extensible SQL Lexer and Parser for Rust
|
# Extensible SQL Lexer and Parser for Rust
|
||||||
|
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
|
@ -53,7 +34,7 @@ println!("AST: {:?}", ast);
|
||||||
This outputs
|
This outputs
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
AST: [Query(Query { ctes: [], body: Select(Select { distinct: false, projection: [UnnamedExpr(Identifier("a")), UnnamedExpr(Identifier("b")), UnnamedExpr(Value(Long(123))), UnnamedExpr(Function(Function { name:ObjectName([Identifier(Ident { value: "myfunc", quote_style: None })]), args: [Identifier("b")], filter: None, over: None, distinct: false }))], from: [TableWithJoins { relation: Table { name: ObjectName([Identifier(Ident { value: "table_1", quote_style: None })]), alias: None, args: [], with_hints: [] }, joins: [] }], selection: Some(BinaryOp { left: BinaryOp { left: Identifier("a"), op: Gt, right: Identifier("b") }, op: And, right: BinaryOp { left: Identifier("b"), op: Lt, right: Value(Long(100)) } }), group_by: [], having: None }), order_by: [OrderByExpr { expr: Identifier("a"), asc: Some(false) }, OrderByExpr { expr: Identifier("b"), asc: None }], limit: None, offset: None, fetch: None })]
|
AST: [Query(Query { ctes: [], body: Select(Select { distinct: false, projection: [UnnamedExpr(Identifier("a")), UnnamedExpr(Identifier("b")), UnnamedExpr(Value(Long(123))), UnnamedExpr(Function(Function { name: ObjectName(["myfunc"]), args: [Identifier("b")], filter: None, over: None, distinct: false }))], from: [TableWithJoins { relation: Table { name: ObjectName(["table_1"]), alias: None, args: [], with_hints: [] }, joins: [] }], selection: Some(BinaryOp { left: BinaryOp { left: Identifier("a"), op: Gt, right: Identifier("b") }, op: And, right: BinaryOp { left: Identifier("b"), op: Lt, right: Value(Long(100)) } }), group_by: [], having: None }), order_by: [OrderByExpr { expr: Identifier("a"), asc: Some(false) }, OrderByExpr { expr: Identifier("b"), asc: None }], limit: None, offset: None, fetch: None })]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +44,7 @@ The following optional [crate features](https://doc.rust-lang.org/cargo/referen
|
||||||
|
|
||||||
* `serde`: Adds [Serde](https://serde.rs/) support by implementing `Serialize` and `Deserialize` for all AST nodes.
|
* `serde`: Adds [Serde](https://serde.rs/) support by implementing `Serialize` and `Deserialize` for all AST nodes.
|
||||||
* `visitor`: Adds a `Visitor` capable of recursively walking the AST tree.
|
* `visitor`: Adds a `Visitor` capable of recursively walking the AST tree.
|
||||||
* `recursive-protection` (enabled by default), uses [recursive](https://docs.rs/recursive/latest/recursive/) for stack overflow protection.
|
|
||||||
|
|
||||||
## Syntax vs Semantics
|
## Syntax vs Semantics
|
||||||
|
|
||||||
|
@ -89,14 +70,10 @@ keywords, the following should hold true for all SQL:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Parse SQL
|
// Parse SQL
|
||||||
let sql = "SELECT 'hello'";
|
|
||||||
let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
|
let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
|
||||||
|
|
||||||
// The original SQL text can be generated from the AST
|
// The original SQL text can be generated from the AST
|
||||||
assert_eq!(ast[0].to_string(), sql);
|
assert_eq!(ast[0].to_string(), sql);
|
||||||
|
|
||||||
// The SQL can also be pretty-printed with newlines and indentation
|
|
||||||
assert_eq!(format!("{:#}", ast[0]), "SELECT\n 'hello'");
|
|
||||||
```
|
```
|
||||||
|
|
||||||
There are still some cases in this crate where different SQL with seemingly
|
There are still some cases in this crate where different SQL with seemingly
|
||||||
|
@ -104,37 +81,15 @@ similar semantics are represented with the same AST. We welcome PRs to fix such
|
||||||
issues and distinguish different syntaxes in the AST.
|
issues and distinguish different syntaxes in the AST.
|
||||||
|
|
||||||
|
|
||||||
## Source Locations (Work in Progress)
|
|
||||||
|
|
||||||
This crate allows recovering source locations from AST nodes via the [Spanned]
|
|
||||||
trait, which can be used for advanced diagnostics tooling. Note that this
|
|
||||||
feature is a work in progress and many nodes report missing or inaccurate spans.
|
|
||||||
Please see [this ticket] for information on how to contribute missing
|
|
||||||
improvements.
|
|
||||||
|
|
||||||
[Spanned]: https://docs.rs/sqlparser/latest/sqlparser/ast/trait.Spanned.html
|
|
||||||
[this ticket]: https://github.com/apache/datafusion-sqlparser-rs/issues/1548
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// Parse SQL
|
|
||||||
let ast = Parser::parse_sql(&GenericDialect, "SELECT A FROM B").unwrap();
|
|
||||||
|
|
||||||
// The source span can be retrieved with start and end locations
|
|
||||||
assert_eq!(ast[0].span(), Span {
|
|
||||||
start: Location::of(1, 1),
|
|
||||||
end: Location::of(1, 16),
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## SQL compliance
|
## SQL compliance
|
||||||
|
|
||||||
SQL was first standardized in 1987, and revisions of the standard have been
|
SQL was first standardized in 1987, and revisions of the standard have been
|
||||||
published regularly since. Most revisions have added significant new features to
|
published regularly since. Most revisions have added significant new features to
|
||||||
the language, and as a result no database claims to support the full breadth of
|
the language, and as a result no database claims to support the full breadth of
|
||||||
features. This parser currently supports most of the SQL-92 syntax, plus some
|
features. This parser currently supports most of the SQL-92 syntax, plus some
|
||||||
syntax from newer versions that have been explicitly requested, plus various
|
syntax from newer versions that have been explicitly requested, plus some MSSQL,
|
||||||
other dialect-specific syntax. Whenever possible, the [online SQL:2016
|
PostgreSQL, and other dialect-specific syntax. Whenever possible, the [online
|
||||||
grammar][sql-2016-grammar] is used to guide what syntax to accept.
|
SQL:2016 grammar][sql-2016-grammar] is used to guide what syntax to accept.
|
||||||
|
|
||||||
Unfortunately, stating anything more specific about compliance is difficult.
|
Unfortunately, stating anything more specific about compliance is difficult.
|
||||||
There is no publicly available test suite that can assess compliance
|
There is no publicly available test suite that can assess compliance
|
||||||
|
@ -160,8 +115,7 @@ $ cargo run --features json_example --example cli FILENAME.sql [--dialectname]
|
||||||
## Users
|
## Users
|
||||||
|
|
||||||
This parser is currently being used by the [DataFusion] query engine, [LocustDB],
|
This parser is currently being used by the [DataFusion] query engine, [LocustDB],
|
||||||
[Ballista], [GlueSQL], [Opteryx], [Polars], [PRQL], [Qrlew], [JumpWire], [ParadeDB], [CipherStash Proxy],
|
[Ballista], [GlueSQL], [Opteryx], [Polars], [PRQL], [Qrlew], [JumpWire], and [ParadeDB].
|
||||||
and [GreptimeDB].
|
|
||||||
|
|
||||||
If your project is using sqlparser-rs feel free to make a PR to add it
|
If your project is using sqlparser-rs feel free to make a PR to add it
|
||||||
to this list.
|
to this list.
|
||||||
|
@ -237,21 +191,6 @@ Our goal as maintainers is to facilitate the integration
|
||||||
of various features from various contributors, but not to provide the
|
of various features from various contributors, but not to provide the
|
||||||
implementations ourselves, as we simply don't have the resources.
|
implementations ourselves, as we simply don't have the resources.
|
||||||
|
|
||||||
### Benchmarking
|
|
||||||
|
|
||||||
There are several micro benchmarks in the `sqlparser_bench` directory.
|
|
||||||
You can run them with:
|
|
||||||
|
|
||||||
```
|
|
||||||
git checkout main
|
|
||||||
cd sqlparser_bench
|
|
||||||
cargo bench -- --save-baseline main
|
|
||||||
git checkout <your branch>
|
|
||||||
cargo bench -- --baseline main
|
|
||||||
```
|
|
||||||
|
|
||||||
By adding the `--save-baseline main` and `--baseline main` you can track the
|
|
||||||
progress of your improvements as you continue working on the feature branch.
|
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
|
@ -280,5 +219,3 @@ licensed as above, without any additional terms or conditions.
|
||||||
[sql-standard]: https://en.wikipedia.org/wiki/ISO/IEC_9075
|
[sql-standard]: https://en.wikipedia.org/wiki/ISO/IEC_9075
|
||||||
[`Dialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/trait.Dialect.html
|
[`Dialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/trait.Dialect.html
|
||||||
[`GenericDialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/struct.GenericDialect.html
|
[`GenericDialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/struct.GenericDialect.html
|
||||||
[CipherStash Proxy]: https://github.com/cipherstash/proxy
|
|
||||||
[GreptimeDB]: https://github.com/GreptimeTeam/greptimedb
|
|
||||||
|
|
19
SECURITY.md
19
SECURITY.md
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,104 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.52.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 45 commits from 20 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
**Implemented enhancements:**
|
|
||||||
|
|
||||||
- feat: support explain options [#1426](https://github.com/apache/datafusion-sqlparser-rs/pull/1426) (kysshsy)
|
|
||||||
- feat: adding Display implementation to DELETE and INSERT [#1427](https://github.com/apache/datafusion-sqlparser-rs/pull/1427) (seve-martinez)
|
|
||||||
|
|
||||||
**Fixed bugs:**
|
|
||||||
|
|
||||||
- fix: `maybe_parse` preventing parser from erroring on recursion limit [#1464](https://github.com/apache/datafusion-sqlparser-rs/pull/1464) (tomershaniii)
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- Fix parsing of negative values [#1419](https://github.com/apache/datafusion-sqlparser-rs/pull/1419) (agscpp)
|
|
||||||
- Allow to use ON CLUSTER cluster_name in TRUNCATE syntax [#1428](https://github.com/apache/datafusion-sqlparser-rs/pull/1428) (git-hulk)
|
|
||||||
- chore: remove redundant punctuation [#1434](https://github.com/apache/datafusion-sqlparser-rs/pull/1434) (Fischer0522)
|
|
||||||
- MS SQL Server: add support for IDENTITY column option [#1432](https://github.com/apache/datafusion-sqlparser-rs/pull/1432) (7phs)
|
|
||||||
- Update to ASF header / add when missing [#1437](https://github.com/apache/datafusion-sqlparser-rs/pull/1437) (alamb)
|
|
||||||
- Some small optimizations [#1424](https://github.com/apache/datafusion-sqlparser-rs/pull/1424) (exrok)
|
|
||||||
- Fix `codestyle` CI check [#1438](https://github.com/apache/datafusion-sqlparser-rs/pull/1438) (alamb)
|
|
||||||
- Implements CREATE POLICY syntax for PostgreSQL [#1440](https://github.com/apache/datafusion-sqlparser-rs/pull/1440) (git-hulk)
|
|
||||||
- make `parse_expr_with_alias` public [#1444](https://github.com/apache/datafusion-sqlparser-rs/pull/1444) (Eason0729)
|
|
||||||
- Implements DROP POLICY syntax for PostgreSQL [#1445](https://github.com/apache/datafusion-sqlparser-rs/pull/1445) (git-hulk)
|
|
||||||
- Support `DROP DATABASE` [#1443](https://github.com/apache/datafusion-sqlparser-rs/pull/1443) (linhr)
|
|
||||||
- Implements ALTER POLICY syntax for PostgreSQL [#1446](https://github.com/apache/datafusion-sqlparser-rs/pull/1446) (git-hulk)
|
|
||||||
- Add a note discouraging new use of `dialect_of` macro [#1448](https://github.com/apache/datafusion-sqlparser-rs/pull/1448) (alamb)
|
|
||||||
- Expand handling of `LIMIT 1, 2` handling to include sqlite [#1447](https://github.com/apache/datafusion-sqlparser-rs/pull/1447) (joshuawarner32)
|
|
||||||
- Fix always uses CommentDef::WithoutEq while parsing the inline comment [#1453](https://github.com/apache/datafusion-sqlparser-rs/pull/1453) (git-hulk)
|
|
||||||
- Add support for the LIKE ANY and ILIKE ANY pattern-matching condition [#1456](https://github.com/apache/datafusion-sqlparser-rs/pull/1456) (yoavcloud)
|
|
||||||
- added ability to parse extension to parse_comment inside postgres dialect [#1451](https://github.com/apache/datafusion-sqlparser-rs/pull/1451) (MaxwellKnight)
|
|
||||||
- Snowflake: support of views column comment [#1441](https://github.com/apache/datafusion-sqlparser-rs/pull/1441) (7phs)
|
|
||||||
- Add SQLite "ON CONFLICT" column option in CREATE TABLE statements [#1442](https://github.com/apache/datafusion-sqlparser-rs/pull/1442) (nucccc)
|
|
||||||
- Add support for ASC and DESC in CREATE TABLE column constraints for SQLite. [#1462](https://github.com/apache/datafusion-sqlparser-rs/pull/1462) (caldwell)
|
|
||||||
- Add support of `EXPLAIN QUERY PLAN` syntax for SQLite dialect [#1458](https://github.com/apache/datafusion-sqlparser-rs/pull/1458) (git-hulk)
|
|
||||||
- Add "DROP TYPE" support. [#1461](https://github.com/apache/datafusion-sqlparser-rs/pull/1461) (caldwell)
|
|
||||||
- chore: Add asf.yaml [#1463](https://github.com/apache/datafusion-sqlparser-rs/pull/1463) (Xuanwo)
|
|
||||||
- Add support for quantified comparison predicates (ALL/ANY/SOME) [#1459](https://github.com/apache/datafusion-sqlparser-rs/pull/1459) (yoavcloud)
|
|
||||||
- MySQL dialect: Add support for hash comments [#1466](https://github.com/apache/datafusion-sqlparser-rs/pull/1466) (hansott)
|
|
||||||
- Fix #1469 (SET ROLE regression) [#1474](https://github.com/apache/datafusion-sqlparser-rs/pull/1474) (lovasoa)
|
|
||||||
- Add support for parsing MsSql alias with equals [#1467](https://github.com/apache/datafusion-sqlparser-rs/pull/1467) (yoavcloud)
|
|
||||||
- Snowflake: support for extended column options in `CREATE TABLE` [#1454](https://github.com/apache/datafusion-sqlparser-rs/pull/1454) (7phs)
|
|
||||||
- MsSQL TRY_CONVERT [#1477](https://github.com/apache/datafusion-sqlparser-rs/pull/1477) (yoavcloud)
|
|
||||||
- Add PostgreSQL specfic "CREATE TYPE t AS ENUM (...)" support. [#1460](https://github.com/apache/datafusion-sqlparser-rs/pull/1460) (caldwell)
|
|
||||||
- Fix build [#1483](https://github.com/apache/datafusion-sqlparser-rs/pull/1483) (yoavcloud)
|
|
||||||
- Fix complex blocks warning when running clippy [#1488](https://github.com/apache/datafusion-sqlparser-rs/pull/1488) (git-hulk)
|
|
||||||
- Add support for SHOW DATABASES/SCHEMAS/TABLES/VIEWS in Hive [#1487](https://github.com/apache/datafusion-sqlparser-rs/pull/1487) (yoavcloud)
|
|
||||||
- Fix typo in `Dialect::supports_eq_alias_assigment` [#1478](https://github.com/apache/datafusion-sqlparser-rs/pull/1478) (alamb)
|
|
||||||
- Add support for PostgreSQL `LISTEN/NOTIFY` syntax [#1485](https://github.com/apache/datafusion-sqlparser-rs/pull/1485) (wugeer)
|
|
||||||
- Add support for TOP before ALL/DISTINCT [#1495](https://github.com/apache/datafusion-sqlparser-rs/pull/1495) (yoavcloud)
|
|
||||||
- add support for `FOR ORDINALITY` and `NESTED` in JSON_TABLE [#1493](https://github.com/apache/datafusion-sqlparser-rs/pull/1493) (lovasoa)
|
|
||||||
- Add Apache License to additional files [#1502](https://github.com/apache/datafusion-sqlparser-rs/pull/1502) (alamb)
|
|
||||||
- Move CHANGELOG content [#1503](https://github.com/apache/datafusion-sqlparser-rs/pull/1503) (alamb)
|
|
||||||
- improve support for T-SQL EXECUTE statements [#1490](https://github.com/apache/datafusion-sqlparser-rs/pull/1490) (lovasoa)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
8 Andrew Lamb
|
|
||||||
7 Yoav Cohen
|
|
||||||
7 hulk
|
|
||||||
3 Aleksei Piianin
|
|
||||||
3 David Caldwell
|
|
||||||
3 Ophir LOJKINE
|
|
||||||
1 Agaev Guseyn
|
|
||||||
1 Eason
|
|
||||||
1 Fischer
|
|
||||||
1 Hans Ott
|
|
||||||
1 Heran Lin
|
|
||||||
1 Joshua Warner
|
|
||||||
1 Maxwell Knight
|
|
||||||
1 Seve Martinez
|
|
||||||
1 Siyuan Huang
|
|
||||||
1 Thomas Dagenais
|
|
||||||
1 Xuanwo
|
|
||||||
1 nucccc
|
|
||||||
1 tomershaniii
|
|
||||||
1 wugeer
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.53.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 47 commits from 16 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- hive: support for special not expression `!a` and raise error for `a!` factorial operator [#1472](https://github.com/apache/datafusion-sqlparser-rs/pull/1472) (wugeer)
|
|
||||||
- Add support for MSSQL's `OPENJSON WITH` clause [#1498](https://github.com/apache/datafusion-sqlparser-rs/pull/1498) (gaoqiangz)
|
|
||||||
- Parse true and false as identifiers in mssql [#1510](https://github.com/apache/datafusion-sqlparser-rs/pull/1510) (lovasoa)
|
|
||||||
- Fix the parsing error in MSSQL for multiple statements that include `DECLARE` statements [#1497](https://github.com/apache/datafusion-sqlparser-rs/pull/1497) (wugeer)
|
|
||||||
- Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements [#1501](https://github.com/apache/datafusion-sqlparser-rs/pull/1501) (yoavcloud)
|
|
||||||
- Add support of COMMENT ON syntax for Snowflake [#1516](https://github.com/apache/datafusion-sqlparser-rs/pull/1516) (git-hulk)
|
|
||||||
- Add support for MYSQL's `CREATE TABLE SELECT` expr [#1515](https://github.com/apache/datafusion-sqlparser-rs/pull/1515) (wugeer)
|
|
||||||
- Add support for MSSQL's `XQuery` methods [#1500](https://github.com/apache/datafusion-sqlparser-rs/pull/1500) (gaoqiangz)
|
|
||||||
- Add support for Hive's `LOAD DATA` expr [#1520](https://github.com/apache/datafusion-sqlparser-rs/pull/1520) (wugeer)
|
|
||||||
- Fix ClickHouse document link from `Russian` to `English` [#1527](https://github.com/apache/datafusion-sqlparser-rs/pull/1527) (git-hulk)
|
|
||||||
- Support ANTI and SEMI joins without LEFT/RIGHT [#1528](https://github.com/apache/datafusion-sqlparser-rs/pull/1528) (delamarch3)
|
|
||||||
- support sqlite's OR clauses in update statements [#1530](https://github.com/apache/datafusion-sqlparser-rs/pull/1530) (lovasoa)
|
|
||||||
- support column type definitions in table aliases [#1526](https://github.com/apache/datafusion-sqlparser-rs/pull/1526) (lovasoa)
|
|
||||||
- Add support for MSSQL's `JSON_ARRAY`/`JSON_OBJECT` expr [#1507](https://github.com/apache/datafusion-sqlparser-rs/pull/1507) (gaoqiangz)
|
|
||||||
- Add support for PostgreSQL `UNLISTEN` syntax and Add support for Postgres `LOAD extension` expr [#1531](https://github.com/apache/datafusion-sqlparser-rs/pull/1531) (wugeer)
|
|
||||||
- Parse byte/bit string literals in MySQL and Postgres [#1532](https://github.com/apache/datafusion-sqlparser-rs/pull/1532) (mvzink)
|
|
||||||
- Allow example CLI to read from stdin [#1536](https://github.com/apache/datafusion-sqlparser-rs/pull/1536) (mvzink)
|
|
||||||
- recursive select calls are parsed with bad trailing_commas parameter [#1521](https://github.com/apache/datafusion-sqlparser-rs/pull/1521) (tomershaniii)
|
|
||||||
- PartiQL queries in Redshift [#1534](https://github.com/apache/datafusion-sqlparser-rs/pull/1534) (yoavcloud)
|
|
||||||
- Include license file in sqlparser_derive crate [#1543](https://github.com/apache/datafusion-sqlparser-rs/pull/1543) (ankane)
|
|
||||||
- Fallback to identifier parsing if expression parsing fails [#1513](https://github.com/apache/datafusion-sqlparser-rs/pull/1513) (yoavcloud)
|
|
||||||
- support `json_object('k':'v')` in postgres [#1546](https://github.com/apache/datafusion-sqlparser-rs/pull/1546) (lovasoa)
|
|
||||||
- Document micro benchmarks [#1555](https://github.com/apache/datafusion-sqlparser-rs/pull/1555) (alamb)
|
|
||||||
- Implement `Spanned` to retrieve source locations on AST nodes [#1435](https://github.com/apache/datafusion-sqlparser-rs/pull/1435) (Nyrox)
|
|
||||||
- Fix error in benchmark queries [#1560](https://github.com/apache/datafusion-sqlparser-rs/pull/1560) (alamb)
|
|
||||||
- Fix clippy warnings on rust 1.83 [#1570](https://github.com/apache/datafusion-sqlparser-rs/pull/1570) (iffyio)
|
|
||||||
- Support relation visitor to visit the `Option` field [#1556](https://github.com/apache/datafusion-sqlparser-rs/pull/1556) (goldmedal)
|
|
||||||
- Rename `TokenWithLocation` to `TokenWithSpan`, in backwards compatible way [#1562](https://github.com/apache/datafusion-sqlparser-rs/pull/1562) (alamb)
|
|
||||||
- Support MySQL size variants for BLOB and TEXT columns [#1564](https://github.com/apache/datafusion-sqlparser-rs/pull/1564) (mvzink)
|
|
||||||
- Increase version of sqlparser_derive from 0.2.2 to 0.3.0 [#1571](https://github.com/apache/datafusion-sqlparser-rs/pull/1571) (alamb)
|
|
||||||
- `json_object('k' VALUE 'v')` in postgres [#1547](https://github.com/apache/datafusion-sqlparser-rs/pull/1547) (lovasoa)
|
|
||||||
- Support snowflake double dot notation for object name [#1540](https://github.com/apache/datafusion-sqlparser-rs/pull/1540) (ayman-sigma)
|
|
||||||
- Update comments / docs for `Spanned` [#1549](https://github.com/apache/datafusion-sqlparser-rs/pull/1549) (alamb)
|
|
||||||
- Support Databricks struct literal [#1542](https://github.com/apache/datafusion-sqlparser-rs/pull/1542) (ayman-sigma)
|
|
||||||
- Encapsulate CreateFunction [#1573](https://github.com/apache/datafusion-sqlparser-rs/pull/1573) (philipcristiano)
|
|
||||||
- Support BIT column types [#1577](https://github.com/apache/datafusion-sqlparser-rs/pull/1577) (mvzink)
|
|
||||||
- Support parsing optional nulls handling for unique constraint [#1567](https://github.com/apache/datafusion-sqlparser-rs/pull/1567) (mvzink)
|
|
||||||
- Fix displaying WORK or TRANSACTION after BEGIN [#1565](https://github.com/apache/datafusion-sqlparser-rs/pull/1565) (mvzink)
|
|
||||||
- Add support of the ENUM8|ENUM16 for ClickHouse dialect [#1574](https://github.com/apache/datafusion-sqlparser-rs/pull/1574) (git-hulk)
|
|
||||||
- Parse Snowflake USE ROLE and USE SECONDARY ROLES [#1578](https://github.com/apache/datafusion-sqlparser-rs/pull/1578) (yoavcloud)
|
|
||||||
- Snowflake ALTER TABLE clustering options [#1579](https://github.com/apache/datafusion-sqlparser-rs/pull/1579) (yoavcloud)
|
|
||||||
- Support INSERT OVERWRITE INTO syntax [#1584](https://github.com/apache/datafusion-sqlparser-rs/pull/1584) (yuval-illumex)
|
|
||||||
- Parse `INSERT` with subquery when lacking column names [#1586](https://github.com/apache/datafusion-sqlparser-rs/pull/1586) (iffyio)
|
|
||||||
- Add support for ODBC functions [#1585](https://github.com/apache/datafusion-sqlparser-rs/pull/1585) (iffyio)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
8 Andrew Lamb
|
|
||||||
6 Michael Victor Zink
|
|
||||||
5 Ophir LOJKINE
|
|
||||||
5 Yoav Cohen
|
|
||||||
5 wugeer
|
|
||||||
3 Ifeanyi Ubah
|
|
||||||
3 gaoqiangz
|
|
||||||
3 hulk
|
|
||||||
2 Ayman Elkfrawy
|
|
||||||
1 Andrew Kane
|
|
||||||
1 Jax Liu
|
|
||||||
1 Mark-Oliver Junge
|
|
||||||
1 Philip Cristiano
|
|
||||||
1 Yuval Shkolar
|
|
||||||
1 delamarch3
|
|
||||||
1 tomershaniii
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.54.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 57 commits from 24 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
**Implemented enhancements:**
|
|
||||||
|
|
||||||
- feat: support `INSERT INTO [TABLE] FUNCTION` of Clickhouse [#1633](https://github.com/apache/datafusion-sqlparser-rs/pull/1633) (byte-sourcerer)
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- Run cargo fmt on `derive` crate [#1595](https://github.com/apache/datafusion-sqlparser-rs/pull/1595) (alamb)
|
|
||||||
- Add Apache license header to spans.rs [#1594](https://github.com/apache/datafusion-sqlparser-rs/pull/1594) (alamb)
|
|
||||||
- Add support for BigQuery `ANY TYPE` data type [#1602](https://github.com/apache/datafusion-sqlparser-rs/pull/1602) (MartinSahlen)
|
|
||||||
- Add support for TABLESAMPLE [#1580](https://github.com/apache/datafusion-sqlparser-rs/pull/1580) (yoavcloud)
|
|
||||||
- Redshift: Fix parsing for quoted numbered columns [#1576](https://github.com/apache/datafusion-sqlparser-rs/pull/1576) (7phs)
|
|
||||||
- Add the alter table ON COMMIT option to Snowflake [#1606](https://github.com/apache/datafusion-sqlparser-rs/pull/1606) (yoavcloud)
|
|
||||||
- Support parsing `EXPLAIN ESTIMATE` of Clickhouse [#1605](https://github.com/apache/datafusion-sqlparser-rs/pull/1605) (byte-sourcerer)
|
|
||||||
- Fix BigQuery hyphenated ObjectName with numbers [#1598](https://github.com/apache/datafusion-sqlparser-rs/pull/1598) (ayman-sigma)
|
|
||||||
- Fix test compilation issue [#1609](https://github.com/apache/datafusion-sqlparser-rs/pull/1609) (iffyio)
|
|
||||||
- Allow foreign table constraint without columns [#1608](https://github.com/apache/datafusion-sqlparser-rs/pull/1608) (ramnivas)
|
|
||||||
- Support optional table for `ANALYZE` statement [#1599](https://github.com/apache/datafusion-sqlparser-rs/pull/1599) (yuyang-ok)
|
|
||||||
- Support DOUBLE data types with precision for Mysql [#1611](https://github.com/apache/datafusion-sqlparser-rs/pull/1611) (artorias1024)
|
|
||||||
- Add `#[recursive]` [#1522](https://github.com/apache/datafusion-sqlparser-rs/pull/1522) (blaginin)
|
|
||||||
- Support arbitrary composite access expressions [#1600](https://github.com/apache/datafusion-sqlparser-rs/pull/1600) (ayman-sigma)
|
|
||||||
- Consolidate `MapAccess`, and `Subscript` into `CompoundExpr` to handle the complex field access chain [#1551](https://github.com/apache/datafusion-sqlparser-rs/pull/1551) (goldmedal)
|
|
||||||
- Handle empty projection in Postgres SELECT statements [#1613](https://github.com/apache/datafusion-sqlparser-rs/pull/1613) (tobyhede)
|
|
||||||
- Merge composite and compound expr test cases [#1615](https://github.com/apache/datafusion-sqlparser-rs/pull/1615) (iffyio)
|
|
||||||
- Support Snowflake Update-From-Select [#1604](https://github.com/apache/datafusion-sqlparser-rs/pull/1604) (yuval-illumex)
|
|
||||||
- Improve parsing performance by reducing token cloning [#1587](https://github.com/apache/datafusion-sqlparser-rs/pull/1587) (davisp)
|
|
||||||
- Improve Parser documentation [#1617](https://github.com/apache/datafusion-sqlparser-rs/pull/1617) (alamb)
|
|
||||||
- Add support for DROP EXTENSION [#1610](https://github.com/apache/datafusion-sqlparser-rs/pull/1610) (ramnivas)
|
|
||||||
- Refactor advancing token to avoid duplication, avoid borrow checker issues [#1618](https://github.com/apache/datafusion-sqlparser-rs/pull/1618) (alamb)
|
|
||||||
- Fix the parsing result for the special double number [#1621](https://github.com/apache/datafusion-sqlparser-rs/pull/1621) (goldmedal)
|
|
||||||
- SQLite: Allow dollar signs in placeholder names [#1620](https://github.com/apache/datafusion-sqlparser-rs/pull/1620) (hansott)
|
|
||||||
- Improve error for an unexpected token after DROP [#1623](https://github.com/apache/datafusion-sqlparser-rs/pull/1623) (ramnivas)
|
|
||||||
- Fix `sqlparser_bench` benchmark compilation [#1625](https://github.com/apache/datafusion-sqlparser-rs/pull/1625) (alamb)
|
|
||||||
- Improve parsing speed by avoiding some clones in parse_identifier [#1624](https://github.com/apache/datafusion-sqlparser-rs/pull/1624) (alamb)
|
|
||||||
- Simplify `parse_keyword_apis` more [#1626](https://github.com/apache/datafusion-sqlparser-rs/pull/1626) (alamb)
|
|
||||||
- Test benchmarks and Improve benchmark README.md [#1627](https://github.com/apache/datafusion-sqlparser-rs/pull/1627) (alamb)
|
|
||||||
- Add support for MYSQL's `RENAME TABLE` [#1616](https://github.com/apache/datafusion-sqlparser-rs/pull/1616) (wugeer)
|
|
||||||
- Correctly tokenize nested comments [#1629](https://github.com/apache/datafusion-sqlparser-rs/pull/1629) (hansott)
|
|
||||||
- Add support for USE SECONDARY ROLE (vs. ROLES) [#1637](https://github.com/apache/datafusion-sqlparser-rs/pull/1637) (yoavcloud)
|
|
||||||
- Add support for various Snowflake grantees [#1640](https://github.com/apache/datafusion-sqlparser-rs/pull/1640) (yoavcloud)
|
|
||||||
- Add support for the SQL OVERLAPS predicate [#1638](https://github.com/apache/datafusion-sqlparser-rs/pull/1638) (yoavcloud)
|
|
||||||
- Add support for Snowflake LIST and REMOVE [#1639](https://github.com/apache/datafusion-sqlparser-rs/pull/1639) (yoavcloud)
|
|
||||||
- Add support for MySQL's INSERT INTO ... SET syntax [#1641](https://github.com/apache/datafusion-sqlparser-rs/pull/1641) (yoavcloud)
|
|
||||||
- Start new line if \r in Postgres dialect [#1647](https://github.com/apache/datafusion-sqlparser-rs/pull/1647) (hansott)
|
|
||||||
- Support pluralized time units [#1630](https://github.com/apache/datafusion-sqlparser-rs/pull/1630) (wugeer)
|
|
||||||
- Replace `ReferentialAction` enum in `DROP` statements [#1648](https://github.com/apache/datafusion-sqlparser-rs/pull/1648) (stepancheg)
|
|
||||||
- Add support for MS-SQL BEGIN/END TRY/CATCH [#1649](https://github.com/apache/datafusion-sqlparser-rs/pull/1649) (yoavcloud)
|
|
||||||
- Fix MySQL parsing of GRANT, REVOKE, and CREATE VIEW [#1538](https://github.com/apache/datafusion-sqlparser-rs/pull/1538) (mvzink)
|
|
||||||
- Add support for the Snowflake MINUS set operator [#1652](https://github.com/apache/datafusion-sqlparser-rs/pull/1652) (yoavcloud)
|
|
||||||
- ALTER TABLE DROP {COLUMN|CONSTRAINT} RESTRICT [#1651](https://github.com/apache/datafusion-sqlparser-rs/pull/1651) (stepancheg)
|
|
||||||
- Add support for ClickHouse `FORMAT` on `INSERT` [#1628](https://github.com/apache/datafusion-sqlparser-rs/pull/1628) (bombsimon)
|
|
||||||
- MsSQL SET for session params [#1646](https://github.com/apache/datafusion-sqlparser-rs/pull/1646) (yoavcloud)
|
|
||||||
- Correctly look for end delimiter dollar quoted string [#1650](https://github.com/apache/datafusion-sqlparser-rs/pull/1650) (hansott)
|
|
||||||
- Support single line comments starting with '#' for Hive [#1654](https://github.com/apache/datafusion-sqlparser-rs/pull/1654) (wugeer)
|
|
||||||
- Support trailing commas in `FROM` clause [#1645](https://github.com/apache/datafusion-sqlparser-rs/pull/1645) (barsela1)
|
|
||||||
- Allow empty options for BigQuery [#1657](https://github.com/apache/datafusion-sqlparser-rs/pull/1657) (MartinSahlen)
|
|
||||||
- Add support for parsing RAISERROR [#1656](https://github.com/apache/datafusion-sqlparser-rs/pull/1656) (AvivDavid-Satori)
|
|
||||||
- Add support for Snowflake column aliases that use SQL keywords [#1632](https://github.com/apache/datafusion-sqlparser-rs/pull/1632) (yoavcloud)
|
|
||||||
- fix parsing of `INSERT INTO ... SELECT ... RETURNING ` [#1661](https://github.com/apache/datafusion-sqlparser-rs/pull/1661) (lovasoa)
|
|
||||||
- Add support for `IS [NOT] [form] NORMALIZED` [#1655](https://github.com/apache/datafusion-sqlparser-rs/pull/1655) (alexander-beedie)
|
|
||||||
- Add support for qualified column names in JOIN ... USING [#1663](https://github.com/apache/datafusion-sqlparser-rs/pull/1663) (yoavcloud)
|
|
||||||
- Add support for Snowflake AT/BEFORE [#1667](https://github.com/apache/datafusion-sqlparser-rs/pull/1667) (yoavcloud)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
13 Yoav Cohen
|
|
||||||
9 Andrew Lamb
|
|
||||||
4 Hans Ott
|
|
||||||
3 Ramnivas Laddad
|
|
||||||
3 wugeer
|
|
||||||
2 Ayman Elkfrawy
|
|
||||||
2 Ifeanyi Ubah
|
|
||||||
2 Jax Liu
|
|
||||||
2 Martin Abelson Sahlen
|
|
||||||
2 Stepan Koltsov
|
|
||||||
2 cjw
|
|
||||||
1 Aleksei Piianin
|
|
||||||
1 Alexander Beedie
|
|
||||||
1 AvivDavid-Satori
|
|
||||||
1 Dmitrii Blaginin
|
|
||||||
1 Michael Victor Zink
|
|
||||||
1 Ophir LOJKINE
|
|
||||||
1 Paul J. Davis
|
|
||||||
1 Simon Sawert
|
|
||||||
1 Toby Hede
|
|
||||||
1 Yuval Shkolar
|
|
||||||
1 artorias1024
|
|
||||||
1 bar sela
|
|
||||||
1 yuyang
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.55.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 55 commits from 25 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
## Migrating usages of `Expr::Value`
|
|
||||||
|
|
||||||
In v0.55 of sqlparser the `Expr::Value` enum variant contains a `ValueWithSpan` instead of a `Value`. Here is how to migrate.
|
|
||||||
|
|
||||||
### When pattern matching
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- Expr::Value(Value::SingleQuotedString(my_string)) => { ... }
|
|
||||||
+ Expr::Value(ValueWithSpan{ value: Value::SingleQuotedString(my_string), span: _ }) => { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
### When creating an `Expr`
|
|
||||||
|
|
||||||
Use the new `Expr::value` method (notice the lowercase `v`), which will create a `ValueWithSpan` containing an empty span:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- Expr::Value(Value::SingleQuotedString(my_string))
|
|
||||||
+ Expr::value(Value::SingleQuotedString(my_string))
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migrating usages of `ObjectName`
|
|
||||||
|
|
||||||
In v0.55 of sqlparser, the `ObjectName` structure has been changed as shown below. Here is now to migrate.
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- pub struct ObjectName(pub Vec<Ident>);
|
|
||||||
+ pub struct ObjectName(pub Vec<ObjectNamePart>)
|
|
||||||
```
|
|
||||||
|
|
||||||
### When constructing `ObjectName`
|
|
||||||
|
|
||||||
Use the `From` impl:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- name: ObjectName(vec![Ident::new("f")]),
|
|
||||||
+ name: ObjectName::from(vec![Ident::new("f")]),
|
|
||||||
```
|
|
||||||
|
|
||||||
### Accessing Spans
|
|
||||||
|
|
||||||
Use the `span()` function
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- name.span
|
|
||||||
+ name.span()
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Breaking changes:**
|
|
||||||
|
|
||||||
- Enhance object name path segments [#1539](https://github.com/apache/datafusion-sqlparser-rs/pull/1539) (ayman-sigma)
|
|
||||||
- Store spans for Value expressions [#1738](https://github.com/apache/datafusion-sqlparser-rs/pull/1738) (lovasoa)
|
|
||||||
|
|
||||||
**Implemented enhancements:**
|
|
||||||
|
|
||||||
- feat: adjust create and drop trigger for mysql dialect [#1734](https://github.com/apache/datafusion-sqlparser-rs/pull/1734) (invm)
|
|
||||||
|
|
||||||
**Fixed bugs:**
|
|
||||||
|
|
||||||
- fix: make `serde` feature no_std [#1730](https://github.com/apache/datafusion-sqlparser-rs/pull/1730) (iajoiner)
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- Update rat_exclude_file.txt [#1670](https://github.com/apache/datafusion-sqlparser-rs/pull/1670) (alamb)
|
|
||||||
- Add support for Snowflake account privileges [#1666](https://github.com/apache/datafusion-sqlparser-rs/pull/1666) (yoavcloud)
|
|
||||||
- Add support for Create Iceberg Table statement for Snowflake parser [#1664](https://github.com/apache/datafusion-sqlparser-rs/pull/1664) (Vedin)
|
|
||||||
- National strings: check if dialect supports backslash escape [#1672](https://github.com/apache/datafusion-sqlparser-rs/pull/1672) (hansott)
|
|
||||||
- Only support escape literals for Postgres, Redshift and generic dialect [#1674](https://github.com/apache/datafusion-sqlparser-rs/pull/1674) (hansott)
|
|
||||||
- BigQuery: Support trailing commas in column definitions list [#1682](https://github.com/apache/datafusion-sqlparser-rs/pull/1682) (iffyio)
|
|
||||||
- Enable GROUP BY exp for Snowflake dialect [#1683](https://github.com/apache/datafusion-sqlparser-rs/pull/1683) (yoavcloud)
|
|
||||||
- Add support for parsing empty dictionary expressions [#1684](https://github.com/apache/datafusion-sqlparser-rs/pull/1684) (yoavcloud)
|
|
||||||
- Support multiple tables in `UPDATE FROM` clause [#1681](https://github.com/apache/datafusion-sqlparser-rs/pull/1681) (iffyio)
|
|
||||||
- Add support for mysql table hints [#1675](https://github.com/apache/datafusion-sqlparser-rs/pull/1675) (AvivDavid-Satori)
|
|
||||||
- BigQuery: Add support for select expr star [#1680](https://github.com/apache/datafusion-sqlparser-rs/pull/1680) (iffyio)
|
|
||||||
- Support underscore separators in numbers for Clickhouse. Fixes #1659 [#1677](https://github.com/apache/datafusion-sqlparser-rs/pull/1677) (graup)
|
|
||||||
- BigQuery: Fix column identifier reserved keywords list [#1678](https://github.com/apache/datafusion-sqlparser-rs/pull/1678) (iffyio)
|
|
||||||
- Fix bug when parsing a Snowflake stage with `;` suffix [#1688](https://github.com/apache/datafusion-sqlparser-rs/pull/1688) (yoavcloud)
|
|
||||||
- Allow plain JOIN without turning it into INNER [#1692](https://github.com/apache/datafusion-sqlparser-rs/pull/1692) (mvzink)
|
|
||||||
- Fix DDL generation in case of an empty arguments function. [#1690](https://github.com/apache/datafusion-sqlparser-rs/pull/1690) (remysaissy)
|
|
||||||
- Fix `CREATE FUNCTION` round trip for Hive dialect [#1693](https://github.com/apache/datafusion-sqlparser-rs/pull/1693) (iffyio)
|
|
||||||
- Make numeric literal underscore test dialect agnostic [#1685](https://github.com/apache/datafusion-sqlparser-rs/pull/1685) (iffyio)
|
|
||||||
- Extend lambda support for ClickHouse and DuckDB dialects [#1686](https://github.com/apache/datafusion-sqlparser-rs/pull/1686) (gstvg)
|
|
||||||
- Make TypedString preserve quote style [#1679](https://github.com/apache/datafusion-sqlparser-rs/pull/1679) (graup)
|
|
||||||
- Do not parse ASOF and MATCH_CONDITION as table factor aliases [#1698](https://github.com/apache/datafusion-sqlparser-rs/pull/1698) (yoavcloud)
|
|
||||||
- Add support for GRANT on some common Snowflake objects [#1699](https://github.com/apache/datafusion-sqlparser-rs/pull/1699) (yoavcloud)
|
|
||||||
- Add RETURNS TABLE() support for CREATE FUNCTION in Postgresql [#1687](https://github.com/apache/datafusion-sqlparser-rs/pull/1687) (remysaissy)
|
|
||||||
- Add parsing for GRANT ROLE and GRANT DATABASE ROLE in Snowflake dialect [#1689](https://github.com/apache/datafusion-sqlparser-rs/pull/1689) (yoavcloud)
|
|
||||||
- Add support for `CREATE/ALTER/DROP CONNECTOR` syntax [#1701](https://github.com/apache/datafusion-sqlparser-rs/pull/1701) (wugeer)
|
|
||||||
- Parse Snowflake COPY INTO <location> [#1669](https://github.com/apache/datafusion-sqlparser-rs/pull/1669) (yoavcloud)
|
|
||||||
- Require space after -- to start single line comment in MySQL [#1705](https://github.com/apache/datafusion-sqlparser-rs/pull/1705) (hansott)
|
|
||||||
- Add suppport for Show Objects statement for the Snowflake parser [#1702](https://github.com/apache/datafusion-sqlparser-rs/pull/1702) (DanCodedThis)
|
|
||||||
- Fix incorrect parsing of JsonAccess bracket notation after cast in Snowflake [#1708](https://github.com/apache/datafusion-sqlparser-rs/pull/1708) (yoavcloud)
|
|
||||||
- Parse Postgres VARBIT datatype [#1703](https://github.com/apache/datafusion-sqlparser-rs/pull/1703) (mvzink)
|
|
||||||
- Implement FROM-first selects [#1713](https://github.com/apache/datafusion-sqlparser-rs/pull/1713) (mitsuhiko)
|
|
||||||
- Enable custom dialects to support `MATCH() AGAINST()` [#1719](https://github.com/apache/datafusion-sqlparser-rs/pull/1719) (joocer)
|
|
||||||
- Support group by cube/rollup etc in BigQuery [#1720](https://github.com/apache/datafusion-sqlparser-rs/pull/1720) (Groennbeck)
|
|
||||||
- Add support for MS Varbinary(MAX) (#1714) [#1715](https://github.com/apache/datafusion-sqlparser-rs/pull/1715) (TylerBrinks)
|
|
||||||
- Add supports for Hive's `SELECT ... GROUP BY .. GROUPING SETS` syntax [#1653](https://github.com/apache/datafusion-sqlparser-rs/pull/1653) (wugeer)
|
|
||||||
- Differentiate LEFT JOIN from LEFT OUTER JOIN [#1726](https://github.com/apache/datafusion-sqlparser-rs/pull/1726) (mvzink)
|
|
||||||
- Add support for Postgres `ALTER TYPE` [#1727](https://github.com/apache/datafusion-sqlparser-rs/pull/1727) (jvatic)
|
|
||||||
- Replace `Method` and `CompositeAccess` with `CompoundFieldAccess` [#1716](https://github.com/apache/datafusion-sqlparser-rs/pull/1716) (iffyio)
|
|
||||||
- Add support for `EXECUTE IMMEDIATE` [#1717](https://github.com/apache/datafusion-sqlparser-rs/pull/1717) (iffyio)
|
|
||||||
- Treat COLLATE like any other column option [#1731](https://github.com/apache/datafusion-sqlparser-rs/pull/1731) (mvzink)
|
|
||||||
- Add support for PostgreSQL/Redshift geometric operators [#1723](https://github.com/apache/datafusion-sqlparser-rs/pull/1723) (benrsatori)
|
|
||||||
- Implement SnowFlake ALTER SESSION [#1712](https://github.com/apache/datafusion-sqlparser-rs/pull/1712) (osipovartem)
|
|
||||||
- Extend Visitor trait for Value type [#1725](https://github.com/apache/datafusion-sqlparser-rs/pull/1725) (tomershaniii)
|
|
||||||
- Add support for `ORDER BY ALL` [#1724](https://github.com/apache/datafusion-sqlparser-rs/pull/1724) (PokIsemaine)
|
|
||||||
- Parse casting to array using double colon operator in Redshift [#1737](https://github.com/apache/datafusion-sqlparser-rs/pull/1737) (yoavcloud)
|
|
||||||
- Replace parallel condition/result vectors with single CaseWhen vector in Expr::Case. This fixes the iteration order when using the `Visitor` trait. Expressions are now visited in the same order as they appear in the sql source. [#1733](https://github.com/apache/datafusion-sqlparser-rs/pull/1733) (lovasoa)
|
|
||||||
- BigQuery: Add support for `BEGIN` [#1718](https://github.com/apache/datafusion-sqlparser-rs/pull/1718) (iffyio)
|
|
||||||
- Parse SIGNED INTEGER type in MySQL CAST [#1739](https://github.com/apache/datafusion-sqlparser-rs/pull/1739) (mvzink)
|
|
||||||
- Parse MySQL ALTER TABLE ALGORITHM option [#1745](https://github.com/apache/datafusion-sqlparser-rs/pull/1745) (mvzink)
|
|
||||||
- Random test cleanups use Expr::value [#1749](https://github.com/apache/datafusion-sqlparser-rs/pull/1749) (alamb)
|
|
||||||
- Parse ALTER TABLE AUTO_INCREMENT operation for MySQL [#1748](https://github.com/apache/datafusion-sqlparser-rs/pull/1748) (mvzink)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
10 Yoav Cohen
|
|
||||||
9 Ifeanyi Ubah
|
|
||||||
7 Michael Victor Zink
|
|
||||||
3 Hans Ott
|
|
||||||
2 Andrew Lamb
|
|
||||||
2 Ophir LOJKINE
|
|
||||||
2 Paul Grau
|
|
||||||
2 Rémy SAISSY
|
|
||||||
2 wugeer
|
|
||||||
1 Armin Ronacher
|
|
||||||
1 Artem Osipov
|
|
||||||
1 AvivDavid-Satori
|
|
||||||
1 Ayman Elkfrawy
|
|
||||||
1 DanCodedThis
|
|
||||||
1 Denys Tsomenko
|
|
||||||
1 Emil
|
|
||||||
1 Ian Alexander Joiner
|
|
||||||
1 Jesse Stuart
|
|
||||||
1 Justin Joyce
|
|
||||||
1 Michael
|
|
||||||
1 SiLe Zhou
|
|
||||||
1 Tyler Brinks
|
|
||||||
1 benrsatori
|
|
||||||
1 gstvg
|
|
||||||
1 tomershaniii
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.56.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 48 commits from 19 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- Ignore escaped LIKE wildcards in MySQL [#1735](https://github.com/apache/datafusion-sqlparser-rs/pull/1735) (mvzink)
|
|
||||||
- Parse SET NAMES syntax in Postgres [#1752](https://github.com/apache/datafusion-sqlparser-rs/pull/1752) (mvzink)
|
|
||||||
- re-add support for nested comments in mssql [#1754](https://github.com/apache/datafusion-sqlparser-rs/pull/1754) (lovasoa)
|
|
||||||
- Extend support for INDEX parsing [#1707](https://github.com/apache/datafusion-sqlparser-rs/pull/1707) (LucaCappelletti94)
|
|
||||||
- Parse MySQL `ALTER TABLE DROP FOREIGN KEY` syntax [#1762](https://github.com/apache/datafusion-sqlparser-rs/pull/1762) (mvzink)
|
|
||||||
- add support for `with` clauses (CTEs) in `delete` statements [#1764](https://github.com/apache/datafusion-sqlparser-rs/pull/1764) (lovasoa)
|
|
||||||
- SET with a list of comma separated assignments [#1757](https://github.com/apache/datafusion-sqlparser-rs/pull/1757) (MohamedAbdeen21)
|
|
||||||
- Preserve MySQL-style `LIMIT <offset>, <limit>` syntax [#1765](https://github.com/apache/datafusion-sqlparser-rs/pull/1765) (mvzink)
|
|
||||||
- Add support for `DROP MATERIALIZED VIEW` [#1743](https://github.com/apache/datafusion-sqlparser-rs/pull/1743) (iffyio)
|
|
||||||
- Add `CASE` and `IF` statement support [#1741](https://github.com/apache/datafusion-sqlparser-rs/pull/1741) (iffyio)
|
|
||||||
- BigQuery: Add support for `CREATE SCHEMA` options [#1742](https://github.com/apache/datafusion-sqlparser-rs/pull/1742) (iffyio)
|
|
||||||
- Snowflake: Support dollar quoted comments [#1755](https://github.com/apache/datafusion-sqlparser-rs/pull/1755)
|
|
||||||
- Add LOCK operation for ALTER TABLE [#1768](https://github.com/apache/datafusion-sqlparser-rs/pull/1768) (MohamedAbdeen21)
|
|
||||||
- Add support for `RAISE` statement [#1766](https://github.com/apache/datafusion-sqlparser-rs/pull/1766) (iffyio)
|
|
||||||
- Add GLOBAL context/modifier to SET statements [#1767](https://github.com/apache/datafusion-sqlparser-rs/pull/1767) (MohamedAbdeen21)
|
|
||||||
- Parse `SUBSTR` as alias for `SUBSTRING` [#1769](https://github.com/apache/datafusion-sqlparser-rs/pull/1769) (mvzink)
|
|
||||||
- SET statements: scope modifier for multiple assignments [#1772](https://github.com/apache/datafusion-sqlparser-rs/pull/1772) (MohamedAbdeen21)
|
|
||||||
- Support qualified column names in `MATCH AGAINST` clause [#1774](https://github.com/apache/datafusion-sqlparser-rs/pull/1774) (tomershaniii)
|
|
||||||
- Mysql: Add support for := operator [#1779](https://github.com/apache/datafusion-sqlparser-rs/pull/1779) (barsela1)
|
|
||||||
- Add cipherstash-proxy to list of users in README.md [#1782](https://github.com/apache/datafusion-sqlparser-rs/pull/1782) (coderdan)
|
|
||||||
- Fix typos [#1785](https://github.com/apache/datafusion-sqlparser-rs/pull/1785) (jayvdb)
|
|
||||||
- Add support for Databricks TIMESTAMP_NTZ. [#1781](https://github.com/apache/datafusion-sqlparser-rs/pull/1781) (romanb)
|
|
||||||
- Enable double-dot-notation for mssql. [#1787](https://github.com/apache/datafusion-sqlparser-rs/pull/1787) (romanb)
|
|
||||||
- Fix: Snowflake ALTER SESSION cannot be followed by other statements. [#1786](https://github.com/apache/datafusion-sqlparser-rs/pull/1786) (romanb)
|
|
||||||
- Add GreptimeDB to the "Users" in README [#1788](https://github.com/apache/datafusion-sqlparser-rs/pull/1788) (MichaelScofield)
|
|
||||||
- Extend snowflake grant options support [#1794](https://github.com/apache/datafusion-sqlparser-rs/pull/1794) (yoavcloud)
|
|
||||||
- Fix clippy lint on rust 1.86 [#1796](https://github.com/apache/datafusion-sqlparser-rs/pull/1796) (iffyio)
|
|
||||||
- Allow single quotes in EXTRACT() for Redshift. [#1795](https://github.com/apache/datafusion-sqlparser-rs/pull/1795) (romanb)
|
|
||||||
- MSSQL: Add support for functionality `MERGE` output clause [#1790](https://github.com/apache/datafusion-sqlparser-rs/pull/1790) (dilovancelik)
|
|
||||||
- Support additional DuckDB integer types such as HUGEINT, UHUGEINT, etc [#1797](https://github.com/apache/datafusion-sqlparser-rs/pull/1797) (alexander-beedie)
|
|
||||||
- Add support for MSSQL IF/ELSE statements. [#1791](https://github.com/apache/datafusion-sqlparser-rs/pull/1791) (romanb)
|
|
||||||
- Allow literal backslash escapes for string literals in Redshift dialect. [#1801](https://github.com/apache/datafusion-sqlparser-rs/pull/1801) (romanb)
|
|
||||||
- Add support for MySQL's STRAIGHT_JOIN join operator. [#1802](https://github.com/apache/datafusion-sqlparser-rs/pull/1802) (romanb)
|
|
||||||
- Snowflake COPY INTO target columns, select items and optional alias [#1805](https://github.com/apache/datafusion-sqlparser-rs/pull/1805) (yoavcloud)
|
|
||||||
- Fix tokenization of qualified identifiers with numeric prefix. [#1803](https://github.com/apache/datafusion-sqlparser-rs/pull/1803) (romanb)
|
|
||||||
- Add support for `INHERITS` option in `CREATE TABLE` statement [#1806](https://github.com/apache/datafusion-sqlparser-rs/pull/1806) (LucaCappelletti94)
|
|
||||||
- Add `DROP TRIGGER` support for SQL Server [#1813](https://github.com/apache/datafusion-sqlparser-rs/pull/1813) (aharpervc)
|
|
||||||
- Snowflake: support nested join without parentheses [#1799](https://github.com/apache/datafusion-sqlparser-rs/pull/1799) (barsela1)
|
|
||||||
- Add support for parenthesized subquery as `IN` predicate [#1793](https://github.com/apache/datafusion-sqlparser-rs/pull/1793) (adamchainz)
|
|
||||||
- Fix `STRAIGHT_JOIN` constraint when table alias is absent [#1812](https://github.com/apache/datafusion-sqlparser-rs/pull/1812) (killertux)
|
|
||||||
- Add support for `PRINT` statement for SQL Server [#1811](https://github.com/apache/datafusion-sqlparser-rs/pull/1811) (aharpervc)
|
|
||||||
- enable `supports_filter_during_aggregation` for Generic dialect [#1815](https://github.com/apache/datafusion-sqlparser-rs/pull/1815) (goldmedal)
|
|
||||||
- Add support for `XMLTABLE` [#1817](https://github.com/apache/datafusion-sqlparser-rs/pull/1817) (lovasoa)
|
|
||||||
- Add `CREATE FUNCTION` support for SQL Server [#1808](https://github.com/apache/datafusion-sqlparser-rs/pull/1808) (aharpervc)
|
|
||||||
- Add `OR ALTER` support for `CREATE VIEW` [#1818](https://github.com/apache/datafusion-sqlparser-rs/pull/1818) (aharpervc)
|
|
||||||
- Add `DECLARE ... CURSOR FOR` support for SQL Server [#1821](https://github.com/apache/datafusion-sqlparser-rs/pull/1821) (aharpervc)
|
|
||||||
- Handle missing login in changelog generate script [#1823](https://github.com/apache/datafusion-sqlparser-rs/pull/1823) (iffyio)
|
|
||||||
- Snowflake: Add support for `CONNECT_BY_ROOT` [#1780](https://github.com/apache/datafusion-sqlparser-rs/pull/1780) (tomershaniii)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
8 Roman Borschel
|
|
||||||
6 Ifeanyi Ubah
|
|
||||||
5 Andrew Harper
|
|
||||||
5 Michael Victor Zink
|
|
||||||
4 Mohamed Abdeen
|
|
||||||
3 Ophir LOJKINE
|
|
||||||
2 Luca Cappelletti
|
|
||||||
2 Yoav Cohen
|
|
||||||
2 bar sela
|
|
||||||
2 tomershaniii
|
|
||||||
1 Adam Johnson
|
|
||||||
1 Aleksei Piianin
|
|
||||||
1 Alexander Beedie
|
|
||||||
1 Bruno Clemente
|
|
||||||
1 Dan Draper
|
|
||||||
1 DilovanCelik
|
|
||||||
1 Jax Liu
|
|
||||||
1 John Vandenberg
|
|
||||||
1 LFC
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# sqlparser-rs 0.57.0 Changelog
|
|
||||||
|
|
||||||
This release consists of 39 commits from 19 contributors. See credits at the end of this changelog for more information.
|
|
||||||
|
|
||||||
**Implemented enhancements:**
|
|
||||||
|
|
||||||
- feat: Hive: support `SORT BY` direction [#1873](https://github.com/apache/datafusion-sqlparser-rs/pull/1873) (chenkovsky)
|
|
||||||
|
|
||||||
**Other:**
|
|
||||||
|
|
||||||
- Support some of pipe operators [#1759](https://github.com/apache/datafusion-sqlparser-rs/pull/1759) (simonvandel)
|
|
||||||
- Added support for `DROP DOMAIN` [#1828](https://github.com/apache/datafusion-sqlparser-rs/pull/1828) (LucaCappelletti94)
|
|
||||||
- Improve support for cursors for SQL Server [#1831](https://github.com/apache/datafusion-sqlparser-rs/pull/1831) (aharpervc)
|
|
||||||
- Add all missing table options to be handled in any order [#1747](https://github.com/apache/datafusion-sqlparser-rs/pull/1747) (benrsatori)
|
|
||||||
- Add `CREATE TRIGGER` support for SQL Server [#1810](https://github.com/apache/datafusion-sqlparser-rs/pull/1810) (aharpervc)
|
|
||||||
- Added support for `CREATE DOMAIN` [#1830](https://github.com/apache/datafusion-sqlparser-rs/pull/1830) (LucaCappelletti94)
|
|
||||||
- Allow stored procedures to be defined without `BEGIN`/`END` [#1834](https://github.com/apache/datafusion-sqlparser-rs/pull/1834) (aharpervc)
|
|
||||||
- Add support for the MATCH and REGEXP binary operators [#1840](https://github.com/apache/datafusion-sqlparser-rs/pull/1840) (lovasoa)
|
|
||||||
- Fix: parsing ident starting with underscore in certain dialects [#1835](https://github.com/apache/datafusion-sqlparser-rs/pull/1835) (MohamedAbdeen21)
|
|
||||||
- implement pretty-printing with `{:#}` [#1847](https://github.com/apache/datafusion-sqlparser-rs/pull/1847) (lovasoa)
|
|
||||||
- Fix big performance issue in string serialization [#1848](https://github.com/apache/datafusion-sqlparser-rs/pull/1848) (lovasoa)
|
|
||||||
- Add support for `DENY` statements [#1836](https://github.com/apache/datafusion-sqlparser-rs/pull/1836) (aharpervc)
|
|
||||||
- Postgresql: Add `REPLICA IDENTITY` operation for `ALTER TABLE` [#1844](https://github.com/apache/datafusion-sqlparser-rs/pull/1844) (MohamedAbdeen21)
|
|
||||||
- Add support for INCLUDE/EXCLUDE NULLS for UNPIVOT [#1849](https://github.com/apache/datafusion-sqlparser-rs/pull/1849) (Vedin)
|
|
||||||
- pretty print improvements [#1851](https://github.com/apache/datafusion-sqlparser-rs/pull/1851) (lovasoa)
|
|
||||||
- fix new rust 1.87 cargo clippy warnings [#1856](https://github.com/apache/datafusion-sqlparser-rs/pull/1856) (lovasoa)
|
|
||||||
- Update criterion requirement from 0.5 to 0.6 in /sqlparser_bench [#1857](https://github.com/apache/datafusion-sqlparser-rs/pull/1857) (dependabot[bot])
|
|
||||||
- pretty-print CREATE TABLE statements [#1854](https://github.com/apache/datafusion-sqlparser-rs/pull/1854) (lovasoa)
|
|
||||||
- pretty-print CREATE VIEW statements [#1855](https://github.com/apache/datafusion-sqlparser-rs/pull/1855) (lovasoa)
|
|
||||||
- Handle optional datatypes properly in `CREATE FUNCTION` statements [#1826](https://github.com/apache/datafusion-sqlparser-rs/pull/1826) (LucaCappelletti94)
|
|
||||||
- Mysql: Add `SRID` column option [#1852](https://github.com/apache/datafusion-sqlparser-rs/pull/1852) (MohamedAbdeen21)
|
|
||||||
- Add support for table valued functions for SQL Server [#1839](https://github.com/apache/datafusion-sqlparser-rs/pull/1839) (aharpervc)
|
|
||||||
- Keep the COLUMN keyword only if it exists when dropping the column [#1862](https://github.com/apache/datafusion-sqlparser-rs/pull/1862) (git-hulk)
|
|
||||||
- Add support for parameter default values in SQL Server [#1866](https://github.com/apache/datafusion-sqlparser-rs/pull/1866) (aharpervc)
|
|
||||||
- Add support for `TABLESAMPLE` pipe operator [#1860](https://github.com/apache/datafusion-sqlparser-rs/pull/1860) (hendrikmakait)
|
|
||||||
- Adds support for mysql's drop index [#1864](https://github.com/apache/datafusion-sqlparser-rs/pull/1864) (dmzmk)
|
|
||||||
- Fix: GROUPING SETS accept values without parenthesis [#1867](https://github.com/apache/datafusion-sqlparser-rs/pull/1867) (Vedin)
|
|
||||||
- Add ICEBERG keyword support to ALTER TABLE statement [#1869](https://github.com/apache/datafusion-sqlparser-rs/pull/1869) (osipovartem)
|
|
||||||
- MySQL: Support `index_name` in FK constraints [#1871](https://github.com/apache/datafusion-sqlparser-rs/pull/1871) (MohamedAbdeen21)
|
|
||||||
- Postgres: Apply `ONLY` keyword per table in TRUNCATE stmt [#1872](https://github.com/apache/datafusion-sqlparser-rs/pull/1872) (MohamedAbdeen21)
|
|
||||||
- Fix `CASE` expression spans [#1874](https://github.com/apache/datafusion-sqlparser-rs/pull/1874) (eliaperantoni)
|
|
||||||
- MySQL: `[[NOT] ENFORCED]` in CHECK constraint [#1870](https://github.com/apache/datafusion-sqlparser-rs/pull/1870) (MohamedAbdeen21)
|
|
||||||
- Add support for `CREATE SCHEMA WITH ( <properties> )` [#1877](https://github.com/apache/datafusion-sqlparser-rs/pull/1877) (utay)
|
|
||||||
- Add support for `ALTER TABLE DROP INDEX` [#1865](https://github.com/apache/datafusion-sqlparser-rs/pull/1865) (vimko)
|
|
||||||
- chore: Replace archived actions-rs/install action [#1876](https://github.com/apache/datafusion-sqlparser-rs/pull/1876) (assignUser)
|
|
||||||
- Allow `IF NOT EXISTS` after table name for Snowflake [#1881](https://github.com/apache/datafusion-sqlparser-rs/pull/1881) (bombsimon)
|
|
||||||
- Support `DISTINCT AS { STRUCT | VALUE }` for BigQuery [#1880](https://github.com/apache/datafusion-sqlparser-rs/pull/1880) (bombsimon)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
|
|
||||||
|
|
||||||
```
|
|
||||||
7 Ophir LOJKINE
|
|
||||||
6 Andrew Harper
|
|
||||||
6 Mohamed Abdeen
|
|
||||||
3 Luca Cappelletti
|
|
||||||
2 Denys Tsomenko
|
|
||||||
2 Simon Sawert
|
|
||||||
1 Andrew Lamb
|
|
||||||
1 Artem Osipov
|
|
||||||
1 Chen Chongchen
|
|
||||||
1 Dmitriy Mazurin
|
|
||||||
1 Elia Perantoni
|
|
||||||
1 Hendrik Makait
|
|
||||||
1 Jacob Wujciak-Jens
|
|
||||||
1 Simon Vandel Sillesen
|
|
||||||
1 Yannick Utard
|
|
||||||
1 benrsatori
|
|
||||||
1 dependabot[bot]
|
|
||||||
1 hulk
|
|
||||||
1 vimko
|
|
||||||
```
|
|
||||||
|
|
||||||
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.
|
|
||||||
|
|
|
@ -1,24 +1,7 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "sqlparser_derive"
|
name = "sqlparser_derive"
|
||||||
description = "Procedural (proc) macros for sqlparser"
|
description = "proc macro for sqlparser"
|
||||||
version = "0.3.0"
|
version = "0.2.2"
|
||||||
authors = ["sqlparser-rs authors"]
|
authors = ["sqlparser-rs authors"]
|
||||||
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
|
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||||
documentation = "https://docs.rs/sqlparser_derive/"
|
documentation = "https://docs.rs/sqlparser_derive/"
|
||||||
|
@ -28,7 +11,6 @@ license = "Apache-2.0"
|
||||||
include = [
|
include = [
|
||||||
"src/**/*.rs",
|
"src/**/*.rs",
|
||||||
"Cargo.toml",
|
"Cargo.toml",
|
||||||
"LICENSE.TXT",
|
|
||||||
]
|
]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../LICENSE.TXT
|
|
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# SQL Parser Derive Macro
|
# SQL Parser Derive Macro
|
||||||
|
|
||||||
## Visit
|
## Visit
|
||||||
|
@ -151,55 +132,6 @@ visitor.post_visit_expr(<is null operand>)
|
||||||
visitor.post_visit_expr(<is null expr>)
|
visitor.post_visit_expr(<is null expr>)
|
||||||
```
|
```
|
||||||
|
|
||||||
If the field is a `Option` and add `#[with = "visit_xxx"]` to the field, the generated code
|
|
||||||
will try to access the field only if it is `Some`:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct ShowStatementIn {
|
|
||||||
pub clause: ShowStatementInClause,
|
|
||||||
pub parent_type: Option<ShowStatementInParentType>,
|
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
|
||||||
pub parent_name: Option<ObjectName>,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This will generate
|
|
||||||
|
|
||||||
```rust
|
|
||||||
impl sqlparser::ast::Visit for ShowStatementIn {
|
|
||||||
fn visit<V: sqlparser::ast::Visitor>(
|
|
||||||
&self,
|
|
||||||
visitor: &mut V,
|
|
||||||
) -> ::std::ops::ControlFlow<V::Break> {
|
|
||||||
sqlparser::ast::Visit::visit(&self.clause, visitor)?;
|
|
||||||
sqlparser::ast::Visit::visit(&self.parent_type, visitor)?;
|
|
||||||
if let Some(value) = &self.parent_name {
|
|
||||||
visitor.pre_visit_relation(value)?;
|
|
||||||
sqlparser::ast::Visit::visit(value, visitor)?;
|
|
||||||
visitor.post_visit_relation(value)?;
|
|
||||||
}
|
|
||||||
::std::ops::ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl sqlparser::ast::VisitMut for ShowStatementIn {
|
|
||||||
fn visit<V: sqlparser::ast::VisitorMut>(
|
|
||||||
&mut self,
|
|
||||||
visitor: &mut V,
|
|
||||||
) -> ::std::ops::ControlFlow<V::Break> {
|
|
||||||
sqlparser::ast::VisitMut::visit(&mut self.clause, visitor)?;
|
|
||||||
sqlparser::ast::VisitMut::visit(&mut self.parent_type, visitor)?;
|
|
||||||
if let Some(value) = &mut self.parent_name {
|
|
||||||
visitor.pre_visit_relation(value)?;
|
|
||||||
sqlparser::ast::VisitMut::visit(value, visitor)?;
|
|
||||||
visitor.post_visit_relation(value)?;
|
|
||||||
}
|
|
||||||
::std::ops::ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Releasing
|
## Releasing
|
||||||
|
|
||||||
This crate's release is not automated. Instead it is released manually as needed
|
This crate's release is not automated. Instead it is released manually as needed
|
||||||
|
|
|
@ -1,54 +1,31 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_macro_input, parse_quote, Attribute, Data, DeriveInput, Fields, GenericParam, Generics,
|
parse_macro_input, parse_quote, Attribute, Data, DeriveInput,
|
||||||
Ident, Index, LitStr, Meta, Token, Type, TypePath,
|
Fields, GenericParam, Generics, Ident, Index, LitStr, Meta, Token
|
||||||
};
|
};
|
||||||
use syn::{Path, PathArguments};
|
|
||||||
|
|
||||||
/// Implementation of `[#derive(Visit)]`
|
/// Implementation of `[#derive(Visit)]`
|
||||||
#[proc_macro_derive(VisitMut, attributes(visit))]
|
#[proc_macro_derive(VisitMut, attributes(visit))]
|
||||||
pub fn derive_visit_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_visit_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
derive_visit(
|
derive_visit(input, &VisitType {
|
||||||
input,
|
visit_trait: quote!(VisitMut),
|
||||||
&VisitType {
|
visitor_trait: quote!(VisitorMut),
|
||||||
visit_trait: quote!(VisitMut),
|
modifier: Some(quote!(mut)),
|
||||||
visitor_trait: quote!(VisitorMut),
|
})
|
||||||
modifier: Some(quote!(mut)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of `[#derive(Visit)]`
|
/// Implementation of `[#derive(Visit)]`
|
||||||
#[proc_macro_derive(Visit, attributes(visit))]
|
#[proc_macro_derive(Visit, attributes(visit))]
|
||||||
pub fn derive_visit_immutable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_visit_immutable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
derive_visit(
|
derive_visit(input, &VisitType {
|
||||||
input,
|
visit_trait: quote!(Visit),
|
||||||
&VisitType {
|
visitor_trait: quote!(Visitor),
|
||||||
visit_trait: quote!(Visit),
|
modifier: None,
|
||||||
visitor_trait: quote!(Visitor),
|
})
|
||||||
modifier: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VisitType {
|
struct VisitType {
|
||||||
|
@ -57,16 +34,15 @@ struct VisitType {
|
||||||
modifier: Option<TokenStream>,
|
modifier: Option<TokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_visit(input: proc_macro::TokenStream, visit_type: &VisitType) -> proc_macro::TokenStream {
|
fn derive_visit(
|
||||||
|
input: proc_macro::TokenStream,
|
||||||
|
visit_type: &VisitType,
|
||||||
|
) -> proc_macro::TokenStream {
|
||||||
// Parse the input tokens into a syntax tree.
|
// Parse the input tokens into a syntax tree.
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
let name = input.ident;
|
let name = input.ident;
|
||||||
|
|
||||||
let VisitType {
|
let VisitType { visit_trait, visitor_trait, modifier } = visit_type;
|
||||||
visit_trait,
|
|
||||||
visitor_trait,
|
|
||||||
modifier,
|
|
||||||
} = visit_type;
|
|
||||||
|
|
||||||
let attributes = Attributes::parse(&input.attrs);
|
let attributes = Attributes::parse(&input.attrs);
|
||||||
// Add a bound `T: Visit` to every type parameter T.
|
// Add a bound `T: Visit` to every type parameter T.
|
||||||
|
@ -78,10 +54,7 @@ fn derive_visit(input: proc_macro::TokenStream, visit_type: &VisitType) -> proc_
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
// The generated impl.
|
// The generated impl.
|
||||||
// Note that it uses [`recursive::recursive`] to protect from stack overflow.
|
|
||||||
// See tests in https://github.com/apache/datafusion-sqlparser-rs/pull/1522/ for more info.
|
|
||||||
impl #impl_generics sqlparser::ast::#visit_trait for #name #ty_generics #where_clause {
|
impl #impl_generics sqlparser::ast::#visit_trait for #name #ty_generics #where_clause {
|
||||||
#[cfg_attr(feature = "recursive-protection", recursive::recursive)]
|
|
||||||
fn visit<V: sqlparser::ast::#visitor_trait>(
|
fn visit<V: sqlparser::ast::#visitor_trait>(
|
||||||
&#modifier self,
|
&#modifier self,
|
||||||
visitor: &mut V
|
visitor: &mut V
|
||||||
|
@ -114,10 +87,7 @@ impl Parse for WithIdent {
|
||||||
let mut result = WithIdent { with: None };
|
let mut result = WithIdent { with: None };
|
||||||
let ident = input.parse::<Ident>()?;
|
let ident = input.parse::<Ident>()?;
|
||||||
if ident != "with" {
|
if ident != "with" {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(ident.span(), "Expected identifier to be `with`"));
|
||||||
ident.span(),
|
|
||||||
"Expected identifier to be `with`",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
input.parse::<Token!(=)>()?;
|
input.parse::<Token!(=)>()?;
|
||||||
let s = input.parse::<LitStr>()?;
|
let s = input.parse::<LitStr>()?;
|
||||||
|
@ -161,46 +131,25 @@ impl Attributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a bound `T: Visit` to every type parameter T.
|
// Add a bound `T: Visit` to every type parameter T.
|
||||||
fn add_trait_bounds(mut generics: Generics, VisitType { visit_trait, .. }: &VisitType) -> Generics {
|
fn add_trait_bounds(mut generics: Generics, VisitType{visit_trait, ..}: &VisitType) -> Generics {
|
||||||
for param in &mut generics.params {
|
for param in &mut generics.params {
|
||||||
if let GenericParam::Type(ref mut type_param) = *param {
|
if let GenericParam::Type(ref mut type_param) = *param {
|
||||||
type_param
|
type_param.bounds.push(parse_quote!(sqlparser::ast::#visit_trait));
|
||||||
.bounds
|
|
||||||
.push(parse_quote!(sqlparser::ast::#visit_trait));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generics
|
generics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the body of the visit implementation for the given type
|
// Generate the body of the visit implementation for the given type
|
||||||
fn visit_children(
|
fn visit_children(data: &Data, VisitType{visit_trait, modifier, ..}: &VisitType) -> TokenStream {
|
||||||
data: &Data,
|
|
||||||
VisitType {
|
|
||||||
visit_trait,
|
|
||||||
modifier,
|
|
||||||
..
|
|
||||||
}: &VisitType,
|
|
||||||
) -> TokenStream {
|
|
||||||
match data {
|
match data {
|
||||||
Data::Struct(data) => match &data.fields {
|
Data::Struct(data) => match &data.fields {
|
||||||
Fields::Named(fields) => {
|
Fields::Named(fields) => {
|
||||||
let recurse = fields.named.iter().map(|f| {
|
let recurse = fields.named.iter().map(|f| {
|
||||||
let name = &f.ident;
|
let name = &f.ident;
|
||||||
let is_option = is_option(&f.ty);
|
|
||||||
let attributes = Attributes::parse(&f.attrs);
|
let attributes = Attributes::parse(&f.attrs);
|
||||||
if is_option && attributes.with.is_some() {
|
let (pre_visit, post_visit) = attributes.visit(quote!(&#modifier self.#name));
|
||||||
let (pre_visit, post_visit) = attributes.visit(quote!(value));
|
quote_spanned!(f.span() => #pre_visit sqlparser::ast::#visit_trait::visit(&#modifier self.#name, visitor)?; #post_visit)
|
||||||
quote_spanned!(f.span() =>
|
|
||||||
if let Some(value) = &#modifier self.#name {
|
|
||||||
#pre_visit sqlparser::ast::#visit_trait::visit(value, visitor)?; #post_visit
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let (pre_visit, post_visit) = attributes.visit(quote!(&#modifier self.#name));
|
|
||||||
quote_spanned!(f.span() =>
|
|
||||||
#pre_visit sqlparser::ast::#visit_trait::visit(&#modifier self.#name, visitor)?; #post_visit
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
quote! {
|
quote! {
|
||||||
#(#recurse)*
|
#(#recurse)*
|
||||||
|
@ -272,20 +221,3 @@ fn visit_children(
|
||||||
Data::Union(_) => unimplemented!(),
|
Data::Union(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_option(ty: &Type) -> bool {
|
|
||||||
if let Type::Path(TypePath {
|
|
||||||
path: Path { segments, .. },
|
|
||||||
..
|
|
||||||
}) = ty
|
|
||||||
{
|
|
||||||
if let Some(segment) = segments.last() {
|
|
||||||
if segment.ident == "Option" {
|
|
||||||
if let PathArguments::AngleBracketed(args) = &segment.arguments {
|
|
||||||
return args.args.len() == 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,187 +0,0 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Process Overview
|
|
||||||
|
|
||||||
As part of the Apache governance model, official releases consist of signed
|
|
||||||
source tarballs approved by the DataFusion PMC.
|
|
||||||
|
|
||||||
We then use the code in the approved artifacts to release to crates.io.
|
|
||||||
|
|
||||||
### Change Log
|
|
||||||
|
|
||||||
We maintain a `CHANGELOG.md` so our users know what has been changed between releases.
|
|
||||||
|
|
||||||
You will need a GitHub Personal Access Token for the following steps. Follow
|
|
||||||
[these instructions](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
|
|
||||||
to generate one if you do not already have one.
|
|
||||||
|
|
||||||
The changelog is generated using a Python script which needs `PyGitHub`, installed using pip:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip3 install PyGitHub
|
|
||||||
```
|
|
||||||
|
|
||||||
To generate the changelog, set the `GITHUB_TOKEN` environment variable to a valid token and then run the script
|
|
||||||
providing two commit ids or tags followed by the version number of the release being created. The following
|
|
||||||
example generates a change log of all changes between the first commit and the current HEAD revision.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
export GITHUB_TOKEN=<your-token-here>
|
|
||||||
python ./dev/release/generate-changelog.py v0.51.0 HEAD 0.52.0 > changelog/0.52.0.md
|
|
||||||
```
|
|
||||||
|
|
||||||
This script creates a changelog from GitHub PRs based on the labels associated with them as well as looking for
|
|
||||||
titles starting with `feat:`, `fix:`, or `docs:`.
|
|
||||||
|
|
||||||
Add an entry to CHANGELOG.md for the new version
|
|
||||||
|
|
||||||
## Prepare release commits and PR
|
|
||||||
|
|
||||||
### Update Version
|
|
||||||
|
|
||||||
Checkout the main commit to be released
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git fetch apache
|
|
||||||
git checkout apache/main
|
|
||||||
```
|
|
||||||
|
|
||||||
Manually update the version in the root `Cargo.toml` to the release version (e.g. `0.52.0`).
|
|
||||||
|
|
||||||
Lastly commit the version change:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git commit -a -m 'Update version'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Prepare release candidate artifacts
|
|
||||||
|
|
||||||
After the PR gets merged, you are ready to create release artifacts from the
|
|
||||||
merged commit.
|
|
||||||
|
|
||||||
(Note you need to be a committer to run these scripts as they upload to the apache svn distribution servers)
|
|
||||||
|
|
||||||
### Pick a Release Candidate (RC) number
|
|
||||||
|
|
||||||
Pick numbers in sequential order, with `0` for `rc0`, `1` for `rc1`, etc.
|
|
||||||
|
|
||||||
### Create git tag for the release:
|
|
||||||
|
|
||||||
While the official release artifacts are signed tarballs and zip files, we also
|
|
||||||
tag the commit it was created for convenience and code archaeology.
|
|
||||||
|
|
||||||
Using a string such as `v0.52.0` as the `<version>`, create and push the tag by running these commands:
|
|
||||||
|
|
||||||
For example to tag version `0.52.0`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git fetch apache
|
|
||||||
git tag v0.52.0-rc1 apache/main
|
|
||||||
# push tag to Github remote
|
|
||||||
git push apache v0.52.0-rc1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create, sign, and upload artifacts
|
|
||||||
|
|
||||||
Run `create-tarball.sh` with the `<version>` tag and `<rc>` and you found in previous steps:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
GITHUB_TOKEN=<TOKEN> ./dev/release/create-tarball.sh 0.52.0 1
|
|
||||||
```
|
|
||||||
|
|
||||||
The `create-tarball.sh` script
|
|
||||||
|
|
||||||
1. creates and uploads all release candidate artifacts to the [datafusion
|
|
||||||
dev](https://dist.apache.org/repos/dist/dev/datafusion) location on the
|
|
||||||
apache distribution svn server
|
|
||||||
|
|
||||||
2. provide you an email template to
|
|
||||||
send to dev@datafusion.apache.org for release voting.
|
|
||||||
|
|
||||||
### Vote on Release Candidate artifacts
|
|
||||||
|
|
||||||
Send the email output from the script to dev@datafusion.apache.org.
|
|
||||||
|
|
||||||
For the release to become "official" it needs at least three PMC members to vote +1 on it.
|
|
||||||
|
|
||||||
### Verifying Release Candidates
|
|
||||||
|
|
||||||
The `dev/release/verify-release-candidate.sh` is a script in this repository that can assist in the verification process. Run it like:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./dev/release/verify-release-candidate.sh 0.52.0 1
|
|
||||||
```
|
|
||||||
|
|
||||||
#### If the release is not approved
|
|
||||||
|
|
||||||
If the release is not approved, fix whatever the problem is, merge changelog
|
|
||||||
changes into main if there is any and try again with the next RC number.
|
|
||||||
|
|
||||||
## Finalize the release
|
|
||||||
|
|
||||||
NOTE: steps in this section can only be done by PMC members.
|
|
||||||
|
|
||||||
### After the release is approved
|
|
||||||
|
|
||||||
Move artifacts to the release location in SVN, using the `release-tarball.sh` script:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./dev/release/release-tarball.sh 0.52.0 1
|
|
||||||
```
|
|
||||||
|
|
||||||
Promote the rc tag to the release tag
|
|
||||||
```shell
|
|
||||||
git tag v0.52.0 v0.52.0-rc3
|
|
||||||
git push apache v0.52.0
|
|
||||||
```
|
|
||||||
|
|
||||||
Congratulations! The release is now official!
|
|
||||||
|
|
||||||
### Publish on Crates.io
|
|
||||||
|
|
||||||
Only approved releases of the tarball should be published to
|
|
||||||
crates.io, in order to conform to Apache Software Foundation
|
|
||||||
governance standards.
|
|
||||||
|
|
||||||
A DataFusion committer can publish this crate after an official project release has
|
|
||||||
been made to crates.io using the following instructions.
|
|
||||||
|
|
||||||
Follow [these
|
|
||||||
instructions](https://doc.rust-lang.org/cargo/reference/publishing.html) to
|
|
||||||
create an account and login to crates.io before asking to be added as an owner
|
|
||||||
to the sqlparser DataFusion crates.
|
|
||||||
|
|
||||||
Download and unpack the official release tarball
|
|
||||||
|
|
||||||
Verify that the Cargo.toml in the tarball contains the correct version
|
|
||||||
(e.g. `version = "0.52.0"`) and then publish the crates by running the following commands
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cargo publish
|
|
||||||
```
|
|
||||||
|
|
||||||
If necessary, also publish the `sqlparser_derive` crate:
|
|
||||||
|
|
||||||
crates.io homepage: https://crates.io/crates/sqlparser_derive
|
|
||||||
|
|
||||||
```shell
|
|
||||||
(cd derive && cargo publish
|
|
||||||
```
|
|
|
@ -1,59 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
##############################################################################
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
##############################################################################
|
|
||||||
import fnmatch
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
if len(sys.argv) != 3:
|
|
||||||
sys.stderr.write("Usage: %s exclude_globs.lst rat_report.xml\n" %
|
|
||||||
sys.argv[0])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
exclude_globs_filename = sys.argv[1]
|
|
||||||
xml_filename = sys.argv[2]
|
|
||||||
|
|
||||||
globs = [line.strip() for line in open(exclude_globs_filename, "r")]
|
|
||||||
|
|
||||||
tree = ET.parse(xml_filename)
|
|
||||||
root = tree.getroot()
|
|
||||||
resources = root.findall('resource')
|
|
||||||
|
|
||||||
all_ok = True
|
|
||||||
for r in resources:
|
|
||||||
approvals = r.findall('license-approval')
|
|
||||||
if not approvals or approvals[0].attrib['name'] == 'true':
|
|
||||||
continue
|
|
||||||
clean_name = re.sub('^[^/]+/', '', r.attrib['name'])
|
|
||||||
excluded = False
|
|
||||||
for g in globs:
|
|
||||||
if fnmatch.fnmatch(clean_name, g):
|
|
||||||
excluded = True
|
|
||||||
break
|
|
||||||
if not excluded:
|
|
||||||
sys.stdout.write("NOT APPROVED: %s (%s): %s\n" % (
|
|
||||||
clean_name, r.attrib['name'], approvals[0].attrib['name']))
|
|
||||||
all_ok = False
|
|
||||||
|
|
||||||
if not all_ok:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print('OK')
|
|
||||||
sys.exit(0)
|
|
|
@ -1,135 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Adapted from https://github.com/apache/datafusion/tree/master/dev/release/create-tarball.sh
|
|
||||||
|
|
||||||
# This script creates a signed tarball in
|
|
||||||
# dev/dist/apache-datafusion-sqlparser-rs-<version>-rc.tar.gz and uploads it to
|
|
||||||
# the "dev" area of the dist.apache.datafusion repository and prepares an
|
|
||||||
# email for sending to the dev@datafusion.apache.org list for a formal
|
|
||||||
# vote.
|
|
||||||
#
|
|
||||||
# See release/README.md for full release instructions
|
|
||||||
#
|
|
||||||
# Requirements:
|
|
||||||
#
|
|
||||||
# 1. gpg setup for signing and have uploaded your public
|
|
||||||
# signature to https://pgp.mit.edu/
|
|
||||||
#
|
|
||||||
# 2. Logged into the apache svn server with the appropriate
|
|
||||||
# credentials
|
|
||||||
#
|
|
||||||
# 3. Install the requests python package
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Based in part on 02-source.sh from apache/arrow
|
|
||||||
#
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
SOURCE_TOP_DIR="$(cd "${SOURCE_DIR}/../../" && pwd)"
|
|
||||||
|
|
||||||
if [ "$#" -ne 2 ]; then
|
|
||||||
echo "Usage: $0 <version> <rc>"
|
|
||||||
echo "ex. $0 0.52.0 2"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "${GITHUB_TOKEN}" ]]; then
|
|
||||||
echo "Please set personal github token through GITHUB_TOKEN environment variable"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$1
|
|
||||||
rc=$2
|
|
||||||
tag="v${version}-rc${rc}"
|
|
||||||
|
|
||||||
echo "Attempting to create ${tarball} from tag ${tag}"
|
|
||||||
release_hash=$(cd "${SOURCE_TOP_DIR}" && git rev-list --max-count=1 ${tag})
|
|
||||||
|
|
||||||
release=apache-datafusion-sqlparser-rs-${version}
|
|
||||||
distdir=${SOURCE_TOP_DIR}/dev/dist/${release}-rc${rc}
|
|
||||||
tarname=${release}.tar.gz
|
|
||||||
tarball=${distdir}/${tarname}
|
|
||||||
url="https://dist.apache.org/repos/dist/dev/datafusion/${release}-rc${rc}"
|
|
||||||
|
|
||||||
if [ -z "$release_hash" ]; then
|
|
||||||
echo "Cannot continue: unknown git tag: ${tag}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Draft email for dev@datafusion.apache.org mailing list"
|
|
||||||
echo ""
|
|
||||||
echo "---------------------------------------------------------"
|
|
||||||
cat <<MAIL
|
|
||||||
To: dev@datafusion.apache.org
|
|
||||||
Subject: [VOTE] Release Apache DataFusion sqlparser-rs ${version} RC${rc}
|
|
||||||
Hi,
|
|
||||||
|
|
||||||
I would like to propose a release of Apache DataFusion sqlparser-rs version ${version}.
|
|
||||||
|
|
||||||
This release candidate is based on commit: ${release_hash} [1]
|
|
||||||
The proposed release tarball and signatures are hosted at [2].
|
|
||||||
The changelog is located at [3].
|
|
||||||
|
|
||||||
Please download, verify checksums and signatures, run the unit tests, and vote
|
|
||||||
on the release. The vote will be open for at least 72 hours.
|
|
||||||
|
|
||||||
Only votes from PMC members are binding, but all members of the community are
|
|
||||||
encouraged to test the release and vote with "(non-binding)".
|
|
||||||
|
|
||||||
The standard verification procedure is documented at https://github.com/apache/datafusion-sqlparser-rs/blob/main/dev/release/README.md#verifying-release-candidates.
|
|
||||||
|
|
||||||
[ ] +1 Release this as Apache DataFusion sqlparser-rs ${version}
|
|
||||||
[ ] +0
|
|
||||||
[ ] -1 Do not release this as Apache DataFusion sqlparser-rs ${version} because...
|
|
||||||
|
|
||||||
Here is my vote:
|
|
||||||
|
|
||||||
+1
|
|
||||||
|
|
||||||
[1]: https://github.com/apache/datafusion-sqlparser-rs/tree/${release_hash}
|
|
||||||
[2]: ${url}
|
|
||||||
[3]: https://github.com/apache/datafusion-sqlparser-rs/blob/${release_hash}/CHANGELOG.md
|
|
||||||
MAIL
|
|
||||||
echo "---------------------------------------------------------"
|
|
||||||
|
|
||||||
|
|
||||||
# create <tarball> containing the files in git at $release_hash
|
|
||||||
# the files in the tarball are prefixed with {version} (e.g. 4.0.1)
|
|
||||||
mkdir -p ${distdir}
|
|
||||||
(cd "${SOURCE_TOP_DIR}" && git archive ${release_hash} --prefix ${release}/ | gzip > ${tarball})
|
|
||||||
|
|
||||||
echo "Running rat license checker on ${tarball}"
|
|
||||||
${SOURCE_DIR}/run-rat.sh ${tarball}
|
|
||||||
|
|
||||||
echo "Signing tarball and creating checksums"
|
|
||||||
gpg --armor --output ${tarball}.asc --detach-sig ${tarball}
|
|
||||||
# create signing with relative path of tarball
|
|
||||||
# so that they can be verified with a command such as
|
|
||||||
# shasum --check apache-datafusion-sqlparser-rs-0.52.0-rc1.tar.gz.sha512
|
|
||||||
(cd ${distdir} && shasum -a 256 ${tarname}) > ${tarball}.sha256
|
|
||||||
(cd ${distdir} && shasum -a 512 ${tarname}) > ${tarball}.sha512
|
|
||||||
|
|
||||||
|
|
||||||
echo "Uploading to sqlparser-rs dist/dev to ${url}"
|
|
||||||
svn co --depth=empty https://dist.apache.org/repos/dist/dev/datafusion ${SOURCE_TOP_DIR}/dev/dist
|
|
||||||
svn add ${distdir}
|
|
||||||
svn ci -m "Apache DataFusion ${version} ${rc}" ${distdir}
|
|
|
@ -1,165 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
# contributor license agreements. See the NOTICE file distributed with
|
|
||||||
# this work for additional information regarding copyright ownership.
|
|
||||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
# (the "License"); you may not use this file except in compliance with
|
|
||||||
# the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
from github import Github
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
def print_pulls(repo_name, title, pulls):
|
|
||||||
if len(pulls) > 0:
|
|
||||||
print("**{}:**".format(title))
|
|
||||||
print()
|
|
||||||
for (pull, commit) in pulls:
|
|
||||||
url = "https://github.com/{}/pull/{}".format(repo_name, pull.number)
|
|
||||||
author = f"({commit.author.login})" if commit.author else ''
|
|
||||||
print("- {} [#{}]({}) {}".format(pull.title, pull.number, url, author))
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def generate_changelog(repo, repo_name, tag1, tag2, version):
|
|
||||||
|
|
||||||
# get a list of commits between two tags
|
|
||||||
print(f"Fetching list of commits between {tag1} and {tag2}", file=sys.stderr)
|
|
||||||
comparison = repo.compare(tag1, tag2)
|
|
||||||
|
|
||||||
# get the pull requests for these commits
|
|
||||||
print("Fetching pull requests", file=sys.stderr)
|
|
||||||
unique_pulls = []
|
|
||||||
all_pulls = []
|
|
||||||
for commit in comparison.commits:
|
|
||||||
pulls = commit.get_pulls()
|
|
||||||
for pull in pulls:
|
|
||||||
# there can be multiple commits per PR if squash merge is not being used and
|
|
||||||
# in this case we should get all the author names, but for now just pick one
|
|
||||||
if pull.number not in unique_pulls:
|
|
||||||
unique_pulls.append(pull.number)
|
|
||||||
all_pulls.append((pull, commit))
|
|
||||||
|
|
||||||
# we split the pulls into categories
|
|
||||||
breaking = []
|
|
||||||
bugs = []
|
|
||||||
docs = []
|
|
||||||
enhancements = []
|
|
||||||
performance = []
|
|
||||||
other = []
|
|
||||||
|
|
||||||
# categorize the pull requests based on GitHub labels
|
|
||||||
print("Categorizing pull requests", file=sys.stderr)
|
|
||||||
for (pull, commit) in all_pulls:
|
|
||||||
|
|
||||||
# see if PR title uses Conventional Commits
|
|
||||||
cc_type = ''
|
|
||||||
cc_scope = ''
|
|
||||||
cc_breaking = ''
|
|
||||||
parts = re.findall(r'^([a-z]+)(\([a-z]+\))?(!)?:', pull.title)
|
|
||||||
if len(parts) == 1:
|
|
||||||
parts_tuple = parts[0]
|
|
||||||
cc_type = parts_tuple[0] # fix, feat, docs, chore
|
|
||||||
cc_scope = parts_tuple[1] # component within project
|
|
||||||
cc_breaking = parts_tuple[2] == '!'
|
|
||||||
|
|
||||||
labels = [label.name for label in pull.labels]
|
|
||||||
if 'api change' in labels or cc_breaking:
|
|
||||||
breaking.append((pull, commit))
|
|
||||||
elif 'bug' in labels or cc_type == 'fix':
|
|
||||||
bugs.append((pull, commit))
|
|
||||||
elif 'performance' in labels or cc_type == 'perf':
|
|
||||||
performance.append((pull, commit))
|
|
||||||
elif 'enhancement' in labels or cc_type == 'feat':
|
|
||||||
enhancements.append((pull, commit))
|
|
||||||
elif 'documentation' in labels or cc_type == 'docs' or cc_type == 'doc':
|
|
||||||
docs.append((pull, commit))
|
|
||||||
else:
|
|
||||||
other.append((pull, commit))
|
|
||||||
|
|
||||||
# produce the changelog content
|
|
||||||
print("Generating changelog content", file=sys.stderr)
|
|
||||||
|
|
||||||
# ASF header
|
|
||||||
print("""<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->\n""")
|
|
||||||
|
|
||||||
print(f"# sqlparser-rs {version} Changelog\n")
|
|
||||||
|
|
||||||
# get the number of commits
|
|
||||||
commit_count = subprocess.check_output(f"git log --pretty=oneline {tag1}..{tag2} | wc -l", shell=True, text=True).strip()
|
|
||||||
|
|
||||||
# get number of contributors
|
|
||||||
contributor_count = subprocess.check_output(f"git shortlog -sn {tag1}..{tag2} | wc -l", shell=True, text=True).strip()
|
|
||||||
|
|
||||||
print(f"This release consists of {commit_count} commits from {contributor_count} contributors. "
|
|
||||||
f"See credits at the end of this changelog for more information.\n")
|
|
||||||
|
|
||||||
print_pulls(repo_name, "Breaking changes", breaking)
|
|
||||||
print_pulls(repo_name, "Performance related", performance)
|
|
||||||
print_pulls(repo_name, "Implemented enhancements", enhancements)
|
|
||||||
print_pulls(repo_name, "Fixed bugs", bugs)
|
|
||||||
print_pulls(repo_name, "Documentation updates", docs)
|
|
||||||
print_pulls(repo_name, "Other", other)
|
|
||||||
|
|
||||||
# show code contributions
|
|
||||||
credits = subprocess.check_output(f"git shortlog -sn {tag1}..{tag2}", shell=True, text=True).rstrip()
|
|
||||||
|
|
||||||
print("## Credits\n")
|
|
||||||
print("Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) "
|
|
||||||
"per contributor.\n")
|
|
||||||
print("```")
|
|
||||||
print(credits)
|
|
||||||
print("```\n")
|
|
||||||
|
|
||||||
print("Thank you also to everyone who contributed in other ways such as filing issues, reviewing "
|
|
||||||
"PRs, and providing feedback on this release.\n")
|
|
||||||
|
|
||||||
def cli(args=None):
|
|
||||||
"""Process command line arguments."""
|
|
||||||
if not args:
|
|
||||||
args = sys.argv[1:]
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("tag1", help="The previous commit or tag (e.g. 0.1.0)")
|
|
||||||
parser.add_argument("tag2", help="The current commit or tag (e.g. HEAD)")
|
|
||||||
parser.add_argument("version", help="The version number to include in the changelog")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
token = os.getenv("GITHUB_TOKEN")
|
|
||||||
project = "apache/datafusion-sqlparser-rs"
|
|
||||||
|
|
||||||
g = Github(token)
|
|
||||||
repo = g.get_repo(project)
|
|
||||||
generate_changelog(repo, project, args.tag1, args.tag2, args.version)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
cli()
|
|
|
@ -1,8 +0,0 @@
|
||||||
.tool-versions
|
|
||||||
target/*
|
|
||||||
**.gitignore
|
|
||||||
rat.txt
|
|
||||||
dev/release/rat_exclude_files.txt
|
|
||||||
sqlparser_bench/img/flamegraph.svg
|
|
||||||
**Cargo.lock
|
|
||||||
filtered_rat.txt
|
|
|
@ -1,74 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Adapted from https://github.com/apache/arrow-rs/tree/master/dev/release/release-tarball.sh
|
|
||||||
|
|
||||||
# This script copies a tarball from the "dev" area of the
|
|
||||||
# dist.apache.datafusion repository to the "release" area
|
|
||||||
#
|
|
||||||
# This script should only be run after the release has been approved
|
|
||||||
# by the Apache DataFusion PMC committee.
|
|
||||||
#
|
|
||||||
# See release/README.md for full release instructions
|
|
||||||
#
|
|
||||||
# Based in part on post-01-upload.sh from apache/arrow
|
|
||||||
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -u
|
|
||||||
|
|
||||||
if [ "$#" -ne 2 ]; then
|
|
||||||
echo "Usage: $0 <version> <rc-num>"
|
|
||||||
echo "ex. $0 0.52.0 2"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$1
|
|
||||||
rc=$2
|
|
||||||
|
|
||||||
tmp_dir=tmp-apache-datafusion-dist
|
|
||||||
|
|
||||||
echo "Recreate temporary directory: ${tmp_dir}"
|
|
||||||
rm -rf ${tmp_dir}
|
|
||||||
mkdir -p ${tmp_dir}
|
|
||||||
|
|
||||||
echo "Clone dev dist repository"
|
|
||||||
svn \
|
|
||||||
co \
|
|
||||||
https://dist.apache.org/repos/dist/dev/datafusion/apache-datafusion-sqlparser-rs-${version}-rc${rc} \
|
|
||||||
${tmp_dir}/dev
|
|
||||||
|
|
||||||
echo "Clone release dist repository"
|
|
||||||
svn co https://dist.apache.org/repos/dist/release/datafusion ${tmp_dir}/release
|
|
||||||
|
|
||||||
echo "Copy ${version}-rc${rc} to release working copy"
|
|
||||||
release_version=datafusion-sqlparser-rs-${version}
|
|
||||||
mkdir -p ${tmp_dir}/release/${release_version}
|
|
||||||
cp -r ${tmp_dir}/dev/* ${tmp_dir}/release/${release_version}/
|
|
||||||
svn add ${tmp_dir}/release/${release_version}
|
|
||||||
|
|
||||||
echo "Commit release"
|
|
||||||
svn ci -m "Apache DataFusion sqlparser-rs ${version}" ${tmp_dir}/release
|
|
||||||
|
|
||||||
echo "Clean up"
|
|
||||||
rm -rf ${tmp_dir}
|
|
||||||
|
|
||||||
echo "Success! The release is available here:"
|
|
||||||
echo " https://dist.apache.org/repos/dist/release/datafusion/${release_version}"
|
|
|
@ -1,43 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
RAT_VERSION=0.13
|
|
||||||
|
|
||||||
# download apache rat
|
|
||||||
if [ ! -f apache-rat-${RAT_VERSION}.jar ]; then
|
|
||||||
curl -s https://repo1.maven.org/maven2/org/apache/rat/apache-rat/${RAT_VERSION}/apache-rat-${RAT_VERSION}.jar > apache-rat-${RAT_VERSION}.jar
|
|
||||||
fi
|
|
||||||
|
|
||||||
RAT="java -jar apache-rat-${RAT_VERSION}.jar -x "
|
|
||||||
|
|
||||||
RELEASE_DIR=$(cd "$(dirname "$BASH_SOURCE")"; pwd)
|
|
||||||
|
|
||||||
# generate the rat report
|
|
||||||
$RAT $1 > rat.txt
|
|
||||||
python $RELEASE_DIR/check-rat-report.py $RELEASE_DIR/rat_exclude_files.txt rat.txt > filtered_rat.txt
|
|
||||||
cat filtered_rat.txt
|
|
||||||
UNAPPROVED=`cat filtered_rat.txt | grep "NOT APPROVED" | wc -l`
|
|
||||||
|
|
||||||
if [ "0" -eq "${UNAPPROVED}" ]; then
|
|
||||||
echo "No unapproved licenses"
|
|
||||||
else
|
|
||||||
echo "${UNAPPROVED} unapproved licences. Check rat report: rat.txt"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
|
@ -1,152 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
case $# in
|
|
||||||
2) VERSION="$1"
|
|
||||||
RC_NUMBER="$2"
|
|
||||||
;;
|
|
||||||
*) echo "Usage: $0 X.Y.Z RC_NUMBER"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -x
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
|
||||||
ARROW_DIR="$(dirname $(dirname ${SOURCE_DIR}))"
|
|
||||||
ARROW_DIST_URL='https://dist.apache.org/repos/dist/dev/datafusion'
|
|
||||||
|
|
||||||
download_dist_file() {
|
|
||||||
curl \
|
|
||||||
--silent \
|
|
||||||
--show-error \
|
|
||||||
--fail \
|
|
||||||
--location \
|
|
||||||
--remote-name $ARROW_DIST_URL/$1
|
|
||||||
}
|
|
||||||
|
|
||||||
download_rc_file() {
|
|
||||||
download_dist_file apache-datafusion-sqlparser-rs-${VERSION}-rc${RC_NUMBER}/$1
|
|
||||||
}
|
|
||||||
|
|
||||||
import_gpg_keys() {
|
|
||||||
download_dist_file KEYS
|
|
||||||
gpg --import KEYS
|
|
||||||
}
|
|
||||||
|
|
||||||
if type shasum >/dev/null 2>&1; then
|
|
||||||
sha256_verify="shasum -a 256 -c"
|
|
||||||
sha512_verify="shasum -a 512 -c"
|
|
||||||
else
|
|
||||||
sha256_verify="sha256sum -c"
|
|
||||||
sha512_verify="sha512sum -c"
|
|
||||||
fi
|
|
||||||
|
|
||||||
fetch_archive() {
|
|
||||||
local dist_name=$1
|
|
||||||
download_rc_file ${dist_name}.tar.gz
|
|
||||||
download_rc_file ${dist_name}.tar.gz.asc
|
|
||||||
download_rc_file ${dist_name}.tar.gz.sha256
|
|
||||||
download_rc_file ${dist_name}.tar.gz.sha512
|
|
||||||
verify_dir_artifact_signatures
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_dir_artifact_signatures() {
|
|
||||||
# verify the signature and the checksums of each artifact
|
|
||||||
find . -name '*.asc' | while read sigfile; do
|
|
||||||
artifact=${sigfile/.asc/}
|
|
||||||
gpg --verify $sigfile $artifact || exit 1
|
|
||||||
|
|
||||||
# go into the directory because the checksum files contain only the
|
|
||||||
# basename of the artifact
|
|
||||||
pushd $(dirname $artifact)
|
|
||||||
base_artifact=$(basename $artifact)
|
|
||||||
${sha256_verify} $base_artifact.sha256 || exit 1
|
|
||||||
${sha512_verify} $base_artifact.sha512 || exit 1
|
|
||||||
popd
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_tempdir() {
|
|
||||||
cleanup() {
|
|
||||||
if [ "${TEST_SUCCESS}" = "yes" ]; then
|
|
||||||
rm -fr "${ARROW_TMPDIR}"
|
|
||||||
else
|
|
||||||
echo "Failed to verify release candidate. See ${ARROW_TMPDIR} for details."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "${ARROW_TMPDIR}" ]; then
|
|
||||||
# clean up automatically if ARROW_TMPDIR is not defined
|
|
||||||
ARROW_TMPDIR=$(mktemp -d -t "$1.XXXXX")
|
|
||||||
trap cleanup EXIT
|
|
||||||
else
|
|
||||||
# don't clean up automatically
|
|
||||||
mkdir -p "${ARROW_TMPDIR}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
test_source_distribution() {
|
|
||||||
# install rust toolchain in a similar fashion like test-miniconda
|
|
||||||
export RUSTUP_HOME=$PWD/test-rustup
|
|
||||||
export CARGO_HOME=$PWD/test-rustup
|
|
||||||
|
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path
|
|
||||||
|
|
||||||
export PATH=$RUSTUP_HOME/bin:$PATH
|
|
||||||
source $RUSTUP_HOME/env
|
|
||||||
|
|
||||||
# build and test rust
|
|
||||||
|
|
||||||
# raises on any formatting errors
|
|
||||||
rustup component add rustfmt --toolchain stable
|
|
||||||
cargo fmt --all -- --check
|
|
||||||
|
|
||||||
cargo build
|
|
||||||
cargo test --all-features
|
|
||||||
|
|
||||||
if ( find -iname 'Cargo.toml' | xargs grep SNAPSHOT ); then
|
|
||||||
echo "Cargo.toml version should not contain SNAPSHOT for releases"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check that publish works
|
|
||||||
cargo publish --dry-run
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_SUCCESS=no
|
|
||||||
|
|
||||||
setup_tempdir "datafusion-sqlparser-rs-${VERSION}"
|
|
||||||
echo "Working in sandbox ${ARROW_TMPDIR}"
|
|
||||||
cd ${ARROW_TMPDIR}
|
|
||||||
|
|
||||||
dist_name="apache-datafusion-sqlparser-rs-${VERSION}"
|
|
||||||
import_gpg_keys
|
|
||||||
fetch_archive ${dist_name}
|
|
||||||
tar xf ${dist_name}.tar.gz
|
|
||||||
pushd ${dist_name}
|
|
||||||
test_source_distribution
|
|
||||||
popd
|
|
||||||
|
|
||||||
TEST_SUCCESS=yes
|
|
||||||
echo 'Release candidate looks good!'
|
|
||||||
exit 0
|
|
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Benchmarking
|
# Benchmarking
|
||||||
|
|
||||||
Run `cargo bench` in the project `sqlparser_bench` execute the queries.
|
Run `cargo bench` in the project `sqlparser_bench` execute the queries.
|
||||||
|
|
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Writing a Custom SQL Parser
|
# Writing a Custom SQL Parser
|
||||||
|
|
||||||
I have explored many different ways of building this library to make it easy to extend it for custom SQL dialects. Most of my attempts ended in failure but I have now found a workable solution. It is not without downsides but this seems to be the most pragmatic solution.
|
I have explored many different ways of building this library to make it easy to extend it for custom SQL dialects. Most of my attempts ended in failure but I have now found a workable solution. It is not without downsides but this seems to be the most pragmatic solution.
|
||||||
|
|
|
@ -1,22 +1,3 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Fuzzing
|
# Fuzzing
|
||||||
|
|
||||||
## Installing `honggfuzz`
|
## Installing `honggfuzz`
|
||||||
|
|
62
docs/releasing.md
Normal file
62
docs/releasing.md
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# Releasing
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
Publishing to crates.io has been automated via GitHub Actions, so you will only
|
||||||
|
need push access to the [sqlparser-rs GitHub repository](https://github.com/sqlparser-rs/sqlparser-rs)
|
||||||
|
in order to publish a release.
|
||||||
|
|
||||||
|
We use the [`cargo release`](https://github.com/sunng87/cargo-release)
|
||||||
|
subcommand to ensure correct versioning. Install via:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cargo install cargo-release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Process
|
||||||
|
|
||||||
|
1. **Before releasing** ensure `CHANGELOG.md` is updated appropriately and that
|
||||||
|
you have a clean checkout of the `main` branch of the sqlparser repository:
|
||||||
|
```
|
||||||
|
$ git fetch && git status
|
||||||
|
On branch main
|
||||||
|
Your branch is up to date with 'origin/main'.
|
||||||
|
|
||||||
|
nothing to commit, working tree clean
|
||||||
|
```
|
||||||
|
* If you have the time, check that the examples in the README are up to date.
|
||||||
|
|
||||||
|
2. Using `cargo-release` we can publish a new release like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cargo release minor --push-remote origin
|
||||||
|
```
|
||||||
|
|
||||||
|
After verifying, you can rerun with `--execute` if all looks good.
|
||||||
|
You can add `--no-push` to stop before actually publishing the release.
|
||||||
|
|
||||||
|
`cargo release` will then:
|
||||||
|
|
||||||
|
* Bump the minor part of the version in `Cargo.toml` (e.g. `0.7.1-alpha.0`
|
||||||
|
-> `0.8.0`. You can use `patch` instead of `minor`, as appropriate).
|
||||||
|
* Create a new tag (e.g. `v0.8.0`) locally
|
||||||
|
* Push the new tag to the specified remote (`origin` in the above
|
||||||
|
example), which will trigger a publishing process to crates.io as part of
|
||||||
|
the [corresponding GitHub Action](https://github.com/sqlparser-rs/sqlparser-rs/blob/main/.github/workflows/rust.yml).
|
||||||
|
|
||||||
|
Note that credentials for authoring in this way are securely stored in
|
||||||
|
the (GitHub) repo secrets as `CRATE_TOKEN`.
|
||||||
|
|
||||||
|
4. Check that the new version of the crate is available on crates.io:
|
||||||
|
https://crates.io/crates/sqlparser
|
||||||
|
|
||||||
|
|
||||||
|
## `sqlparser_derive` crate
|
||||||
|
|
||||||
|
Currently this crate is manually published via `cargo publish`.
|
||||||
|
|
||||||
|
crates.io homepage: https://crates.io/crates/sqlparser_derive
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd derive
|
||||||
|
cargo publish
|
||||||
|
```
|
|
@ -1,27 +1,20 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
//! A small command-line app to run the parser.
|
/// A small command-line app to run the parser.
|
||||||
//! Run with `cargo run --example cli`
|
/// Run with `cargo run --example cli`
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{stdin, Read};
|
|
||||||
|
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use sqlparser::dialect::*;
|
use sqlparser::dialect::*;
|
||||||
|
@ -40,9 +33,6 @@ $ cargo run --example cli FILENAME.sql [--dialectname]
|
||||||
To print the parse results as JSON:
|
To print the parse results as JSON:
|
||||||
$ cargo run --feature json_example --example cli FILENAME.sql [--dialectname]
|
$ cargo run --feature json_example --example cli FILENAME.sql [--dialectname]
|
||||||
|
|
||||||
To read from stdin instead of a file:
|
|
||||||
$ cargo run --example cli - [--dialectname]
|
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,18 +52,9 @@ $ cargo run --example cli - [--dialectname]
|
||||||
s => panic!("Unexpected parameter: {s}"),
|
s => panic!("Unexpected parameter: {s}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let contents = if filename == "-" {
|
println!("Parsing from file '{}' using {:?}", &filename, dialect);
|
||||||
println!("Parsing from stdin using {dialect:?}");
|
let contents = fs::read_to_string(&filename)
|
||||||
let mut buf = Vec::new();
|
.unwrap_or_else(|_| panic!("Unable to read the file {}", &filename));
|
||||||
stdin()
|
|
||||||
.read_to_end(&mut buf)
|
|
||||||
.expect("failed to read from stdin");
|
|
||||||
String::from_utf8(buf).expect("stdin content wasn't valid utf8")
|
|
||||||
} else {
|
|
||||||
println!("Parsing from file '{}' using {:?}", &filename, dialect);
|
|
||||||
fs::read_to_string(&filename)
|
|
||||||
.unwrap_or_else(|_| panic!("Unable to read the file {}", &filename))
|
|
||||||
};
|
|
||||||
let without_bom = if contents.chars().next().unwrap() as u64 != 0xfeff {
|
let without_bom = if contents.chars().next().unwrap() as u64 != 0xfeff {
|
||||||
contents.as_str()
|
contents.as_str()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "fuzz"
|
name = "fuzz"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use honggfuzz::fuzz;
|
use honggfuzz::fuzz;
|
||||||
use sqlparser::dialect::GenericDialect;
|
use sqlparser::dialect::GenericDialect;
|
||||||
use sqlparser::parser::Parser;
|
use sqlparser::parser::Parser;
|
||||||
|
|
17
rustfmt.toml
17
rustfmt.toml
|
@ -1,18 +1 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
# We use rustfmt's default settings to format the source code
|
# We use rustfmt's default settings to format the source code
|
|
@ -1,23 +1,5 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "sqlparser_bench"
|
name = "sqlparser_bench"
|
||||||
description = "Benchmarks for sqlparser"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Dandandan <danielheres@gmail.com>"]
|
authors = ["Dandandan <danielheres@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
@ -26,7 +8,7 @@ edition = "2018"
|
||||||
sqlparser = { path = "../" }
|
sqlparser = { path = "../" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.6"
|
criterion = "0.5"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "sqlparser_bench"
|
name = "sqlparser_bench"
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
<!---
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
Benchmarks for sqlparser. See [the main README](../README.md) for more information.
|
|
||||||
|
|
||||||
Note: this is in a separate, non workspace crate to avoid adding a dependency
|
|
||||||
on `criterion` to the main crate (which complicates testing without std).
|
|
||||||
|
|
||||||
# Running Benchmarks
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cargo bench --bench sqlparser_bench
|
|
||||||
```
|
|
||||||
|
|
||||||
# Profiling
|
|
||||||
|
|
||||||
Note you can generate a [flamegraph] using the following command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cargo flamegraph --bench sqlparser_bench
|
|
||||||
```
|
|
||||||
|
|
||||||
[flamegraph]: https://crates.io/crates/flamegraph
|
|
||||||
|
|
||||||
Here is an example flamegraph:
|
|
||||||

|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use sqlparser::dialect::GenericDialect;
|
use sqlparser::dialect::GenericDialect;
|
||||||
|
@ -23,9 +18,9 @@ fn basic_queries(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("sqlparser-rs parsing benchmark");
|
let mut group = c.benchmark_group("sqlparser-rs parsing benchmark");
|
||||||
let dialect = GenericDialect {};
|
let dialect = GenericDialect {};
|
||||||
|
|
||||||
let string = "SELECT * FROM my_table WHERE 1 = 1";
|
let string = "SELECT * FROM table WHERE 1 = 1";
|
||||||
group.bench_function("sqlparser::select", |b| {
|
group.bench_function("sqlparser::select", |b| {
|
||||||
b.iter(|| Parser::parse_sql(&dialect, string).unwrap());
|
b.iter(|| Parser::parse_sql(&dialect, string));
|
||||||
});
|
});
|
||||||
|
|
||||||
let with_query = "
|
let with_query = "
|
||||||
|
@ -33,52 +28,14 @@ fn basic_queries(c: &mut Criterion) {
|
||||||
SELECT MAX(a) AS max_a,
|
SELECT MAX(a) AS max_a,
|
||||||
COUNT(b) AS b_num,
|
COUNT(b) AS b_num,
|
||||||
user_id
|
user_id
|
||||||
FROM MY_TABLE
|
FROM TABLE
|
||||||
GROUP BY user_id
|
GROUP BY user_id
|
||||||
)
|
)
|
||||||
SELECT * FROM my_table
|
SELECT * FROM table
|
||||||
LEFT JOIN derived USING (user_id)
|
LEFT JOIN derived USING (user_id)
|
||||||
";
|
";
|
||||||
group.bench_function("sqlparser::with_select", |b| {
|
group.bench_function("sqlparser::with_select", |b| {
|
||||||
b.iter(|| Parser::parse_sql(&dialect, with_query).unwrap());
|
b.iter(|| Parser::parse_sql(&dialect, with_query));
|
||||||
});
|
|
||||||
|
|
||||||
let large_statement = {
|
|
||||||
let expressions = (0..1000)
|
|
||||||
.map(|n| format!("FN_{n}(COL_{n})"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
let tables = (0..1000)
|
|
||||||
.map(|n| format!("TABLE_{n}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" JOIN ");
|
|
||||||
let where_condition = (0..1000)
|
|
||||||
.map(|n| format!("COL_{n} = {n}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" OR ");
|
|
||||||
let order_condition = (0..1000)
|
|
||||||
.map(|n| format!("COL_{n} DESC"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
format!(
|
|
||||||
"SELECT {expressions} FROM {tables} WHERE {where_condition} ORDER BY {order_condition}"
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
group.bench_function("parse_large_statement", |b| {
|
|
||||||
b.iter(|| Parser::parse_sql(&dialect, std::hint::black_box(large_statement.as_str())));
|
|
||||||
});
|
|
||||||
|
|
||||||
let large_statement = Parser::parse_sql(&dialect, large_statement.as_str())
|
|
||||||
.unwrap()
|
|
||||||
.pop()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
group.bench_function("format_large_statement", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let _formatted_query = large_statement.to_string();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 1.5 MiB |
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement)
|
//! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement)
|
||||||
//! (commonly referred to as Data Control Language, or DCL)
|
//! (commonly referred to as Data Control Language, or DCL)
|
||||||
|
@ -28,7 +23,7 @@ use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "visitor")]
|
#[cfg(feature = "visitor")]
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
use sqlparser_derive::{Visit, VisitMut};
|
||||||
|
|
||||||
use super::{display_comma_separated, Expr, Ident, Password};
|
use super::{Expr, Ident, Password};
|
||||||
use crate::ast::{display_separated, ObjectName};
|
use crate::ast::{display_separated, ObjectName};
|
||||||
|
|
||||||
/// An option in `ROLE` statement.
|
/// An option in `ROLE` statement.
|
||||||
|
@ -173,7 +168,7 @@ impl fmt::Display for AlterRoleOperation {
|
||||||
in_database,
|
in_database,
|
||||||
} => {
|
} => {
|
||||||
if let Some(database_name) = in_database {
|
if let Some(database_name) = in_database {
|
||||||
write!(f, "IN DATABASE {database_name} ")?;
|
write!(f, "IN DATABASE {} ", database_name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match config_value {
|
match config_value {
|
||||||
|
@ -187,7 +182,7 @@ impl fmt::Display for AlterRoleOperation {
|
||||||
in_database,
|
in_database,
|
||||||
} => {
|
} => {
|
||||||
if let Some(database_name) = in_database {
|
if let Some(database_name) = in_database {
|
||||||
write!(f, "IN DATABASE {database_name} ")?;
|
write!(f, "IN DATABASE {} ", database_name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match config_name {
|
match config_name {
|
||||||
|
@ -198,57 +193,3 @@ impl fmt::Display for AlterRoleOperation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `USE` (`Statement::Use`) operation
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum Use {
|
|
||||||
Catalog(ObjectName), // e.g. `USE CATALOG foo.bar`
|
|
||||||
Schema(ObjectName), // e.g. `USE SCHEMA foo.bar`
|
|
||||||
Database(ObjectName), // e.g. `USE DATABASE foo.bar`
|
|
||||||
Warehouse(ObjectName), // e.g. `USE WAREHOUSE foo.bar`
|
|
||||||
Role(ObjectName), // e.g. `USE ROLE PUBLIC`
|
|
||||||
SecondaryRoles(SecondaryRoles), // e.g. `USE SECONDARY ROLES ALL`
|
|
||||||
Object(ObjectName), // e.g. `USE foo.bar`
|
|
||||||
Default, // e.g. `USE DEFAULT`
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Use {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.write_str("USE ")?;
|
|
||||||
match self {
|
|
||||||
Use::Catalog(name) => write!(f, "CATALOG {name}"),
|
|
||||||
Use::Schema(name) => write!(f, "SCHEMA {name}"),
|
|
||||||
Use::Database(name) => write!(f, "DATABASE {name}"),
|
|
||||||
Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
|
|
||||||
Use::Role(name) => write!(f, "ROLE {name}"),
|
|
||||||
Use::SecondaryRoles(secondary_roles) => {
|
|
||||||
write!(f, "SECONDARY ROLES {secondary_roles}")
|
|
||||||
}
|
|
||||||
Use::Object(name) => write!(f, "{name}"),
|
|
||||||
Use::Default => write!(f, "DEFAULT"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Snowflake `SECONDARY ROLES` USE variant
|
|
||||||
/// See: <https://docs.snowflake.com/en/sql-reference/sql/use-secondary-roles>
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum SecondaryRoles {
|
|
||||||
All,
|
|
||||||
None,
|
|
||||||
List(Vec<Ident>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SecondaryRoles {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
SecondaryRoles::All => write!(f, "ALL"),
|
|
||||||
SecondaryRoles::None => write!(f, "NONE"),
|
|
||||||
SecondaryRoles::List(roles) => write!(f, "{}", display_comma_separated(roles)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
1381
src/ast/ddl.rs
1381
src/ast/ddl.rs
File diff suppressed because it is too large
Load diff
384
src/ast/dml.rs
384
src/ast/dml.rs
|
@ -1,27 +1,17 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::{
|
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||||
boxed::Box,
|
|
||||||
format,
|
|
||||||
string::{String, ToString},
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
|
|
||||||
use core::fmt::{self, Display};
|
use core::fmt::{self, Display};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -29,38 +19,16 @@ use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "visitor")]
|
#[cfg(feature = "visitor")]
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
use sqlparser_derive::{Visit, VisitMut};
|
||||||
|
|
||||||
use crate::display_utils::{indented_list, DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
|
|
||||||
|
|
||||||
pub use super::ddl::{ColumnDef, TableConstraint};
|
pub use super::ddl::{ColumnDef, TableConstraint};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
display_comma_separated, display_separated, query::InputFormatClause, Assignment, ClusteredBy,
|
display_comma_separated, display_separated, CommentDef, Expr, FileFormat, FromTable,
|
||||||
CommentDef, CreateTableOptions, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat,
|
HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident, InsertAliases,
|
||||||
HiveIOFormat, HiveRowFormat, Ident, IndexType, InsertAliases, MysqlInsertPriority, ObjectName,
|
MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens, OrderByExpr, Query,
|
||||||
OnCommit, OnInsert, OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem,
|
RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine, TableWithJoins, Tag,
|
||||||
Setting, SqliteOnConflict, StorageSerializationPolicy, TableObject, TableWithJoins, Tag,
|
|
||||||
WrappedCollection,
|
WrappedCollection,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Index column type.
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct IndexColumn {
|
|
||||||
pub column: OrderByExpr,
|
|
||||||
pub operator_class: Option<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for IndexColumn {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.column)?;
|
|
||||||
if let Some(operator_class) = &self.operator_class {
|
|
||||||
write!(f, " {operator_class}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CREATE INDEX statement.
|
/// CREATE INDEX statement.
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -70,15 +38,13 @@ pub struct CreateIndex {
|
||||||
pub name: Option<ObjectName>,
|
pub name: Option<ObjectName>,
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||||
pub table_name: ObjectName,
|
pub table_name: ObjectName,
|
||||||
pub using: Option<IndexType>,
|
pub using: Option<Ident>,
|
||||||
pub columns: Vec<IndexColumn>,
|
pub columns: Vec<OrderByExpr>,
|
||||||
pub unique: bool,
|
pub unique: bool,
|
||||||
pub concurrently: bool,
|
pub concurrently: bool,
|
||||||
pub if_not_exists: bool,
|
pub if_not_exists: bool,
|
||||||
pub include: Vec<Ident>,
|
pub include: Vec<Ident>,
|
||||||
pub nulls_distinct: Option<bool>,
|
pub nulls_distinct: Option<bool>,
|
||||||
/// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
|
|
||||||
pub with: Vec<Expr>,
|
|
||||||
pub predicate: Option<Expr>,
|
pub predicate: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,9 +83,6 @@ impl Display for CreateIndex {
|
||||||
write!(f, " NULLS NOT DISTINCT")?;
|
write!(f, " NULLS NOT DISTINCT")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.with.is_empty() {
|
|
||||||
write!(f, " WITH ({})", display_comma_separated(&self.with))?;
|
|
||||||
}
|
|
||||||
if let Some(predicate) = &self.predicate {
|
if let Some(predicate) = &self.predicate {
|
||||||
write!(f, " WHERE {predicate}")?;
|
write!(f, " WHERE {predicate}")?;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +102,6 @@ pub struct CreateTable {
|
||||||
pub if_not_exists: bool,
|
pub if_not_exists: bool,
|
||||||
pub transient: bool,
|
pub transient: bool,
|
||||||
pub volatile: bool,
|
pub volatile: bool,
|
||||||
pub iceberg: bool,
|
|
||||||
/// Table name
|
/// Table name
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||||
pub name: ObjectName,
|
pub name: ObjectName,
|
||||||
|
@ -148,21 +110,23 @@ pub struct CreateTable {
|
||||||
pub constraints: Vec<TableConstraint>,
|
pub constraints: Vec<TableConstraint>,
|
||||||
pub hive_distribution: HiveDistributionStyle,
|
pub hive_distribution: HiveDistributionStyle,
|
||||||
pub hive_formats: Option<HiveFormat>,
|
pub hive_formats: Option<HiveFormat>,
|
||||||
pub table_options: CreateTableOptions,
|
pub table_properties: Vec<SqlOption>,
|
||||||
|
pub with_options: Vec<SqlOption>,
|
||||||
pub file_format: Option<FileFormat>,
|
pub file_format: Option<FileFormat>,
|
||||||
pub location: Option<String>,
|
pub location: Option<String>,
|
||||||
pub query: Option<Box<Query>>,
|
pub query: Option<Box<Query>>,
|
||||||
pub without_rowid: bool,
|
pub without_rowid: bool,
|
||||||
pub like: Option<ObjectName>,
|
pub like: Option<ObjectName>,
|
||||||
pub clone: Option<ObjectName>,
|
pub clone: Option<ObjectName>,
|
||||||
// For Hive dialect, the table comment is after the column definitions without `=`,
|
pub engine: Option<TableEngine>,
|
||||||
// so the `comment` field is optional and different than the comment field in the general options list.
|
|
||||||
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
|
|
||||||
pub comment: Option<CommentDef>,
|
pub comment: Option<CommentDef>,
|
||||||
|
pub auto_increment_offset: Option<u32>,
|
||||||
|
pub default_charset: Option<String>,
|
||||||
|
pub collation: Option<String>,
|
||||||
pub on_commit: Option<OnCommit>,
|
pub on_commit: Option<OnCommit>,
|
||||||
/// ClickHouse "ON CLUSTER" clause:
|
/// ClickHouse "ON CLUSTER" clause:
|
||||||
/// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
|
/// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
|
||||||
pub on_cluster: Option<Ident>,
|
pub on_cluster: Option<String>,
|
||||||
/// ClickHouse "PRIMARY KEY " clause.
|
/// ClickHouse "PRIMARY KEY " clause.
|
||||||
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
|
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
|
||||||
pub primary_key: Option<Box<Expr>>,
|
pub primary_key: Option<Box<Expr>>,
|
||||||
|
@ -175,17 +139,10 @@ pub struct CreateTable {
|
||||||
pub partition_by: Option<Box<Expr>>,
|
pub partition_by: Option<Box<Expr>>,
|
||||||
/// BigQuery: Table clustering column list.
|
/// BigQuery: Table clustering column list.
|
||||||
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
|
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
|
||||||
/// Snowflake: Table clustering list which contains base column, expressions on base columns.
|
pub cluster_by: Option<WrappedCollection<Vec<Ident>>>,
|
||||||
/// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
|
/// BigQuery: Table options list.
|
||||||
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
|
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
|
||||||
/// Hive: Table clustering column list.
|
pub options: Option<Vec<SqlOption>>,
|
||||||
/// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
|
|
||||||
pub clustered_by: Option<ClusteredBy>,
|
|
||||||
/// Postgres `INHERITs` clause, which contains the list of tables from which
|
|
||||||
/// the new table inherits.
|
|
||||||
/// <https://www.postgresql.org/docs/current/ddl-inherit.html>
|
|
||||||
/// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
|
|
||||||
pub inherits: Option<Vec<ObjectName>>,
|
|
||||||
/// SQLite "STRICT" clause.
|
/// SQLite "STRICT" clause.
|
||||||
/// if the "STRICT" table-option keyword is added to the end, after the closing ")",
|
/// if the "STRICT" table-option keyword is added to the end, after the closing ")",
|
||||||
/// then strict typing rules apply to that table.
|
/// then strict typing rules apply to that table.
|
||||||
|
@ -217,21 +174,6 @@ pub struct CreateTable {
|
||||||
/// Snowflake "WITH TAG" clause
|
/// Snowflake "WITH TAG" clause
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
|
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
|
||||||
pub with_tags: Option<Vec<Tag>>,
|
pub with_tags: Option<Vec<Tag>>,
|
||||||
/// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
|
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
|
|
||||||
pub external_volume: Option<String>,
|
|
||||||
/// Snowflake "BASE_LOCATION" clause for Iceberg tables
|
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
|
|
||||||
pub base_location: Option<String>,
|
|
||||||
/// Snowflake "CATALOG" clause for Iceberg tables
|
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
|
|
||||||
pub catalog: Option<String>,
|
|
||||||
/// Snowflake "CATALOG_SYNC" clause for Iceberg tables
|
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
|
|
||||||
pub catalog_sync: Option<String>,
|
|
||||||
/// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
|
|
||||||
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
|
|
||||||
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for CreateTable {
|
impl Display for CreateTable {
|
||||||
|
@ -245,7 +187,7 @@ impl Display for CreateTable {
|
||||||
// `CREATE TABLE t (a INT) AS SELECT a from t2`
|
// `CREATE TABLE t (a INT) AS SELECT a from t2`
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{iceberg}TABLE {if_not_exists}{name}",
|
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}TABLE {if_not_exists}{name}",
|
||||||
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
|
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
|
||||||
external = if self.external { "EXTERNAL " } else { "" },
|
external = if self.external { "EXTERNAL " } else { "" },
|
||||||
global = self.global
|
global = self.global
|
||||||
|
@ -261,35 +203,25 @@ impl Display for CreateTable {
|
||||||
temporary = if self.temporary { "TEMPORARY " } else { "" },
|
temporary = if self.temporary { "TEMPORARY " } else { "" },
|
||||||
transient = if self.transient { "TRANSIENT " } else { "" },
|
transient = if self.transient { "TRANSIENT " } else { "" },
|
||||||
volatile = if self.volatile { "VOLATILE " } else { "" },
|
volatile = if self.volatile { "VOLATILE " } else { "" },
|
||||||
// Only for Snowflake
|
|
||||||
iceberg = if self.iceberg { "ICEBERG " } else { "" },
|
|
||||||
name = self.name,
|
name = self.name,
|
||||||
)?;
|
)?;
|
||||||
if let Some(on_cluster) = &self.on_cluster {
|
if let Some(on_cluster) = &self.on_cluster {
|
||||||
write!(f, " ON CLUSTER {on_cluster}")?;
|
write!(
|
||||||
|
f,
|
||||||
|
" ON CLUSTER {}",
|
||||||
|
on_cluster.replace('{', "'{").replace('}', "}'")
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
if !self.columns.is_empty() || !self.constraints.is_empty() {
|
if !self.columns.is_empty() || !self.constraints.is_empty() {
|
||||||
f.write_str(" (")?;
|
write!(f, " ({}", display_comma_separated(&self.columns))?;
|
||||||
NewLine.fmt(f)?;
|
|
||||||
Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
|
|
||||||
if !self.columns.is_empty() && !self.constraints.is_empty() {
|
if !self.columns.is_empty() && !self.constraints.is_empty() {
|
||||||
f.write_str(",")?;
|
write!(f, ", ")?;
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
}
|
||||||
Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
|
write!(f, "{})", display_comma_separated(&self.constraints))?;
|
||||||
NewLine.fmt(f)?;
|
|
||||||
f.write_str(")")?;
|
|
||||||
} else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
|
} else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
|
||||||
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
|
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
|
||||||
f.write_str(" ()")?;
|
write!(f, " ()")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hive table comment should be after column definitions, please refer to:
|
|
||||||
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
|
|
||||||
if let Some(comment) = &self.comment {
|
|
||||||
write!(f, " COMMENT '{comment}'")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only for SQLite
|
// Only for SQLite
|
||||||
if self.without_rowid {
|
if self.without_rowid {
|
||||||
write!(f, " WITHOUT ROWID")?;
|
write!(f, " WITHOUT ROWID")?;
|
||||||
|
@ -308,6 +240,19 @@ impl Display for CreateTable {
|
||||||
HiveDistributionStyle::PARTITIONED { columns } => {
|
HiveDistributionStyle::PARTITIONED { columns } => {
|
||||||
write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
|
write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
|
||||||
}
|
}
|
||||||
|
HiveDistributionStyle::CLUSTERED {
|
||||||
|
columns,
|
||||||
|
sorted_by,
|
||||||
|
num_buckets,
|
||||||
|
} => {
|
||||||
|
write!(f, " CLUSTERED BY ({})", display_comma_separated(columns))?;
|
||||||
|
if !sorted_by.is_empty() {
|
||||||
|
write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
|
||||||
|
}
|
||||||
|
if *num_buckets > 0 {
|
||||||
|
write!(f, " INTO {num_buckets} BUCKETS")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
HiveDistributionStyle::SKEWED {
|
HiveDistributionStyle::SKEWED {
|
||||||
columns,
|
columns,
|
||||||
on,
|
on,
|
||||||
|
@ -326,10 +271,6 @@ impl Display for CreateTable {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(clustered_by) = &self.clustered_by {
|
|
||||||
write!(f, " {clustered_by}")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(HiveFormat {
|
if let Some(HiveFormat {
|
||||||
row_format,
|
row_format,
|
||||||
serde_properties,
|
serde_properties,
|
||||||
|
@ -379,22 +320,38 @@ impl Display for CreateTable {
|
||||||
}
|
}
|
||||||
write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
|
write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
|
||||||
}
|
}
|
||||||
|
if !self.table_properties.is_empty() {
|
||||||
match &self.table_options {
|
write!(
|
||||||
options @ CreateTableOptions::With(_)
|
f,
|
||||||
| options @ CreateTableOptions::Plain(_)
|
" TBLPROPERTIES ({})",
|
||||||
| options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
|
display_comma_separated(&self.table_properties)
|
||||||
_ => (),
|
)?;
|
||||||
|
}
|
||||||
|
if !self.with_options.is_empty() {
|
||||||
|
write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
|
||||||
|
}
|
||||||
|
if let Some(engine) = &self.engine {
|
||||||
|
write!(f, " ENGINE={engine}")?;
|
||||||
|
}
|
||||||
|
if let Some(comment_def) = &self.comment {
|
||||||
|
match comment_def {
|
||||||
|
CommentDef::WithEq(comment) => {
|
||||||
|
write!(f, " COMMENT = '{comment}'")?;
|
||||||
|
}
|
||||||
|
CommentDef::WithoutEq(comment) => {
|
||||||
|
write!(f, " COMMENT '{comment}'")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(auto_increment_offset) = self.auto_increment_offset {
|
||||||
|
write!(f, " AUTO_INCREMENT {auto_increment_offset}")?;
|
||||||
|
}
|
||||||
if let Some(primary_key) = &self.primary_key {
|
if let Some(primary_key) = &self.primary_key {
|
||||||
write!(f, " PRIMARY KEY {primary_key}")?;
|
write!(f, " PRIMARY KEY {}", primary_key)?;
|
||||||
}
|
}
|
||||||
if let Some(order_by) = &self.order_by {
|
if let Some(order_by) = &self.order_by {
|
||||||
write!(f, " ORDER BY {order_by}")?;
|
write!(f, " ORDER BY {}", order_by)?;
|
||||||
}
|
|
||||||
if let Some(inherits) = &self.inherits {
|
|
||||||
write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
|
|
||||||
}
|
}
|
||||||
if let Some(partition_by) = self.partition_by.as_ref() {
|
if let Some(partition_by) = self.partition_by.as_ref() {
|
||||||
write!(f, " PARTITION BY {partition_by}")?;
|
write!(f, " PARTITION BY {partition_by}")?;
|
||||||
|
@ -402,31 +359,12 @@ impl Display for CreateTable {
|
||||||
if let Some(cluster_by) = self.cluster_by.as_ref() {
|
if let Some(cluster_by) = self.cluster_by.as_ref() {
|
||||||
write!(f, " CLUSTER BY {cluster_by}")?;
|
write!(f, " CLUSTER BY {cluster_by}")?;
|
||||||
}
|
}
|
||||||
if let options @ CreateTableOptions::Options(_) = &self.table_options {
|
|
||||||
write!(f, " {options}")?;
|
|
||||||
}
|
|
||||||
if let Some(external_volume) = self.external_volume.as_ref() {
|
|
||||||
write!(f, " EXTERNAL_VOLUME = '{external_volume}'")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(catalog) = self.catalog.as_ref() {
|
if let Some(options) = self.options.as_ref() {
|
||||||
write!(f, " CATALOG = '{catalog}'")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.iceberg {
|
|
||||||
if let Some(base_location) = self.base_location.as_ref() {
|
|
||||||
write!(f, " BASE_LOCATION = '{base_location}'")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(catalog_sync) = self.catalog_sync.as_ref() {
|
|
||||||
write!(f, " CATALOG_SYNC = '{catalog_sync}'")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
" STORAGE_SERIALIZATION_POLICY = {storage_serialization_policy}"
|
" OPTIONS({})",
|
||||||
|
display_comma_separated(options.as_slice())
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +418,13 @@ impl Display for CreateTable {
|
||||||
write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
|
write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(default_charset) = &self.default_charset {
|
||||||
|
write!(f, " DEFAULT CHARSET={default_charset}")?;
|
||||||
|
}
|
||||||
|
if let Some(collation) = &self.collation {
|
||||||
|
write!(f, " COLLATE={collation}")?;
|
||||||
|
}
|
||||||
|
|
||||||
if self.on_commit.is_some() {
|
if self.on_commit.is_some() {
|
||||||
let on_commit = match self.on_commit {
|
let on_commit = match self.on_commit {
|
||||||
Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
|
Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
|
||||||
|
@ -511,7 +456,8 @@ pub struct Insert {
|
||||||
/// INTO - optional keyword
|
/// INTO - optional keyword
|
||||||
pub into: bool,
|
pub into: bool,
|
||||||
/// TABLE
|
/// TABLE
|
||||||
pub table: TableObject,
|
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||||
|
pub table_name: ObjectName,
|
||||||
/// table_name as foo (for PostgreSQL)
|
/// table_name as foo (for PostgreSQL)
|
||||||
pub table_alias: Option<Ident>,
|
pub table_alias: Option<Ident>,
|
||||||
/// COLUMNS
|
/// COLUMNS
|
||||||
|
@ -520,15 +466,12 @@ pub struct Insert {
|
||||||
pub overwrite: bool,
|
pub overwrite: bool,
|
||||||
/// A SQL query that specifies what to insert
|
/// A SQL query that specifies what to insert
|
||||||
pub source: Option<Box<Query>>,
|
pub source: Option<Box<Query>>,
|
||||||
/// MySQL `INSERT INTO ... SET`
|
|
||||||
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
|
|
||||||
pub assignments: Vec<Assignment>,
|
|
||||||
/// partitioned insert (Hive)
|
/// partitioned insert (Hive)
|
||||||
pub partitioned: Option<Vec<Expr>>,
|
pub partitioned: Option<Vec<Expr>>,
|
||||||
/// Columns defined after PARTITION
|
/// Columns defined after PARTITION
|
||||||
pub after_columns: Vec<Ident>,
|
pub after_columns: Vec<Ident>,
|
||||||
/// whether the insert has the table keyword (Hive)
|
/// whether the insert has the table keyword (Hive)
|
||||||
pub has_table_keyword: bool,
|
pub table: bool,
|
||||||
pub on: Option<OnInsert>,
|
pub on: Option<OnInsert>,
|
||||||
/// RETURNING
|
/// RETURNING
|
||||||
pub returning: Option<Vec<SelectItem>>,
|
pub returning: Option<Vec<SelectItem>>,
|
||||||
|
@ -538,107 +481,6 @@ pub struct Insert {
|
||||||
pub priority: Option<MysqlInsertPriority>,
|
pub priority: Option<MysqlInsertPriority>,
|
||||||
/// Only for mysql
|
/// Only for mysql
|
||||||
pub insert_alias: Option<InsertAliases>,
|
pub insert_alias: Option<InsertAliases>,
|
||||||
/// Settings used for ClickHouse.
|
|
||||||
///
|
|
||||||
/// ClickHouse syntax: `INSERT INTO tbl SETTINGS format_template_resultset = '/some/path/resultset.format'`
|
|
||||||
///
|
|
||||||
/// [ClickHouse `INSERT INTO`](https://clickhouse.com/docs/en/sql-reference/statements/insert-into)
|
|
||||||
pub settings: Option<Vec<Setting>>,
|
|
||||||
/// Format for `INSERT` statement when not using standard SQL format. Can be e.g. `CSV`,
|
|
||||||
/// `JSON`, `JSONAsString`, `LineAsString` and more.
|
|
||||||
///
|
|
||||||
/// ClickHouse syntax: `INSERT INTO tbl FORMAT JSONEachRow {"foo": 1, "bar": 2}, {"foo": 3}`
|
|
||||||
///
|
|
||||||
/// [ClickHouse formats JSON insert](https://clickhouse.com/docs/en/interfaces/formats#json-inserting-data)
|
|
||||||
pub format_clause: Option<InputFormatClause>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Insert {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let table_name = if let Some(alias) = &self.table_alias {
|
|
||||||
format!("{0} AS {alias}", self.table)
|
|
||||||
} else {
|
|
||||||
self.table.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(on_conflict) = self.or {
|
|
||||||
write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
|
|
||||||
} else {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{start}",
|
|
||||||
start = if self.replace_into {
|
|
||||||
"REPLACE"
|
|
||||||
} else {
|
|
||||||
"INSERT"
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
if let Some(priority) = self.priority {
|
|
||||||
write!(f, " {priority}",)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{ignore}{over}{int}{tbl} {table_name} ",
|
|
||||||
table_name = table_name,
|
|
||||||
ignore = if self.ignore { " IGNORE" } else { "" },
|
|
||||||
over = if self.overwrite { " OVERWRITE" } else { "" },
|
|
||||||
int = if self.into { " INTO" } else { "" },
|
|
||||||
tbl = if self.has_table_keyword { " TABLE" } else { "" },
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if !self.columns.is_empty() {
|
|
||||||
write!(f, "({})", display_comma_separated(&self.columns))?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
|
||||||
if let Some(ref parts) = self.partitioned {
|
|
||||||
if !parts.is_empty() {
|
|
||||||
write!(f, "PARTITION ({})", display_comma_separated(parts))?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !self.after_columns.is_empty() {
|
|
||||||
write!(f, "({})", display_comma_separated(&self.after_columns))?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(settings) = &self.settings {
|
|
||||||
write!(f, "SETTINGS {}", display_comma_separated(settings))?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(source) = &self.source {
|
|
||||||
source.fmt(f)?;
|
|
||||||
} else if !self.assignments.is_empty() {
|
|
||||||
write!(f, "SET")?;
|
|
||||||
indented_list(f, &self.assignments)?;
|
|
||||||
} else if let Some(format_clause) = &self.format_clause {
|
|
||||||
format_clause.fmt(f)?;
|
|
||||||
} else if self.columns.is_empty() {
|
|
||||||
write!(f, "DEFAULT VALUES")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(insert_alias) = &self.insert_alias {
|
|
||||||
write!(f, " AS {0}", insert_alias.row_alias)?;
|
|
||||||
|
|
||||||
if let Some(col_aliases) = &insert_alias.col_aliases {
|
|
||||||
if !col_aliases.is_empty() {
|
|
||||||
write!(f, " ({})", display_comma_separated(col_aliases))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(on) = &self.on {
|
|
||||||
write!(f, "{on}")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(returning) = &self.returning {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("RETURNING")?;
|
|
||||||
indented_list(f, returning)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DELETE statement.
|
/// DELETE statement.
|
||||||
|
@ -661,49 +503,3 @@ pub struct Delete {
|
||||||
/// LIMIT (MySQL)
|
/// LIMIT (MySQL)
|
||||||
pub limit: Option<Expr>,
|
pub limit: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Delete {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.write_str("DELETE")?;
|
|
||||||
if !self.tables.is_empty() {
|
|
||||||
indented_list(f, &self.tables)?;
|
|
||||||
}
|
|
||||||
match &self.from {
|
|
||||||
FromTable::WithFromKeyword(from) => {
|
|
||||||
f.write_str(" FROM")?;
|
|
||||||
indented_list(f, from)?;
|
|
||||||
}
|
|
||||||
FromTable::WithoutKeyword(from) => {
|
|
||||||
indented_list(f, from)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(using) = &self.using {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("USING")?;
|
|
||||||
indented_list(f, using)?;
|
|
||||||
}
|
|
||||||
if let Some(selection) = &self.selection {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("WHERE")?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
Indent(selection).fmt(f)?;
|
|
||||||
}
|
|
||||||
if let Some(returning) = &self.returning {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("RETURNING")?;
|
|
||||||
indented_list(f, returning)?;
|
|
||||||
}
|
|
||||||
if !self.order_by.is_empty() {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("ORDER BY")?;
|
|
||||||
indented_list(f, &self.order_by)?;
|
|
||||||
}
|
|
||||||
if let Some(limit) = &self.limit {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("LIMIT")?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
Indent(limit).fmt(f)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
|
||||||
use core::fmt::{self, Debug, Formatter};
|
|
||||||
use core::hash::{Hash, Hasher};
|
|
||||||
|
|
||||||
use crate::tokenizer::TokenWithSpan;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[cfg(feature = "visitor")]
|
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
|
||||||
|
|
||||||
/// A wrapper over [`TokenWithSpan`]s that ignores the token and source
|
|
||||||
/// location in comparisons and hashing.
|
|
||||||
///
|
|
||||||
/// This type is used when the token and location is not relevant for semantics,
|
|
||||||
/// but is still needed for accurate source location tracking, for example, in
|
|
||||||
/// the nodes in the [ast](crate::ast) module.
|
|
||||||
///
|
|
||||||
/// Note: **All** `AttachedTokens` are equal.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Same token, different location are equal
|
|
||||||
/// ```
|
|
||||||
/// # use sqlparser::ast::helpers::attached_token::AttachedToken;
|
|
||||||
/// # use sqlparser::tokenizer::{Location, Span, Token, TokenWithLocation};
|
|
||||||
/// // commas @ line 1, column 10
|
|
||||||
/// let tok1 = TokenWithLocation::new(
|
|
||||||
/// Token::Comma,
|
|
||||||
/// Span::new(Location::new(1, 10), Location::new(1, 11)),
|
|
||||||
/// );
|
|
||||||
/// // commas @ line 2, column 20
|
|
||||||
/// let tok2 = TokenWithLocation::new(
|
|
||||||
/// Token::Comma,
|
|
||||||
/// Span::new(Location::new(2, 20), Location::new(2, 21)),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// assert_ne!(tok1, tok2); // token with locations are *not* equal
|
|
||||||
/// assert_eq!(AttachedToken(tok1), AttachedToken(tok2)); // attached tokens are
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Different token, different location are equal 🤯
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use sqlparser::ast::helpers::attached_token::AttachedToken;
|
|
||||||
/// # use sqlparser::tokenizer::{Location, Span, Token, TokenWithLocation};
|
|
||||||
/// // commas @ line 1, column 10
|
|
||||||
/// let tok1 = TokenWithLocation::new(
|
|
||||||
/// Token::Comma,
|
|
||||||
/// Span::new(Location::new(1, 10), Location::new(1, 11)),
|
|
||||||
/// );
|
|
||||||
/// // period @ line 2, column 20
|
|
||||||
/// let tok2 = TokenWithLocation::new(
|
|
||||||
/// Token::Period,
|
|
||||||
/// Span::new(Location::new(2, 10), Location::new(2, 21)),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// assert_ne!(tok1, tok2); // token with locations are *not* equal
|
|
||||||
/// assert_eq!(AttachedToken(tok1), AttachedToken(tok2)); // attached tokens are
|
|
||||||
/// ```
|
|
||||||
/// // period @ line 2, column 20
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct AttachedToken(pub TokenWithSpan);
|
|
||||||
|
|
||||||
impl AttachedToken {
|
|
||||||
/// Return a new Empty AttachedToken
|
|
||||||
pub fn empty() -> Self {
|
|
||||||
AttachedToken(TokenWithSpan::new_eof())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conditional Implementations
|
|
||||||
impl Debug for AttachedToken {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blanket Implementations
|
|
||||||
impl PartialEq for AttachedToken {
|
|
||||||
fn eq(&self, _: &Self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for AttachedToken {}
|
|
||||||
|
|
||||||
impl PartialOrd for AttachedToken {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for AttachedToken {
|
|
||||||
fn cmp(&self, _: &Self) -> Ordering {
|
|
||||||
Ordering::Equal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for AttachedToken {
|
|
||||||
fn hash<H: Hasher>(&self, _state: &mut H) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TokenWithSpan> for AttachedToken {
|
|
||||||
fn from(value: TokenWithSpan) -> Self {
|
|
||||||
AttachedToken(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AttachedToken> for TokenWithSpan {
|
|
||||||
fn from(value: AttachedToken) -> Self {
|
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! Key-value options for SQL statements.
|
|
||||||
//! See [this page](https://docs.snowflake.com/en/sql-reference/commands-data-loading) for more details.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use alloc::string::String;
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::fmt;
|
|
||||||
use core::fmt::Formatter;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[cfg(feature = "visitor")]
|
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct KeyValueOptions {
|
|
||||||
pub options: Vec<KeyValueOption>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum KeyValueOptionType {
|
|
||||||
STRING,
|
|
||||||
BOOLEAN,
|
|
||||||
ENUM,
|
|
||||||
NUMBER,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct KeyValueOption {
|
|
||||||
pub option_name: String,
|
|
||||||
pub option_type: KeyValueOptionType,
|
|
||||||
pub value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for KeyValueOptions {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
if !self.options.is_empty() {
|
|
||||||
let mut first = false;
|
|
||||||
for option in &self.options {
|
|
||||||
if !first {
|
|
||||||
first = true;
|
|
||||||
} else {
|
|
||||||
f.write_str(" ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{option}")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for KeyValueOption {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self.option_type {
|
|
||||||
KeyValueOptionType::STRING => {
|
|
||||||
write!(f, "{}='{}'", self.option_name, self.value)?;
|
|
||||||
}
|
|
||||||
KeyValueOptionType::ENUM | KeyValueOptionType::BOOLEAN | KeyValueOptionType::NUMBER => {
|
|
||||||
write!(f, "{}={}", self.option_name, self.value)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +1,2 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
pub mod attached_token;
|
|
||||||
pub mod key_value_options;
|
|
||||||
pub mod stmt_create_table;
|
pub mod stmt_create_table;
|
||||||
pub mod stmt_data_loading;
|
pub mod stmt_data_loading;
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
||||||
|
|
||||||
|
@ -26,12 +9,10 @@ use sqlparser_derive::{Visit, VisitMut};
|
||||||
|
|
||||||
use super::super::dml::CreateTable;
|
use super::super::dml::CreateTable;
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
ClusteredBy, ColumnDef, CommentDef, CreateTableOptions, Expr, FileFormat,
|
ColumnDef, CommentDef, Expr, FileFormat, HiveDistributionStyle, HiveFormat, Ident, ObjectName,
|
||||||
HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, OneOrManyWithParens, Query,
|
OnCommit, OneOrManyWithParens, Query, RowAccessPolicy, SqlOption, Statement, TableConstraint,
|
||||||
RowAccessPolicy, Statement, StorageSerializationPolicy, TableConstraint, Tag,
|
TableEngine, Tag, WrappedCollection,
|
||||||
WrappedCollection,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::parser::ParserError;
|
use crate::parser::ParserError;
|
||||||
|
|
||||||
/// Builder for create table statement variant ([1]).
|
/// Builder for create table statement variant ([1]).
|
||||||
|
@ -44,11 +25,12 @@ use crate::parser::ParserError;
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use sqlparser::ast::helpers::stmt_create_table::CreateTableBuilder;
|
/// use sqlparser::ast::helpers::stmt_create_table::CreateTableBuilder;
|
||||||
/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName};
|
/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName};
|
||||||
/// let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]))
|
/// let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")]))
|
||||||
/// .if_not_exists(true)
|
/// .if_not_exists(true)
|
||||||
/// .columns(vec![ColumnDef {
|
/// .columns(vec![ColumnDef {
|
||||||
/// name: Ident::new("c1"),
|
/// name: Ident::new("c1"),
|
||||||
/// data_type: DataType::Int(None),
|
/// data_type: DataType::Int(None),
|
||||||
|
/// collation: None,
|
||||||
/// options: vec![],
|
/// options: vec![],
|
||||||
/// }]);
|
/// }]);
|
||||||
/// // You can access internal elements with ease
|
/// // You can access internal elements with ease
|
||||||
|
@ -72,27 +54,31 @@ pub struct CreateTableBuilder {
|
||||||
pub if_not_exists: bool,
|
pub if_not_exists: bool,
|
||||||
pub transient: bool,
|
pub transient: bool,
|
||||||
pub volatile: bool,
|
pub volatile: bool,
|
||||||
pub iceberg: bool,
|
|
||||||
pub name: ObjectName,
|
pub name: ObjectName,
|
||||||
pub columns: Vec<ColumnDef>,
|
pub columns: Vec<ColumnDef>,
|
||||||
pub constraints: Vec<TableConstraint>,
|
pub constraints: Vec<TableConstraint>,
|
||||||
pub hive_distribution: HiveDistributionStyle,
|
pub hive_distribution: HiveDistributionStyle,
|
||||||
pub hive_formats: Option<HiveFormat>,
|
pub hive_formats: Option<HiveFormat>,
|
||||||
|
pub table_properties: Vec<SqlOption>,
|
||||||
|
pub with_options: Vec<SqlOption>,
|
||||||
pub file_format: Option<FileFormat>,
|
pub file_format: Option<FileFormat>,
|
||||||
pub location: Option<String>,
|
pub location: Option<String>,
|
||||||
pub query: Option<Box<Query>>,
|
pub query: Option<Box<Query>>,
|
||||||
pub without_rowid: bool,
|
pub without_rowid: bool,
|
||||||
pub like: Option<ObjectName>,
|
pub like: Option<ObjectName>,
|
||||||
pub clone: Option<ObjectName>,
|
pub clone: Option<ObjectName>,
|
||||||
|
pub engine: Option<TableEngine>,
|
||||||
pub comment: Option<CommentDef>,
|
pub comment: Option<CommentDef>,
|
||||||
|
pub auto_increment_offset: Option<u32>,
|
||||||
|
pub default_charset: Option<String>,
|
||||||
|
pub collation: Option<String>,
|
||||||
pub on_commit: Option<OnCommit>,
|
pub on_commit: Option<OnCommit>,
|
||||||
pub on_cluster: Option<Ident>,
|
pub on_cluster: Option<String>,
|
||||||
pub primary_key: Option<Box<Expr>>,
|
pub primary_key: Option<Box<Expr>>,
|
||||||
pub order_by: Option<OneOrManyWithParens<Expr>>,
|
pub order_by: Option<OneOrManyWithParens<Expr>>,
|
||||||
pub partition_by: Option<Box<Expr>>,
|
pub partition_by: Option<Box<Expr>>,
|
||||||
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
|
pub cluster_by: Option<WrappedCollection<Vec<Ident>>>,
|
||||||
pub clustered_by: Option<ClusteredBy>,
|
pub options: Option<Vec<SqlOption>>,
|
||||||
pub inherits: Option<Vec<ObjectName>>,
|
|
||||||
pub strict: bool,
|
pub strict: bool,
|
||||||
pub copy_grants: bool,
|
pub copy_grants: bool,
|
||||||
pub enable_schema_evolution: Option<bool>,
|
pub enable_schema_evolution: Option<bool>,
|
||||||
|
@ -103,12 +89,6 @@ pub struct CreateTableBuilder {
|
||||||
pub with_aggregation_policy: Option<ObjectName>,
|
pub with_aggregation_policy: Option<ObjectName>,
|
||||||
pub with_row_access_policy: Option<RowAccessPolicy>,
|
pub with_row_access_policy: Option<RowAccessPolicy>,
|
||||||
pub with_tags: Option<Vec<Tag>>,
|
pub with_tags: Option<Vec<Tag>>,
|
||||||
pub base_location: Option<String>,
|
|
||||||
pub external_volume: Option<String>,
|
|
||||||
pub catalog: Option<String>,
|
|
||||||
pub catalog_sync: Option<String>,
|
|
||||||
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
|
|
||||||
pub table_options: CreateTableOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateTableBuilder {
|
impl CreateTableBuilder {
|
||||||
|
@ -121,27 +101,31 @@ impl CreateTableBuilder {
|
||||||
if_not_exists: false,
|
if_not_exists: false,
|
||||||
transient: false,
|
transient: false,
|
||||||
volatile: false,
|
volatile: false,
|
||||||
iceberg: false,
|
|
||||||
name,
|
name,
|
||||||
columns: vec![],
|
columns: vec![],
|
||||||
constraints: vec![],
|
constraints: vec![],
|
||||||
hive_distribution: HiveDistributionStyle::NONE,
|
hive_distribution: HiveDistributionStyle::NONE,
|
||||||
hive_formats: None,
|
hive_formats: None,
|
||||||
|
table_properties: vec![],
|
||||||
|
with_options: vec![],
|
||||||
file_format: None,
|
file_format: None,
|
||||||
location: None,
|
location: None,
|
||||||
query: None,
|
query: None,
|
||||||
without_rowid: false,
|
without_rowid: false,
|
||||||
like: None,
|
like: None,
|
||||||
clone: None,
|
clone: None,
|
||||||
|
engine: None,
|
||||||
comment: None,
|
comment: None,
|
||||||
|
auto_increment_offset: None,
|
||||||
|
default_charset: None,
|
||||||
|
collation: None,
|
||||||
on_commit: None,
|
on_commit: None,
|
||||||
on_cluster: None,
|
on_cluster: None,
|
||||||
primary_key: None,
|
primary_key: None,
|
||||||
order_by: None,
|
order_by: None,
|
||||||
partition_by: None,
|
partition_by: None,
|
||||||
cluster_by: None,
|
cluster_by: None,
|
||||||
clustered_by: None,
|
options: None,
|
||||||
inherits: None,
|
|
||||||
strict: false,
|
strict: false,
|
||||||
copy_grants: false,
|
copy_grants: false,
|
||||||
enable_schema_evolution: None,
|
enable_schema_evolution: None,
|
||||||
|
@ -152,12 +136,6 @@ impl CreateTableBuilder {
|
||||||
with_aggregation_policy: None,
|
with_aggregation_policy: None,
|
||||||
with_row_access_policy: None,
|
with_row_access_policy: None,
|
||||||
with_tags: None,
|
with_tags: None,
|
||||||
base_location: None,
|
|
||||||
external_volume: None,
|
|
||||||
catalog: None,
|
|
||||||
catalog_sync: None,
|
|
||||||
storage_serialization_policy: None,
|
|
||||||
table_options: CreateTableOptions::None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn or_replace(mut self, or_replace: bool) -> Self {
|
pub fn or_replace(mut self, or_replace: bool) -> Self {
|
||||||
|
@ -195,11 +173,6 @@ impl CreateTableBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iceberg(mut self, iceberg: bool) -> Self {
|
|
||||||
self.iceberg = iceberg;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
|
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
|
||||||
self.columns = columns;
|
self.columns = columns;
|
||||||
self
|
self
|
||||||
|
@ -220,6 +193,15 @@ impl CreateTableBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn table_properties(mut self, table_properties: Vec<SqlOption>) -> Self {
|
||||||
|
self.table_properties = table_properties;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_options(mut self, with_options: Vec<SqlOption>) -> Self {
|
||||||
|
self.with_options = with_options;
|
||||||
|
self
|
||||||
|
}
|
||||||
pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
|
pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
|
||||||
self.file_format = file_format;
|
self.file_format = file_format;
|
||||||
self
|
self
|
||||||
|
@ -249,17 +231,37 @@ impl CreateTableBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
|
pub fn engine(mut self, engine: Option<TableEngine>) -> Self {
|
||||||
|
self.engine = engine;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn comment(mut self, comment: Option<CommentDef>) -> Self {
|
||||||
self.comment = comment;
|
self.comment = comment;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn auto_increment_offset(mut self, offset: Option<u32>) -> Self {
|
||||||
|
self.auto_increment_offset = offset;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_charset(mut self, default_charset: Option<String>) -> Self {
|
||||||
|
self.default_charset = default_charset;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collation(mut self, collation: Option<String>) -> Self {
|
||||||
|
self.collation = collation;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
|
pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
|
||||||
self.on_commit = on_commit;
|
self.on_commit = on_commit;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
|
pub fn on_cluster(mut self, on_cluster: Option<String>) -> Self {
|
||||||
self.on_cluster = on_cluster;
|
self.on_cluster = on_cluster;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -279,18 +281,13 @@ impl CreateTableBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
|
pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Ident>>>) -> Self {
|
||||||
self.cluster_by = cluster_by;
|
self.cluster_by = cluster_by;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
|
pub fn options(mut self, options: Option<Vec<SqlOption>>) -> Self {
|
||||||
self.clustered_by = clustered_by;
|
self.options = options;
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
|
|
||||||
self.inherits = inherits;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,39 +347,6 @@ impl CreateTableBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base_location(mut self, base_location: Option<String>) -> Self {
|
|
||||||
self.base_location = base_location;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
|
|
||||||
self.external_volume = external_volume;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn catalog(mut self, catalog: Option<String>) -> Self {
|
|
||||||
self.catalog = catalog;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
|
|
||||||
self.catalog_sync = catalog_sync;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn storage_serialization_policy(
|
|
||||||
mut self,
|
|
||||||
storage_serialization_policy: Option<StorageSerializationPolicy>,
|
|
||||||
) -> Self {
|
|
||||||
self.storage_serialization_policy = storage_serialization_policy;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
|
|
||||||
self.table_options = table_options;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> Statement {
|
pub fn build(self) -> Statement {
|
||||||
Statement::CreateTable(CreateTable {
|
Statement::CreateTable(CreateTable {
|
||||||
or_replace: self.or_replace,
|
or_replace: self.or_replace,
|
||||||
|
@ -392,27 +356,31 @@ impl CreateTableBuilder {
|
||||||
if_not_exists: self.if_not_exists,
|
if_not_exists: self.if_not_exists,
|
||||||
transient: self.transient,
|
transient: self.transient,
|
||||||
volatile: self.volatile,
|
volatile: self.volatile,
|
||||||
iceberg: self.iceberg,
|
|
||||||
name: self.name,
|
name: self.name,
|
||||||
columns: self.columns,
|
columns: self.columns,
|
||||||
constraints: self.constraints,
|
constraints: self.constraints,
|
||||||
hive_distribution: self.hive_distribution,
|
hive_distribution: self.hive_distribution,
|
||||||
hive_formats: self.hive_formats,
|
hive_formats: self.hive_formats,
|
||||||
|
table_properties: self.table_properties,
|
||||||
|
with_options: self.with_options,
|
||||||
file_format: self.file_format,
|
file_format: self.file_format,
|
||||||
location: self.location,
|
location: self.location,
|
||||||
query: self.query,
|
query: self.query,
|
||||||
without_rowid: self.without_rowid,
|
without_rowid: self.without_rowid,
|
||||||
like: self.like,
|
like: self.like,
|
||||||
clone: self.clone,
|
clone: self.clone,
|
||||||
|
engine: self.engine,
|
||||||
comment: self.comment,
|
comment: self.comment,
|
||||||
|
auto_increment_offset: self.auto_increment_offset,
|
||||||
|
default_charset: self.default_charset,
|
||||||
|
collation: self.collation,
|
||||||
on_commit: self.on_commit,
|
on_commit: self.on_commit,
|
||||||
on_cluster: self.on_cluster,
|
on_cluster: self.on_cluster,
|
||||||
primary_key: self.primary_key,
|
primary_key: self.primary_key,
|
||||||
order_by: self.order_by,
|
order_by: self.order_by,
|
||||||
partition_by: self.partition_by,
|
partition_by: self.partition_by,
|
||||||
cluster_by: self.cluster_by,
|
cluster_by: self.cluster_by,
|
||||||
clustered_by: self.clustered_by,
|
options: self.options,
|
||||||
inherits: self.inherits,
|
|
||||||
strict: self.strict,
|
strict: self.strict,
|
||||||
copy_grants: self.copy_grants,
|
copy_grants: self.copy_grants,
|
||||||
enable_schema_evolution: self.enable_schema_evolution,
|
enable_schema_evolution: self.enable_schema_evolution,
|
||||||
|
@ -423,12 +391,6 @@ impl CreateTableBuilder {
|
||||||
with_aggregation_policy: self.with_aggregation_policy,
|
with_aggregation_policy: self.with_aggregation_policy,
|
||||||
with_row_access_policy: self.with_row_access_policy,
|
with_row_access_policy: self.with_row_access_policy,
|
||||||
with_tags: self.with_tags,
|
with_tags: self.with_tags,
|
||||||
base_location: self.base_location,
|
|
||||||
external_volume: self.external_volume,
|
|
||||||
catalog: self.catalog,
|
|
||||||
catalog_sync: self.catalog_sync,
|
|
||||||
storage_serialization_policy: self.storage_serialization_policy,
|
|
||||||
table_options: self.table_options,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,27 +410,31 @@ impl TryFrom<Statement> for CreateTableBuilder {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
transient,
|
transient,
|
||||||
volatile,
|
volatile,
|
||||||
iceberg,
|
|
||||||
name,
|
name,
|
||||||
columns,
|
columns,
|
||||||
constraints,
|
constraints,
|
||||||
hive_distribution,
|
hive_distribution,
|
||||||
hive_formats,
|
hive_formats,
|
||||||
|
table_properties,
|
||||||
|
with_options,
|
||||||
file_format,
|
file_format,
|
||||||
location,
|
location,
|
||||||
query,
|
query,
|
||||||
without_rowid,
|
without_rowid,
|
||||||
like,
|
like,
|
||||||
clone,
|
clone,
|
||||||
|
engine,
|
||||||
comment,
|
comment,
|
||||||
|
auto_increment_offset,
|
||||||
|
default_charset,
|
||||||
|
collation,
|
||||||
on_commit,
|
on_commit,
|
||||||
on_cluster,
|
on_cluster,
|
||||||
primary_key,
|
primary_key,
|
||||||
order_by,
|
order_by,
|
||||||
partition_by,
|
partition_by,
|
||||||
cluster_by,
|
cluster_by,
|
||||||
clustered_by,
|
options,
|
||||||
inherits,
|
|
||||||
strict,
|
strict,
|
||||||
copy_grants,
|
copy_grants,
|
||||||
enable_schema_evolution,
|
enable_schema_evolution,
|
||||||
|
@ -479,12 +445,6 @@ impl TryFrom<Statement> for CreateTableBuilder {
|
||||||
with_aggregation_policy,
|
with_aggregation_policy,
|
||||||
with_row_access_policy,
|
with_row_access_policy,
|
||||||
with_tags,
|
with_tags,
|
||||||
base_location,
|
|
||||||
external_volume,
|
|
||||||
catalog,
|
|
||||||
catalog_sync,
|
|
||||||
storage_serialization_policy,
|
|
||||||
table_options,
|
|
||||||
}) => Ok(Self {
|
}) => Ok(Self {
|
||||||
or_replace,
|
or_replace,
|
||||||
temporary,
|
temporary,
|
||||||
|
@ -497,23 +457,27 @@ impl TryFrom<Statement> for CreateTableBuilder {
|
||||||
constraints,
|
constraints,
|
||||||
hive_distribution,
|
hive_distribution,
|
||||||
hive_formats,
|
hive_formats,
|
||||||
|
table_properties,
|
||||||
|
with_options,
|
||||||
file_format,
|
file_format,
|
||||||
location,
|
location,
|
||||||
query,
|
query,
|
||||||
without_rowid,
|
without_rowid,
|
||||||
like,
|
like,
|
||||||
clone,
|
clone,
|
||||||
|
engine,
|
||||||
comment,
|
comment,
|
||||||
|
auto_increment_offset,
|
||||||
|
default_charset,
|
||||||
|
collation,
|
||||||
on_commit,
|
on_commit,
|
||||||
on_cluster,
|
on_cluster,
|
||||||
primary_key,
|
primary_key,
|
||||||
order_by,
|
order_by,
|
||||||
partition_by,
|
partition_by,
|
||||||
cluster_by,
|
cluster_by,
|
||||||
clustered_by,
|
options,
|
||||||
inherits,
|
|
||||||
strict,
|
strict,
|
||||||
iceberg,
|
|
||||||
copy_grants,
|
copy_grants,
|
||||||
enable_schema_evolution,
|
enable_schema_evolution,
|
||||||
change_tracking,
|
change_tracking,
|
||||||
|
@ -524,12 +488,6 @@ impl TryFrom<Statement> for CreateTableBuilder {
|
||||||
with_row_access_policy,
|
with_row_access_policy,
|
||||||
with_tags,
|
with_tags,
|
||||||
volatile,
|
volatile,
|
||||||
base_location,
|
|
||||||
external_volume,
|
|
||||||
catalog,
|
|
||||||
catalog_sync,
|
|
||||||
storage_serialization_policy,
|
|
||||||
table_options,
|
|
||||||
}),
|
}),
|
||||||
_ => Err(ParserError::ParserError(format!(
|
_ => Err(ParserError::ParserError(format!(
|
||||||
"Expected create table statement, but received: {stmt}"
|
"Expected create table statement, but received: {stmt}"
|
||||||
|
@ -542,9 +500,8 @@ impl TryFrom<Statement> for CreateTableBuilder {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct CreateTableConfiguration {
|
pub(crate) struct CreateTableConfiguration {
|
||||||
pub partition_by: Option<Box<Expr>>,
|
pub partition_by: Option<Box<Expr>>,
|
||||||
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
|
pub cluster_by: Option<WrappedCollection<Vec<Ident>>>,
|
||||||
pub inherits: Option<Vec<ObjectName>>,
|
pub options: Option<Vec<SqlOption>>,
|
||||||
pub table_options: CreateTableOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -555,7 +512,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_from_valid_statement() {
|
pub fn test_from_valid_statement() {
|
||||||
let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
|
let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")]));
|
||||||
|
|
||||||
let stmt = builder.clone().build();
|
let stmt = builder.clone().build();
|
||||||
|
|
||||||
|
@ -564,11 +521,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_from_invalid_statement() {
|
pub fn test_from_invalid_statement() {
|
||||||
let stmt = Statement::Commit {
|
let stmt = Statement::Commit { chain: false };
|
||||||
chain: false,
|
|
||||||
end: false,
|
|
||||||
modifier: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CreateTableBuilder::try_from(stmt).unwrap_err(),
|
CreateTableBuilder::try_from(stmt).unwrap_err(),
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! AST types specific to loading and unloading syntax, like one available in Snowflake which
|
//! AST types specific to loading and unloading syntax, like one available in Snowflake which
|
||||||
//! contains: STAGE ddl operations, PUT upload or COPY INTO
|
//! contains: STAGE ddl operations, PUT upload or COPY INTO
|
||||||
|
@ -21,13 +16,15 @@
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use core::fmt::Formatter;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ast::helpers::key_value_options::KeyValueOptions;
|
use crate::ast::Ident;
|
||||||
use crate::ast::{Ident, ObjectName, SelectItem};
|
|
||||||
#[cfg(feature = "visitor")]
|
#[cfg(feature = "visitor")]
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
use sqlparser_derive::{Visit, VisitMut};
|
||||||
|
|
||||||
|
@ -36,29 +33,35 @@ use sqlparser_derive::{Visit, VisitMut};
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub struct StageParamsObject {
|
pub struct StageParamsObject {
|
||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
pub encryption: KeyValueOptions,
|
pub encryption: DataLoadingOptions,
|
||||||
pub endpoint: Option<String>,
|
pub endpoint: Option<String>,
|
||||||
pub storage_integration: Option<String>,
|
pub storage_integration: Option<String>,
|
||||||
pub credentials: KeyValueOptions,
|
pub credentials: DataLoadingOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This enum enables support for both standard SQL select item expressions
|
|
||||||
/// and Snowflake-specific ones for data loading.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub enum StageLoadSelectItemKind {
|
pub struct DataLoadingOptions {
|
||||||
SelectItem(SelectItem),
|
pub options: Vec<DataLoadingOption>,
|
||||||
StageLoadSelectItem(StageLoadSelectItem),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for StageLoadSelectItemKind {
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
match &self {
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
StageLoadSelectItemKind::SelectItem(item) => write!(f, "{item}"),
|
pub enum DataLoadingOptionType {
|
||||||
StageLoadSelectItemKind::StageLoadSelectItem(item) => write!(f, "{item}"),
|
STRING,
|
||||||
}
|
BOOLEAN,
|
||||||
}
|
ENUM,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct DataLoadingOption {
|
||||||
|
pub option_name: String,
|
||||||
|
pub option_type: DataLoadingOptionType,
|
||||||
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -97,6 +100,39 @@ impl fmt::Display for StageParamsObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DataLoadingOptions {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
if !self.options.is_empty() {
|
||||||
|
for option in &self.options {
|
||||||
|
write!(f, "{}", option)?;
|
||||||
|
if !option.eq(self.options.last().unwrap()) {
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DataLoadingOption {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self.option_type {
|
||||||
|
DataLoadingOptionType::STRING => {
|
||||||
|
write!(f, "{}='{}'", self.option_name, self.value)?;
|
||||||
|
}
|
||||||
|
DataLoadingOptionType::ENUM => {
|
||||||
|
// single quote is omitted
|
||||||
|
write!(f, "{}={}", self.option_name, self.value)?;
|
||||||
|
}
|
||||||
|
DataLoadingOptionType::BOOLEAN => {
|
||||||
|
// single quote is omitted
|
||||||
|
write!(f, "{}={}", self.option_name, self.value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for StageLoadSelectItem {
|
impl fmt::Display for StageLoadSelectItem {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.alias.is_some() {
|
if self.alias.is_some() {
|
||||||
|
@ -112,22 +148,3 @@ impl fmt::Display for StageLoadSelectItem {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct FileStagingCommand {
|
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
|
||||||
pub stage: ObjectName,
|
|
||||||
pub pattern: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FileStagingCommand {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.stage)?;
|
|
||||||
if let Some(pattern) = self.pattern.as_ref() {
|
|
||||||
write!(f, " PATTERN='{pattern}'")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
5298
src/ast/mod.rs
5298
src/ast/mod.rs
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
@ -51,23 +46,6 @@ pub enum UnaryOperator {
|
||||||
PGPrefixFactorial,
|
PGPrefixFactorial,
|
||||||
/// Absolute value, e.g. `@ -9` (PostgreSQL-specific)
|
/// Absolute value, e.g. `@ -9` (PostgreSQL-specific)
|
||||||
PGAbs,
|
PGAbs,
|
||||||
/// Unary logical not operator: e.g. `! false` (Hive-specific)
|
|
||||||
BangNot,
|
|
||||||
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
Hash,
|
|
||||||
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
AtDashAt,
|
|
||||||
/// `@@` Center (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
DoubleAt,
|
|
||||||
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionDash,
|
|
||||||
/// `?|` Is vertical? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionPipe,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for UnaryOperator {
|
impl fmt::Display for UnaryOperator {
|
||||||
|
@ -82,12 +60,6 @@ impl fmt::Display for UnaryOperator {
|
||||||
UnaryOperator::PGPostfixFactorial => "!",
|
UnaryOperator::PGPostfixFactorial => "!",
|
||||||
UnaryOperator::PGPrefixFactorial => "!!",
|
UnaryOperator::PGPrefixFactorial => "!!",
|
||||||
UnaryOperator::PGAbs => "@",
|
UnaryOperator::PGAbs => "@",
|
||||||
UnaryOperator::BangNot => "!",
|
|
||||||
UnaryOperator::Hash => "#",
|
|
||||||
UnaryOperator::AtDashAt => "@-@",
|
|
||||||
UnaryOperator::DoubleAt => "@@",
|
|
||||||
UnaryOperator::QuestionDash => "?-",
|
|
||||||
UnaryOperator::QuestionPipe => "?|",
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,11 +111,6 @@ pub enum BinaryOperator {
|
||||||
DuckIntegerDivide,
|
DuckIntegerDivide,
|
||||||
/// MySQL [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html) integer division
|
/// MySQL [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html) integer division
|
||||||
MyIntegerDivide,
|
MyIntegerDivide,
|
||||||
/// MATCH operator, e.g. `a MATCH b` (SQLite-specific)
|
|
||||||
/// See <https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators>
|
|
||||||
Match,
|
|
||||||
/// REGEXP operator, e.g. `a REGEXP b` (SQLite-specific)
|
|
||||||
Regexp,
|
|
||||||
/// Support for custom operators (such as Postgres custom operators)
|
/// Support for custom operators (such as Postgres custom operators)
|
||||||
Custom(String),
|
Custom(String),
|
||||||
/// Bitwise XOR, e.g. `a # b` (PostgreSQL-specific)
|
/// Bitwise XOR, e.g. `a # b` (PostgreSQL-specific)
|
||||||
|
@ -184,7 +151,7 @@ pub enum BinaryOperator {
|
||||||
Arrow,
|
Arrow,
|
||||||
/// The `->>` operator.
|
/// The `->>` operator.
|
||||||
///
|
///
|
||||||
/// On PostgreSQL, this operator extracts a JSON object field or JSON
|
/// On PostgreSQL, this operator that extracts a JSON object field or JSON
|
||||||
/// array element and converts it to text, for example `'{"a":"b"}'::json
|
/// array element and converts it to text, for example `'{"a":"b"}'::json
|
||||||
/// ->> 'a'` or `[1, 2, 3]'::json ->> 2`.
|
/// ->> 'a'` or `[1, 2, 3]'::json ->> 2`.
|
||||||
///
|
///
|
||||||
|
@ -273,62 +240,6 @@ pub enum BinaryOperator {
|
||||||
/// See [CREATE OPERATOR](https://www.postgresql.org/docs/current/sql-createoperator.html)
|
/// See [CREATE OPERATOR](https://www.postgresql.org/docs/current/sql-createoperator.html)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
PGCustomBinaryOperator(Vec<String>),
|
PGCustomBinaryOperator(Vec<String>),
|
||||||
/// The `OVERLAPS` operator
|
|
||||||
///
|
|
||||||
/// Specifies a test for an overlap between two datetime periods:
|
|
||||||
/// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#overlaps-predicate>
|
|
||||||
Overlaps,
|
|
||||||
/// `##` Point of closest proximity (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
DoubleHash,
|
|
||||||
/// `<->` Distance between (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
LtDashGt,
|
|
||||||
/// `&<` Overlaps to left? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
AndLt,
|
|
||||||
/// `&>` Overlaps to right? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
AndGt,
|
|
||||||
/// `<<|` Is strictly below? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
LtLtPipe,
|
|
||||||
/// `|>>` Is strictly above? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
PipeGtGt,
|
|
||||||
/// `&<|` Does not extend above? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
AndLtPipe,
|
|
||||||
/// `|&>` Does not extend below? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
PipeAndGt,
|
|
||||||
/// `<^` Is below? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
LtCaret,
|
|
||||||
/// `>^` Is above? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
GtCaret,
|
|
||||||
/// `?#` Intersects? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionHash,
|
|
||||||
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionDash,
|
|
||||||
/// `?-|` Is perpendicular? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionDashPipe,
|
|
||||||
/// `?||` Are Parallel? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
QuestionDoublePipe,
|
|
||||||
/// `@` Contained or on? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
At,
|
|
||||||
/// `~=` Same as? (PostgreSQL/Redshift geometric operator)
|
|
||||||
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
|
|
||||||
TildeEq,
|
|
||||||
/// ':=' Assignment Operator
|
|
||||||
/// See <https://dev.mysql.com/doc/refman/8.4/en/assignment-operators.html#operator_assign-value>
|
|
||||||
Assignment,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for BinaryOperator {
|
impl fmt::Display for BinaryOperator {
|
||||||
|
@ -355,8 +266,6 @@ impl fmt::Display for BinaryOperator {
|
||||||
BinaryOperator::BitwiseXor => f.write_str("^"),
|
BinaryOperator::BitwiseXor => f.write_str("^"),
|
||||||
BinaryOperator::DuckIntegerDivide => f.write_str("//"),
|
BinaryOperator::DuckIntegerDivide => f.write_str("//"),
|
||||||
BinaryOperator::MyIntegerDivide => f.write_str("DIV"),
|
BinaryOperator::MyIntegerDivide => f.write_str("DIV"),
|
||||||
BinaryOperator::Match => f.write_str("MATCH"),
|
|
||||||
BinaryOperator::Regexp => f.write_str("REGEXP"),
|
|
||||||
BinaryOperator::Custom(s) => f.write_str(s),
|
BinaryOperator::Custom(s) => f.write_str(s),
|
||||||
BinaryOperator::PGBitwiseXor => f.write_str("#"),
|
BinaryOperator::PGBitwiseXor => f.write_str("#"),
|
||||||
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),
|
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),
|
||||||
|
@ -387,24 +296,6 @@ impl fmt::Display for BinaryOperator {
|
||||||
BinaryOperator::PGCustomBinaryOperator(idents) => {
|
BinaryOperator::PGCustomBinaryOperator(idents) => {
|
||||||
write!(f, "OPERATOR({})", display_separated(idents, "."))
|
write!(f, "OPERATOR({})", display_separated(idents, "."))
|
||||||
}
|
}
|
||||||
BinaryOperator::Overlaps => f.write_str("OVERLAPS"),
|
|
||||||
BinaryOperator::DoubleHash => f.write_str("##"),
|
|
||||||
BinaryOperator::LtDashGt => f.write_str("<->"),
|
|
||||||
BinaryOperator::AndLt => f.write_str("&<"),
|
|
||||||
BinaryOperator::AndGt => f.write_str("&>"),
|
|
||||||
BinaryOperator::LtLtPipe => f.write_str("<<|"),
|
|
||||||
BinaryOperator::PipeGtGt => f.write_str("|>>"),
|
|
||||||
BinaryOperator::AndLtPipe => f.write_str("&<|"),
|
|
||||||
BinaryOperator::PipeAndGt => f.write_str("|&>"),
|
|
||||||
BinaryOperator::LtCaret => f.write_str("<^"),
|
|
||||||
BinaryOperator::GtCaret => f.write_str(">^"),
|
|
||||||
BinaryOperator::QuestionHash => f.write_str("?#"),
|
|
||||||
BinaryOperator::QuestionDash => f.write_str("?-"),
|
|
||||||
BinaryOperator::QuestionDashPipe => f.write_str("?-|"),
|
|
||||||
BinaryOperator::QuestionDoublePipe => f.write_str("?||"),
|
|
||||||
BinaryOperator::At => f.write_str("@"),
|
|
||||||
BinaryOperator::TildeEq => f.write_str("~="),
|
|
||||||
BinaryOperator::Assignment => f.write_str(":="),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1779
src/ast/query.rs
1779
src/ast/query.rs
File diff suppressed because it is too large
Load diff
2511
src/ast/spans.rs
2511
src/ast/spans.rs
File diff suppressed because it is too large
Load diff
|
@ -1,165 +0,0 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! SQL Abstract Syntax Tree (AST) for triggers.
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// This specifies whether the trigger function should be fired once for every row affected by the trigger event, or just once per SQL statement.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum TriggerObject {
|
|
||||||
Row,
|
|
||||||
Statement,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerObject {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TriggerObject::Row => write!(f, "ROW"),
|
|
||||||
TriggerObject::Statement => write!(f, "STATEMENT"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This clause indicates whether the following relation name is for the before-image transition relation or the after-image transition relation
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum TriggerReferencingType {
|
|
||||||
OldTable,
|
|
||||||
NewTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerReferencingType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TriggerReferencingType::OldTable => write!(f, "OLD TABLE"),
|
|
||||||
TriggerReferencingType::NewTable => write!(f, "NEW TABLE"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct TriggerReferencing {
|
|
||||||
pub refer_type: TriggerReferencingType,
|
|
||||||
pub is_as: bool,
|
|
||||||
pub transition_relation_name: ObjectName,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerReferencing {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{refer_type}{is_as} {relation_name}",
|
|
||||||
refer_type = self.refer_type,
|
|
||||||
is_as = if self.is_as { " AS" } else { "" },
|
|
||||||
relation_name = self.transition_relation_name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to describe trigger events
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum TriggerEvent {
|
|
||||||
Insert,
|
|
||||||
Update(Vec<Ident>),
|
|
||||||
Delete,
|
|
||||||
Truncate,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerEvent {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TriggerEvent::Insert => write!(f, "INSERT"),
|
|
||||||
TriggerEvent::Update(columns) => {
|
|
||||||
write!(f, "UPDATE")?;
|
|
||||||
if !columns.is_empty() {
|
|
||||||
write!(f, " OF")?;
|
|
||||||
write!(f, " {}", display_comma_separated(columns))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
TriggerEvent::Delete => write!(f, "DELETE"),
|
|
||||||
TriggerEvent::Truncate => write!(f, "TRUNCATE"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trigger period
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum TriggerPeriod {
|
|
||||||
For,
|
|
||||||
After,
|
|
||||||
Before,
|
|
||||||
InsteadOf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerPeriod {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TriggerPeriod::For => write!(f, "FOR"),
|
|
||||||
TriggerPeriod::After => write!(f, "AFTER"),
|
|
||||||
TriggerPeriod::Before => write!(f, "BEFORE"),
|
|
||||||
TriggerPeriod::InsteadOf => write!(f, "INSTEAD OF"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Types of trigger body execution body.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub enum TriggerExecBodyType {
|
|
||||||
Function,
|
|
||||||
Procedure,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerExecBodyType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TriggerExecBodyType::Function => write!(f, "FUNCTION"),
|
|
||||||
TriggerExecBodyType::Procedure => write!(f, "PROCEDURE"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct TriggerExecBody {
|
|
||||||
pub exec_type: TriggerExecBodyType,
|
|
||||||
pub func_desc: FunctionDesc,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TriggerExecBody {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{exec_type} {func_desc}",
|
|
||||||
exec_type = self.exec_type,
|
|
||||||
func_desc = self.func_desc
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
269
src/ast/value.rs
269
src/ast/value.rs
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
@ -26,96 +21,14 @@ use bigdecimal::BigDecimal;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{ast::Ident, tokenizer::Span};
|
use crate::ast::Ident;
|
||||||
#[cfg(feature = "visitor")]
|
#[cfg(feature = "visitor")]
|
||||||
use sqlparser_derive::{Visit, VisitMut};
|
use sqlparser_derive::{Visit, VisitMut};
|
||||||
|
|
||||||
/// Wraps a primitive SQL [`Value`] with its [`Span`] location
|
|
||||||
///
|
|
||||||
/// # Example: create a `ValueWithSpan` from a `Value`
|
|
||||||
/// ```
|
|
||||||
/// # use sqlparser::ast::{Value, ValueWithSpan};
|
|
||||||
/// # use sqlparser::tokenizer::{Location, Span};
|
|
||||||
/// let value = Value::SingleQuotedString(String::from("endpoint"));
|
|
||||||
/// // from line 1, column 1 to line 1, column 7
|
|
||||||
/// let span = Span::new(Location::new(1, 1), Location::new(1, 7));
|
|
||||||
/// let value_with_span = value.with_span(span);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Example: create a `ValueWithSpan` from a `Value` with an empty span
|
|
||||||
///
|
|
||||||
/// You can call [`Value::with_empty_span`] to create a `ValueWithSpan` with an empty span
|
|
||||||
/// ```
|
|
||||||
/// # use sqlparser::ast::{Value, ValueWithSpan};
|
|
||||||
/// # use sqlparser::tokenizer::{Location, Span};
|
|
||||||
/// let value = Value::SingleQuotedString(String::from("endpoint"));
|
|
||||||
/// let value_with_span = value.with_empty_span();
|
|
||||||
/// assert_eq!(value_with_span.span, Span::empty());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You can also use the [`From`] trait to convert `ValueWithSpan` to/from `Value`s
|
|
||||||
/// ```
|
|
||||||
/// # use sqlparser::ast::{Value, ValueWithSpan};
|
|
||||||
/// # use sqlparser::tokenizer::{Location, Span};
|
|
||||||
/// let value = Value::SingleQuotedString(String::from("endpoint"));
|
|
||||||
/// // converting `Value` to `ValueWithSpan` results in an empty span
|
|
||||||
/// let value_with_span: ValueWithSpan = value.into();
|
|
||||||
/// assert_eq!(value_with_span.span, Span::empty());
|
|
||||||
/// // convert back to `Value`
|
|
||||||
/// let value: Value = value_with_span.into();
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug, Clone, Eq)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
pub struct ValueWithSpan {
|
|
||||||
pub value: Value,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for ValueWithSpan {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.value == other.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for ValueWithSpan {
|
|
||||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
|
||||||
self.value.cmp(&other.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for ValueWithSpan {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
|
||||||
Some(Ord::cmp(self, other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::hash::Hash for ValueWithSpan {
|
|
||||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.value.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Value> for ValueWithSpan {
|
|
||||||
fn from(value: Value) -> Self {
|
|
||||||
value.with_empty_span()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ValueWithSpan> for Value {
|
|
||||||
fn from(value: ValueWithSpan) -> Self {
|
|
||||||
value.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Primitive SQL values such as number and string
|
/// Primitive SQL values such as number and string
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
feature = "visitor",
|
|
||||||
derive(Visit, VisitMut),
|
|
||||||
visit(with = "visit_value")
|
|
||||||
)]
|
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
/// Numeric literal
|
/// Numeric literal
|
||||||
#[cfg(not(feature = "bigdecimal"))]
|
#[cfg(not(feature = "bigdecimal"))]
|
||||||
|
@ -139,10 +52,6 @@ pub enum Value {
|
||||||
/// See [Postgres docs](https://www.postgresql.org/docs/8.3/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)
|
/// See [Postgres docs](https://www.postgresql.org/docs/8.3/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)
|
||||||
/// for more details.
|
/// for more details.
|
||||||
EscapedStringLiteral(String),
|
EscapedStringLiteral(String),
|
||||||
/// u&'string value' (postgres extension)
|
|
||||||
/// See [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
|
|
||||||
/// for more details.
|
|
||||||
UnicodeStringLiteral(String),
|
|
||||||
/// B'string value'
|
/// B'string value'
|
||||||
SingleQuotedByteStringLiteral(String),
|
SingleQuotedByteStringLiteral(String),
|
||||||
/// B"string value"
|
/// B"string value"
|
||||||
|
@ -179,53 +88,6 @@ pub enum Value {
|
||||||
Placeholder(String),
|
Placeholder(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueWithSpan {
|
|
||||||
/// If the underlying literal is a string, regardless of quote style, returns the associated string value
|
|
||||||
pub fn into_string(self) -> Option<String> {
|
|
||||||
self.value.into_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
|
||||||
/// If the underlying literal is a string, regardless of quote style, returns the associated string value
|
|
||||||
pub fn into_string(self) -> Option<String> {
|
|
||||||
match self {
|
|
||||||
Value::SingleQuotedString(s)
|
|
||||||
| Value::DoubleQuotedString(s)
|
|
||||||
| Value::TripleSingleQuotedString(s)
|
|
||||||
| Value::TripleDoubleQuotedString(s)
|
|
||||||
| Value::SingleQuotedByteStringLiteral(s)
|
|
||||||
| Value::DoubleQuotedByteStringLiteral(s)
|
|
||||||
| Value::TripleSingleQuotedByteStringLiteral(s)
|
|
||||||
| Value::TripleDoubleQuotedByteStringLiteral(s)
|
|
||||||
| Value::SingleQuotedRawStringLiteral(s)
|
|
||||||
| Value::DoubleQuotedRawStringLiteral(s)
|
|
||||||
| Value::TripleSingleQuotedRawStringLiteral(s)
|
|
||||||
| Value::TripleDoubleQuotedRawStringLiteral(s)
|
|
||||||
| Value::EscapedStringLiteral(s)
|
|
||||||
| Value::UnicodeStringLiteral(s)
|
|
||||||
| Value::NationalStringLiteral(s)
|
|
||||||
| Value::HexStringLiteral(s) => Some(s),
|
|
||||||
Value::DollarQuotedString(s) => Some(s.value),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_span(self, span: Span) -> ValueWithSpan {
|
|
||||||
ValueWithSpan { value: self, span }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_empty_span(self) -> ValueWithSpan {
|
|
||||||
self.with_span(Span::empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ValueWithSpan {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Value {
|
impl fmt::Display for Value {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -240,7 +102,6 @@ impl fmt::Display for Value {
|
||||||
}
|
}
|
||||||
Value::DollarQuotedString(v) => write!(f, "{v}"),
|
Value::DollarQuotedString(v) => write!(f, "{v}"),
|
||||||
Value::EscapedStringLiteral(v) => write!(f, "E'{}'", escape_escaped_string(v)),
|
Value::EscapedStringLiteral(v) => write!(f, "E'{}'", escape_escaped_string(v)),
|
||||||
Value::UnicodeStringLiteral(v) => write!(f, "U&'{}'", escape_unicode_string(v)),
|
|
||||||
Value::NationalStringLiteral(v) => write!(f, "N'{v}'"),
|
Value::NationalStringLiteral(v) => write!(f, "N'{v}'"),
|
||||||
Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
|
Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
|
||||||
Value::Boolean(v) => write!(f, "{v}"),
|
Value::Boolean(v) => write!(f, "{v}"),
|
||||||
|
@ -284,9 +145,7 @@ impl fmt::Display for DollarQuotedString {
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub enum DateTimeField {
|
pub enum DateTimeField {
|
||||||
Year,
|
Year,
|
||||||
Years,
|
|
||||||
Month,
|
Month,
|
||||||
Months,
|
|
||||||
/// Week optionally followed by a WEEKDAY.
|
/// Week optionally followed by a WEEKDAY.
|
||||||
///
|
///
|
||||||
/// ```sql
|
/// ```sql
|
||||||
|
@ -295,19 +154,14 @@ pub enum DateTimeField {
|
||||||
///
|
///
|
||||||
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#extract)
|
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#extract)
|
||||||
Week(Option<Ident>),
|
Week(Option<Ident>),
|
||||||
Weeks,
|
|
||||||
Day,
|
Day,
|
||||||
DayOfWeek,
|
DayOfWeek,
|
||||||
DayOfYear,
|
DayOfYear,
|
||||||
Days,
|
|
||||||
Date,
|
Date,
|
||||||
Datetime,
|
Datetime,
|
||||||
Hour,
|
Hour,
|
||||||
Hours,
|
|
||||||
Minute,
|
Minute,
|
||||||
Minutes,
|
|
||||||
Second,
|
Second,
|
||||||
Seconds,
|
|
||||||
Century,
|
Century,
|
||||||
Decade,
|
Decade,
|
||||||
Dow,
|
Dow,
|
||||||
|
@ -346,9 +200,7 @@ impl fmt::Display for DateTimeField {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
DateTimeField::Year => write!(f, "YEAR"),
|
DateTimeField::Year => write!(f, "YEAR"),
|
||||||
DateTimeField::Years => write!(f, "YEARS"),
|
|
||||||
DateTimeField::Month => write!(f, "MONTH"),
|
DateTimeField::Month => write!(f, "MONTH"),
|
||||||
DateTimeField::Months => write!(f, "MONTHS"),
|
|
||||||
DateTimeField::Week(week_day) => {
|
DateTimeField::Week(week_day) => {
|
||||||
write!(f, "WEEK")?;
|
write!(f, "WEEK")?;
|
||||||
if let Some(week_day) = week_day {
|
if let Some(week_day) = week_day {
|
||||||
|
@ -356,19 +208,14 @@ impl fmt::Display for DateTimeField {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
DateTimeField::Weeks => write!(f, "WEEKS"),
|
|
||||||
DateTimeField::Day => write!(f, "DAY"),
|
DateTimeField::Day => write!(f, "DAY"),
|
||||||
DateTimeField::DayOfWeek => write!(f, "DAYOFWEEK"),
|
DateTimeField::DayOfWeek => write!(f, "DAYOFWEEK"),
|
||||||
DateTimeField::DayOfYear => write!(f, "DAYOFYEAR"),
|
DateTimeField::DayOfYear => write!(f, "DAYOFYEAR"),
|
||||||
DateTimeField::Days => write!(f, "DAYS"),
|
|
||||||
DateTimeField::Date => write!(f, "DATE"),
|
DateTimeField::Date => write!(f, "DATE"),
|
||||||
DateTimeField::Datetime => write!(f, "DATETIME"),
|
DateTimeField::Datetime => write!(f, "DATETIME"),
|
||||||
DateTimeField::Hour => write!(f, "HOUR"),
|
DateTimeField::Hour => write!(f, "HOUR"),
|
||||||
DateTimeField::Hours => write!(f, "HOURS"),
|
|
||||||
DateTimeField::Minute => write!(f, "MINUTE"),
|
DateTimeField::Minute => write!(f, "MINUTE"),
|
||||||
DateTimeField::Minutes => write!(f, "MINUTES"),
|
|
||||||
DateTimeField::Second => write!(f, "SECOND"),
|
DateTimeField::Second => write!(f, "SECOND"),
|
||||||
DateTimeField::Seconds => write!(f, "SECONDS"),
|
|
||||||
DateTimeField::Century => write!(f, "CENTURY"),
|
DateTimeField::Century => write!(f, "CENTURY"),
|
||||||
DateTimeField::Decade => write!(f, "DECADE"),
|
DateTimeField::Decade => write!(f, "DECADE"),
|
||||||
DateTimeField::Dow => write!(f, "DOW"),
|
DateTimeField::Dow => write!(f, "DOW"),
|
||||||
|
@ -399,41 +246,12 @@ impl fmt::Display for DateTimeField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
|
||||||
/// The Unicode Standard defines four normalization forms, which are intended to eliminate
|
|
||||||
/// certain distinctions between visually or functionally identical characters.
|
|
||||||
///
|
|
||||||
/// See [Unicode Normalization Forms](https://unicode.org/reports/tr15/) for details.
|
|
||||||
pub enum NormalizationForm {
|
|
||||||
/// Canonical Decomposition, followed by Canonical Composition.
|
|
||||||
NFC,
|
|
||||||
/// Canonical Decomposition.
|
|
||||||
NFD,
|
|
||||||
/// Compatibility Decomposition, followed by Canonical Composition.
|
|
||||||
NFKC,
|
|
||||||
/// Compatibility Decomposition.
|
|
||||||
NFKD,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for NormalizationForm {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
NormalizationForm::NFC => write!(f, "NFC"),
|
|
||||||
NormalizationForm::NFD => write!(f, "NFD"),
|
|
||||||
NormalizationForm::NFKC => write!(f, "NFKC"),
|
|
||||||
NormalizationForm::NFKD => write!(f, "NFKD"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EscapeQuotedString<'a> {
|
pub struct EscapeQuotedString<'a> {
|
||||||
string: &'a str,
|
string: &'a str,
|
||||||
quote: char,
|
quote: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for EscapeQuotedString<'_> {
|
impl<'a> fmt::Display for EscapeQuotedString<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// EscapeQuotedString doesn't know which mode of escape was
|
// EscapeQuotedString doesn't know which mode of escape was
|
||||||
// chosen by the user. So this code must to correctly display
|
// chosen by the user. So this code must to correctly display
|
||||||
|
@ -455,38 +273,30 @@ impl fmt::Display for EscapeQuotedString<'_> {
|
||||||
// | `"A\"B\"A"` | default | `DoubleQuotedString(String::from("A\"B\"A"))` | `"A""B""A"` |
|
// | `"A\"B\"A"` | default | `DoubleQuotedString(String::from("A\"B\"A"))` | `"A""B""A"` |
|
||||||
let quote = self.quote;
|
let quote = self.quote;
|
||||||
let mut previous_char = char::default();
|
let mut previous_char = char::default();
|
||||||
let mut start_idx = 0;
|
let mut peekable_chars = self.string.chars().peekable();
|
||||||
let mut peekable_chars = self.string.char_indices().peekable();
|
while let Some(&ch) = peekable_chars.peek() {
|
||||||
while let Some(&(idx, ch)) = peekable_chars.peek() {
|
|
||||||
match ch {
|
match ch {
|
||||||
char if char == quote => {
|
char if char == quote => {
|
||||||
if previous_char == '\\' {
|
if previous_char == '\\' {
|
||||||
// the quote is already escaped with a backslash, skip
|
write!(f, "{char}")?;
|
||||||
peekable_chars.next();
|
peekable_chars.next();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
peekable_chars.next();
|
peekable_chars.next();
|
||||||
match peekable_chars.peek() {
|
if peekable_chars.peek().map(|c| *c == quote).unwrap_or(false) {
|
||||||
Some((_, c)) if *c == quote => {
|
write!(f, "{char}{char}")?;
|
||||||
// the quote is already escaped with another quote, skip
|
peekable_chars.next();
|
||||||
peekable_chars.next();
|
} else {
|
||||||
}
|
write!(f, "{char}{char}")?;
|
||||||
_ => {
|
|
||||||
// The quote is not escaped.
|
|
||||||
// Including idx in the range, so the quote at idx will be printed twice:
|
|
||||||
// in this call to write_str() and in the next one.
|
|
||||||
f.write_str(&self.string[start_idx..=idx])?;
|
|
||||||
start_idx = idx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
write!(f, "{ch}")?;
|
||||||
peekable_chars.next();
|
peekable_chars.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previous_char = ch;
|
previous_char = ch;
|
||||||
}
|
}
|
||||||
f.write_str(&self.string[start_idx..])?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,7 +315,7 @@ pub fn escape_double_quote_string(s: &str) -> EscapeQuotedString<'_> {
|
||||||
|
|
||||||
pub struct EscapeEscapedStringLiteral<'a>(&'a str);
|
pub struct EscapeEscapedStringLiteral<'a>(&'a str);
|
||||||
|
|
||||||
impl fmt::Display for EscapeEscapedStringLiteral<'_> {
|
impl<'a> fmt::Display for EscapeEscapedStringLiteral<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for c in self.0.chars() {
|
for c in self.0.chars() {
|
||||||
match c {
|
match c {
|
||||||
|
@ -537,41 +347,6 @@ pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> {
|
||||||
EscapeEscapedStringLiteral(s)
|
EscapeEscapedStringLiteral(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EscapeUnicodeStringLiteral<'a>(&'a str);
|
|
||||||
|
|
||||||
impl fmt::Display for EscapeUnicodeStringLiteral<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
for c in self.0.chars() {
|
|
||||||
match c {
|
|
||||||
'\'' => {
|
|
||||||
write!(f, "''")?;
|
|
||||||
}
|
|
||||||
'\\' => {
|
|
||||||
write!(f, r#"\\"#)?;
|
|
||||||
}
|
|
||||||
x if x.is_ascii() => {
|
|
||||||
write!(f, "{c}")?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let codepoint = c as u32;
|
|
||||||
// if the character fits in 32 bits, we can use the \XXXX format
|
|
||||||
// otherwise, we need to use the \+XXXXXX format
|
|
||||||
if codepoint <= 0xFFFF {
|
|
||||||
write!(f, "\\{codepoint:04X}")?;
|
|
||||||
} else {
|
|
||||||
write!(f, "\\+{codepoint:06X}")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn escape_unicode_string(s: &str) -> EscapeUnicodeStringLiteral<'_> {
|
|
||||||
EscapeUnicodeStringLiteral(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! Recursive visitors for ast Nodes. See [`Visitor`] for more details.
|
//! Recursive visitors for ast Nodes. See [`Visitor`] for more details.
|
||||||
|
|
||||||
use crate::ast::{Expr, ObjectName, Query, Statement, TableFactor, Value};
|
use crate::ast::{Expr, ObjectName, Query, Statement, TableFactor};
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
/// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
|
/// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
|
||||||
|
@ -233,16 +228,6 @@ pub trait Visitor {
|
||||||
fn post_visit_statement(&mut self, _statement: &Statement) -> ControlFlow<Self::Break> {
|
fn post_visit_statement(&mut self, _statement: &Statement) -> ControlFlow<Self::Break> {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked for any Value that appear in the AST before visiting children
|
|
||||||
fn pre_visit_value(&mut self, _value: &Value) -> ControlFlow<Self::Break> {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoked for any Value that appear in the AST after visiting children
|
|
||||||
fn post_visit_value(&mut self, _value: &Value) -> ControlFlow<Self::Break> {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A visitor that can be used to mutate an AST tree.
|
/// A visitor that can be used to mutate an AST tree.
|
||||||
|
@ -347,16 +332,6 @@ pub trait VisitorMut {
|
||||||
fn post_visit_statement(&mut self, _statement: &mut Statement) -> ControlFlow<Self::Break> {
|
fn post_visit_statement(&mut self, _statement: &mut Statement) -> ControlFlow<Self::Break> {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked for any value that appear in the AST before visiting children
|
|
||||||
fn pre_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoked for any statements that appear in the AST after visiting children
|
|
||||||
fn post_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RelationVisitor<F>(F);
|
struct RelationVisitor<F>(F);
|
||||||
|
@ -423,7 +398,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// # use sqlparser::parser::Parser;
|
/// # use sqlparser::parser::Parser;
|
||||||
/// # use sqlparser::dialect::GenericDialect;
|
/// # use sqlparser::dialect::GenericDialect;
|
||||||
/// # use sqlparser::ast::{ObjectName, ObjectNamePart, Ident, visit_relations_mut};
|
/// # use sqlparser::ast::{ObjectName, visit_relations_mut};
|
||||||
/// # use core::ops::ControlFlow;
|
/// # use core::ops::ControlFlow;
|
||||||
/// let sql = "SELECT a FROM foo";
|
/// let sql = "SELECT a FROM foo";
|
||||||
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql)
|
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql)
|
||||||
|
@ -431,7 +406,7 @@ where
|
||||||
///
|
///
|
||||||
/// // visit statements, renaming table foo to bar
|
/// // visit statements, renaming table foo to bar
|
||||||
/// visit_relations_mut(&mut statements, |table| {
|
/// visit_relations_mut(&mut statements, |table| {
|
||||||
/// table.0[0] = ObjectNamePart::Identifier(Ident::new("bar"));
|
/// table.0[0].value = table.0[0].value.replace("foo", "bar");
|
||||||
/// ControlFlow::<()>::Continue(())
|
/// ControlFlow::<()>::Continue(())
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
|
@ -523,7 +498,7 @@ where
|
||||||
/// // Remove all select limits in sub-queries
|
/// // Remove all select limits in sub-queries
|
||||||
/// visit_expressions_mut(&mut statements, |expr| {
|
/// visit_expressions_mut(&mut statements, |expr| {
|
||||||
/// if let Expr::Subquery(q) = expr {
|
/// if let Expr::Subquery(q) = expr {
|
||||||
/// q.limit_clause = None;
|
/// q.limit = None
|
||||||
/// }
|
/// }
|
||||||
/// ControlFlow::<()>::Continue(())
|
/// ControlFlow::<()>::Continue(())
|
||||||
/// });
|
/// });
|
||||||
|
@ -547,10 +522,9 @@ where
|
||||||
///
|
///
|
||||||
/// visit_expressions_mut(&mut statements, |expr| {
|
/// visit_expressions_mut(&mut statements, |expr| {
|
||||||
/// if matches!(expr, Expr::Identifier(col_name) if col_name.value == "x") {
|
/// if matches!(expr, Expr::Identifier(col_name) if col_name.value == "x") {
|
||||||
/// let old_expr = std::mem::replace(expr, Expr::value(Value::Null));
|
/// let old_expr = std::mem::replace(expr, Expr::Value(Value::Null));
|
||||||
/// *expr = Expr::Function(Function {
|
/// *expr = Expr::Function(Function {
|
||||||
/// name: ObjectName::from(vec![Ident::new("f")]),
|
/// name: ObjectName(vec![Ident::new("f")]),
|
||||||
/// uses_odbc_syntax: false,
|
|
||||||
/// args: FunctionArguments::List(FunctionArgumentList {
|
/// args: FunctionArguments::List(FunctionArgumentList {
|
||||||
/// duplicate_treatment: None,
|
/// duplicate_treatment: None,
|
||||||
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
|
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
|
||||||
|
@ -647,7 +621,7 @@ where
|
||||||
/// // Remove all select limits in outer statements (not in sub-queries)
|
/// // Remove all select limits in outer statements (not in sub-queries)
|
||||||
/// visit_statements_mut(&mut statements, |stmt| {
|
/// visit_statements_mut(&mut statements, |stmt| {
|
||||||
/// if let Statement::Query(q) = stmt {
|
/// if let Statement::Query(q) = stmt {
|
||||||
/// q.limit_clause = None;
|
/// q.limit = None
|
||||||
/// }
|
/// }
|
||||||
/// ControlFlow::<()>::Continue(())
|
/// ControlFlow::<()>::Continue(())
|
||||||
/// });
|
/// });
|
||||||
|
@ -667,7 +641,6 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::Statement;
|
|
||||||
use crate::dialect::GenericDialect;
|
use crate::dialect::GenericDialect;
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
use crate::tokenizer::Tokenizer;
|
use crate::tokenizer::Tokenizer;
|
||||||
|
@ -741,7 +714,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_visit<V: Visitor<Break = ()>>(sql: &str, visitor: &mut V) -> Statement {
|
fn do_visit(sql: &str) -> Vec<String> {
|
||||||
let dialect = GenericDialect {};
|
let dialect = GenericDialect {};
|
||||||
let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap();
|
let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap();
|
||||||
let s = Parser::new(&dialect)
|
let s = Parser::new(&dialect)
|
||||||
|
@ -749,9 +722,9 @@ mod tests {
|
||||||
.parse_statement()
|
.parse_statement()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let flow = s.visit(visitor);
|
let mut visitor = TestVisitor::default();
|
||||||
assert_eq!(flow, ControlFlow::Continue(()));
|
s.visit(&mut visitor);
|
||||||
s
|
visitor.visited
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -898,113 +871,12 @@ mod tests {
|
||||||
"POST: QUERY: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
|
"POST: QUERY: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
|
||||||
"POST: STATEMENT: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
|
"POST: STATEMENT: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
(
|
|
||||||
"SHOW COLUMNS FROM t1",
|
|
||||||
vec![
|
|
||||||
"PRE: STATEMENT: SHOW COLUMNS FROM t1",
|
|
||||||
"PRE: RELATION: t1",
|
|
||||||
"POST: RELATION: t1",
|
|
||||||
"POST: STATEMENT: SHOW COLUMNS FROM t1",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
for (sql, expected) in tests {
|
for (sql, expected) in tests {
|
||||||
let mut visitor = TestVisitor::default();
|
let actual = do_visit(sql);
|
||||||
let _ = do_visit(sql, &mut visitor);
|
let actual: Vec<_> = actual.iter().map(|x| x.as_str()).collect();
|
||||||
let actual: Vec<_> = visitor.visited.iter().map(|x| x.as_str()).collect();
|
|
||||||
assert_eq!(actual, expected)
|
assert_eq!(actual, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QuickVisitor; // [`TestVisitor`] is too slow to iterate over thousands of nodes
|
|
||||||
|
|
||||||
impl Visitor for QuickVisitor {
|
|
||||||
type Break = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn overflow() {
|
|
||||||
let cond = (0..1000)
|
|
||||||
.map(|n| format!("X = {n}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" OR ");
|
|
||||||
let sql = format!("SELECT x where {cond}");
|
|
||||||
|
|
||||||
let dialect = GenericDialect {};
|
|
||||||
let tokens = Tokenizer::new(&dialect, sql.as_str()).tokenize().unwrap();
|
|
||||||
let s = Parser::new(&dialect)
|
|
||||||
.with_tokens(tokens)
|
|
||||||
.parse_statement()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut visitor = QuickVisitor {};
|
|
||||||
let flow = s.visit(&mut visitor);
|
|
||||||
assert_eq!(flow, ControlFlow::Continue(()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod visit_mut_tests {
|
|
||||||
use crate::ast::{Statement, Value, VisitMut, VisitorMut};
|
|
||||||
use crate::dialect::GenericDialect;
|
|
||||||
use crate::parser::Parser;
|
|
||||||
use crate::tokenizer::Tokenizer;
|
|
||||||
use core::ops::ControlFlow;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct MutatorVisitor {
|
|
||||||
index: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VisitorMut for MutatorVisitor {
|
|
||||||
type Break = ();
|
|
||||||
|
|
||||||
fn pre_visit_value(&mut self, value: &mut Value) -> ControlFlow<Self::Break> {
|
|
||||||
self.index += 1;
|
|
||||||
*value = Value::SingleQuotedString(format!("REDACTED_{}", self.index));
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn post_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_visit_mut<V: VisitorMut<Break = ()>>(sql: &str, visitor: &mut V) -> Statement {
|
|
||||||
let dialect = GenericDialect {};
|
|
||||||
let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap();
|
|
||||||
let mut s = Parser::new(&dialect)
|
|
||||||
.with_tokens(tokens)
|
|
||||||
.parse_statement()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let flow = s.visit(visitor);
|
|
||||||
assert_eq!(flow, ControlFlow::Continue(()));
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_value_redact() {
|
|
||||||
let tests = vec![
|
|
||||||
(
|
|
||||||
concat!(
|
|
||||||
"SELECT * FROM monthly_sales ",
|
|
||||||
"PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ",
|
|
||||||
"ORDER BY EMPID"
|
|
||||||
),
|
|
||||||
concat!(
|
|
||||||
"SELECT * FROM monthly_sales ",
|
|
||||||
"PIVOT(SUM(a.amount) FOR a.MONTH IN ('REDACTED_1', 'REDACTED_2', 'REDACTED_3', 'REDACTED_4')) AS p (c, d) ",
|
|
||||||
"ORDER BY EMPID"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (sql, expected) in tests {
|
|
||||||
let mut visitor = MutatorVisitor::default();
|
|
||||||
let mutated = do_visit_mut(sql, &mut visitor);
|
|
||||||
assert_eq!(mutated.to_string(), expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
|
@ -29,8 +24,4 @@ impl Dialect for AnsiDialect {
|
||||||
fn is_identifier_part(&self, ch: char) -> bool {
|
fn is_identifier_part(&self, ch: char) -> bool {
|
||||||
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
|
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,23 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::ast::Statement;
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
use crate::keywords::Keyword;
|
|
||||||
use crate::parser::{Parser, ParserError};
|
|
||||||
|
|
||||||
/// These keywords are disallowed as column identifiers. Such that
|
|
||||||
/// `SELECT 5 AS <col> FROM T` is rejected by BigQuery.
|
|
||||||
const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
|
|
||||||
Keyword::WITH,
|
|
||||||
Keyword::SELECT,
|
|
||||||
Keyword::WHERE,
|
|
||||||
Keyword::GROUP,
|
|
||||||
Keyword::HAVING,
|
|
||||||
Keyword::ORDER,
|
|
||||||
Keyword::LATERAL,
|
|
||||||
Keyword::LIMIT,
|
|
||||||
Keyword::FETCH,
|
|
||||||
Keyword::UNION,
|
|
||||||
Keyword::EXCEPT,
|
|
||||||
Keyword::INTERSECT,
|
|
||||||
Keyword::FROM,
|
|
||||||
Keyword::INTO,
|
|
||||||
Keyword::END,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// A [`Dialect`] for [Google Bigquery](https://cloud.google.com/bigquery/)
|
/// A [`Dialect`] for [Google Bigquery](https://cloud.google.com/bigquery/)
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct BigQueryDialect;
|
pub struct BigQueryDialect;
|
||||||
|
|
||||||
impl Dialect for BigQueryDialect {
|
impl Dialect for BigQueryDialect {
|
||||||
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
|
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#identifiers
|
||||||
if parser.parse_keyword(Keyword::BEGIN) {
|
|
||||||
return Some(parser.parse_begin_exception_end());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#identifiers>
|
|
||||||
fn is_delimited_identifier_start(&self, ch: char) -> bool {
|
fn is_delimited_identifier_start(&self, ch: char) -> bool {
|
||||||
ch == '`'
|
ch == '`'
|
||||||
}
|
}
|
||||||
|
@ -62,16 +26,8 @@ impl Dialect for BigQueryDialect {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_statement>
|
|
||||||
fn supports_column_definition_trailing_commas(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_identifier_start(&self, ch: char) -> bool {
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
|
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
|
||||||
// BigQuery supports `@@foo.bar` variable syntax in its procedural language.
|
|
||||||
// https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#beginexceptionend
|
|
||||||
|| ch == '@'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_identifier_part(&self, ch: char) -> bool {
|
fn is_identifier_part(&self, ch: char) -> bool {
|
||||||
|
@ -107,41 +63,4 @@ impl Dialect for BigQueryDialect {
|
||||||
fn supports_select_wildcard_except(&self) -> bool {
|
fn supports_select_wildcard_except(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#constructing_a_struct
|
|
||||||
fn supports_struct_literal(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_expression_star>
|
|
||||||
fn supports_select_expr_star(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#execute_immediate>
|
|
||||||
fn supports_execute_immediate(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See <https://cloud.google.com/bigquery/docs/access-historical-data>
|
|
||||||
fn supports_timestamp_versioning(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#group_by_clause>
|
|
||||||
fn supports_group_by_expr(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
|
|
||||||
!RESERVED_FOR_COLUMN_ALIAS.contains(kw)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_pipe_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
|
@ -38,60 +33,4 @@ impl Dialect for ClickHouseDialect {
|
||||||
fn supports_select_wildcard_except(&self) -> bool {
|
fn supports_select_wildcard_except(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe_requires_table_keyword(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_limit_comma(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_insert_table_function(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_insert_format(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_numeric_literal_underscores(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClickHouse uses this for some FORMAT expressions in `INSERT` context, e.g. when inserting
|
|
||||||
// with FORMAT JSONEachRow a raw JSON key-value expression is valid and expected.
|
|
||||||
//
|
|
||||||
// [ClickHouse formats](https://clickhouse.com/docs/en/interfaces/formats)
|
|
||||||
fn supports_dictionary_syntax(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://clickhouse.com/docs/en/sql-reference/functions#higher-order-functions---operator-and-lambdaparams-expr-function>
|
|
||||||
fn supports_lambda_functions(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_from_first_select(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
|
|
||||||
fn supports_order_by_all(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See <https://clickhouse.com/docs/en/sql-reference/aggregate-functions/grouping_function#grouping-sets>
|
|
||||||
fn supports_group_by_expr(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
|
|
||||||
fn supports_group_by_with_modifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
/// A [`Dialect`] for [Databricks SQL](https://www.databricks.com/)
|
/// A [`Dialect`] for [Databricks SQL](https://www.databricks.com/)
|
||||||
|
@ -55,13 +38,4 @@ impl Dialect for DatabricksDialect {
|
||||||
fn supports_select_wildcard_except(&self) -> bool {
|
fn supports_select_wildcard_except(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://docs.databricks.com/en/sql/language-manual/functions/struct.html
|
|
||||||
fn supports_struct_literal(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
|
@ -47,10 +42,6 @@ impl Dialect for DuckDbDialect {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// DuckDB uses this syntax for `STRUCT`s.
|
// DuckDB uses this syntax for `STRUCT`s.
|
||||||
//
|
//
|
||||||
// https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
|
// https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
|
||||||
|
@ -64,38 +55,4 @@ impl Dialect for DuckDbDialect {
|
||||||
fn support_map_literal_syntax(&self) -> bool {
|
fn support_map_literal_syntax(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See <https://duckdb.org/docs/sql/functions/lambda.html>
|
|
||||||
fn supports_lambda_functions(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// DuckDB is compatible with PostgreSQL syntax for this statement,
|
|
||||||
// although not all features may be implemented.
|
|
||||||
fn supports_explain_with_utility_options(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See DuckDB <https://duckdb.org/docs/sql/statements/load_and_install.html#load>
|
|
||||||
fn supports_load_extension(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See DuckDB <https://duckdb.org/docs/sql/data_types/array.html#defining-an-array-field>
|
|
||||||
fn supports_array_typedef_with_brackets(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_from_first_select(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See DuckDB <https://duckdb.org/docs/sql/query_syntax/orderby.html#order-by-all-examples>
|
|
||||||
fn supports_order_by_all(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_select_wildcard_exclude(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
|
@ -40,22 +35,10 @@ impl Dialect for GenericDialect {
|
||||||
|| ch == '_'
|
|| ch == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_unicode_string_literal(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_group_by_expr(&self) -> bool {
|
fn supports_group_by_expr(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_group_by_with_modifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_left_associative_joins_without_parens(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_connect_by(&self) -> bool {
|
fn supports_connect_by(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -91,96 +74,4 @@ impl Dialect for GenericDialect {
|
||||||
fn support_map_literal_syntax(&self) -> bool {
|
fn support_map_literal_syntax(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allow_extract_custom(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_create_index_with_clause(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_explain_with_utility_options(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_limit_comma(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_from_first_select(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_projection_trailing_commas(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_asc_desc_in_column_definition(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_try_convert(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_comment_on(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_load_extension(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_struct_literal(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_empty_projections(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_nested_comments(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_user_host_grantee(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_string_escape_constant(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_array_typedef_with_brackets(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_match_against(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_set_names(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_comma_separated_set_assignments(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_filter_during_aggregation(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_select_wildcard_exclude(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
|
@ -47,28 +42,4 @@ impl Dialect for HiveDialect {
|
||||||
fn supports_numeric_prefix(&self) -> bool {
|
fn supports_numeric_prefix(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362061#Tutorial-BuiltInOperators>
|
|
||||||
fn supports_bang_not_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362036#LanguageManualDML-Loadingfilesintotables>
|
|
||||||
fn supports_load_data(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cwiki.apache.org/confluence/display/hive/languagemanual+sampling>
|
|
||||||
fn supports_table_sample_before_alias(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=30151323#EnhancedAggregation,Cube,GroupingandRollup-CubesandRollupsr>
|
|
||||||
fn supports_group_by_with_modifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,33 +1,16 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::ast::helpers::attached_token::AttachedToken;
|
|
||||||
use crate::ast::{
|
|
||||||
BeginEndStatements, ConditionalStatementBlock, ConditionalStatements, GranteesType,
|
|
||||||
IfStatement, Statement, TriggerObject,
|
|
||||||
};
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
use crate::keywords::{self, Keyword};
|
|
||||||
use crate::parser::{Parser, ParserError};
|
|
||||||
use crate::tokenizer::Token;
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use alloc::{vec, vec::Vec};
|
|
||||||
|
|
||||||
const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[Keyword::IF, Keyword::ELSE];
|
|
||||||
|
|
||||||
/// A [`Dialect`] for [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/)
|
/// A [`Dialect`] for [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -52,247 +35,13 @@ impl Dialect for MsSqlDialect {
|
||||||
|| ch == '_'
|
|| ch == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
|
|
||||||
Some('[')
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SQL Server has `CONVERT(type, value)` instead of `CONVERT(value, type)`
|
/// SQL Server has `CONVERT(type, value)` instead of `CONVERT(value, type)`
|
||||||
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16>
|
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16>
|
||||||
fn convert_type_before_value(&self) -> bool {
|
fn convert_type_before_value(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_outer_join_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_connect_by(&self) -> bool {
|
fn supports_connect_by(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_eq_alias_assignment(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_try_convert(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In MSSQL, there is no boolean type, and `true` and `false` are valid column names
|
|
||||||
fn supports_boolean_literals(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_named_fn_args_with_expr_name(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_start_transaction_modifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_end_transaction_modifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See: <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
|
|
||||||
fn supports_set_stmt_without_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See: <https://learn.microsoft.com/en-us/sql/relational-databases/tables/querying-data-in-a-system-versioned-temporal-table>
|
|
||||||
fn supports_timestamp_versioning(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/slash-star-comment-transact-sql?view=sql-server-ver16>
|
|
||||||
fn supports_nested_comments(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql>
|
|
||||||
fn supports_object_name_double_dot_notation(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/server-level-roles>
|
|
||||||
fn get_reserved_grantees_types(&self) -> &[GranteesType] {
|
|
||||||
&[GranteesType::Public]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
|
|
||||||
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
|
|
||||||
if parser.peek_keyword(Keyword::IF) {
|
|
||||||
Some(self.parse_if_stmt(parser))
|
|
||||||
} else if parser.parse_keywords(&[Keyword::CREATE, Keyword::TRIGGER]) {
|
|
||||||
Some(self.parse_create_trigger(parser, false))
|
|
||||||
} else if parser.parse_keywords(&[
|
|
||||||
Keyword::CREATE,
|
|
||||||
Keyword::OR,
|
|
||||||
Keyword::ALTER,
|
|
||||||
Keyword::TRIGGER,
|
|
||||||
]) {
|
|
||||||
Some(self.parse_create_trigger(parser, true))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MsSqlDialect {
|
|
||||||
/// ```sql
|
|
||||||
/// IF boolean_expression
|
|
||||||
/// { sql_statement | statement_block }
|
|
||||||
/// [ ELSE
|
|
||||||
/// { sql_statement | statement_block } ]
|
|
||||||
/// ```
|
|
||||||
fn parse_if_stmt(&self, parser: &mut Parser) -> Result<Statement, ParserError> {
|
|
||||||
let if_token = parser.expect_keyword(Keyword::IF)?;
|
|
||||||
|
|
||||||
let condition = parser.parse_expr()?;
|
|
||||||
|
|
||||||
let if_block = if parser.peek_keyword(Keyword::BEGIN) {
|
|
||||||
let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
|
|
||||||
let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
|
|
||||||
let end_token = parser.expect_keyword(Keyword::END)?;
|
|
||||||
ConditionalStatementBlock {
|
|
||||||
start_token: AttachedToken(if_token),
|
|
||||||
condition: Some(condition),
|
|
||||||
then_token: None,
|
|
||||||
conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
|
|
||||||
begin_token: AttachedToken(begin_token),
|
|
||||||
statements,
|
|
||||||
end_token: AttachedToken(end_token),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let stmt = parser.parse_statement()?;
|
|
||||||
ConditionalStatementBlock {
|
|
||||||
start_token: AttachedToken(if_token),
|
|
||||||
condition: Some(condition),
|
|
||||||
then_token: None,
|
|
||||||
conditional_statements: ConditionalStatements::Sequence {
|
|
||||||
statements: vec![stmt],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut prior_statement_ended_with_semi_colon = false;
|
|
||||||
while let Token::SemiColon = parser.peek_token_ref().token {
|
|
||||||
parser.advance_token();
|
|
||||||
prior_statement_ended_with_semi_colon = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut else_block = None;
|
|
||||||
if parser.peek_keyword(Keyword::ELSE) {
|
|
||||||
let else_token = parser.expect_keyword(Keyword::ELSE)?;
|
|
||||||
if parser.peek_keyword(Keyword::BEGIN) {
|
|
||||||
let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
|
|
||||||
let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
|
|
||||||
let end_token = parser.expect_keyword(Keyword::END)?;
|
|
||||||
else_block = Some(ConditionalStatementBlock {
|
|
||||||
start_token: AttachedToken(else_token),
|
|
||||||
condition: None,
|
|
||||||
then_token: None,
|
|
||||||
conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
|
|
||||||
begin_token: AttachedToken(begin_token),
|
|
||||||
statements,
|
|
||||||
end_token: AttachedToken(end_token),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let stmt = parser.parse_statement()?;
|
|
||||||
else_block = Some(ConditionalStatementBlock {
|
|
||||||
start_token: AttachedToken(else_token),
|
|
||||||
condition: None,
|
|
||||||
then_token: None,
|
|
||||||
conditional_statements: ConditionalStatements::Sequence {
|
|
||||||
statements: vec![stmt],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if prior_statement_ended_with_semi_colon {
|
|
||||||
parser.prev_token();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Statement::If(IfStatement {
|
|
||||||
if_block,
|
|
||||||
else_block,
|
|
||||||
elseif_blocks: Vec::new(),
|
|
||||||
end_token: None,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse `CREATE TRIGGER` for [MsSql]
|
|
||||||
///
|
|
||||||
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
|
|
||||||
fn parse_create_trigger(
|
|
||||||
&self,
|
|
||||||
parser: &mut Parser,
|
|
||||||
or_alter: bool,
|
|
||||||
) -> Result<Statement, ParserError> {
|
|
||||||
let name = parser.parse_object_name(false)?;
|
|
||||||
parser.expect_keyword_is(Keyword::ON)?;
|
|
||||||
let table_name = parser.parse_object_name(false)?;
|
|
||||||
let period = parser.parse_trigger_period()?;
|
|
||||||
let events = parser.parse_comma_separated(Parser::parse_trigger_event)?;
|
|
||||||
|
|
||||||
parser.expect_keyword_is(Keyword::AS)?;
|
|
||||||
let statements = Some(parser.parse_conditional_statements(&[Keyword::END])?);
|
|
||||||
|
|
||||||
Ok(Statement::CreateTrigger {
|
|
||||||
or_alter,
|
|
||||||
or_replace: false,
|
|
||||||
is_constraint: false,
|
|
||||||
name,
|
|
||||||
period,
|
|
||||||
events,
|
|
||||||
table_name,
|
|
||||||
referenced_table_name: None,
|
|
||||||
referencing: Vec::new(),
|
|
||||||
trigger_object: TriggerObject::Statement,
|
|
||||||
include_each: false,
|
|
||||||
condition: None,
|
|
||||||
exec_body: None,
|
|
||||||
statements,
|
|
||||||
characteristics: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a sequence of statements, optionally separated by semicolon.
|
|
||||||
///
|
|
||||||
/// Stops parsing when reaching EOF or the given keyword.
|
|
||||||
fn parse_statement_list(
|
|
||||||
&self,
|
|
||||||
parser: &mut Parser,
|
|
||||||
terminal_keyword: Option<Keyword>,
|
|
||||||
) -> Result<Vec<Statement>, ParserError> {
|
|
||||||
let mut stmts = Vec::new();
|
|
||||||
loop {
|
|
||||||
if let Token::EOF = parser.peek_token_ref().token {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Some(term) = terminal_keyword {
|
|
||||||
if parser.peek_keyword(term) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stmts.push(parser.parse_statement()?);
|
|
||||||
while let Token::SemiColon = parser.peek_token_ref().token {
|
|
||||||
parser.advance_token();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(stmts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
@ -25,15 +20,6 @@ use crate::{
|
||||||
parser::{Parser, ParserError},
|
parser::{Parser, ParserError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::keywords;
|
|
||||||
|
|
||||||
const RESERVED_FOR_TABLE_ALIAS_MYSQL: &[Keyword] = &[
|
|
||||||
Keyword::USE,
|
|
||||||
Keyword::IGNORE,
|
|
||||||
Keyword::FORCE,
|
|
||||||
Keyword::STRAIGHT_JOIN,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// A [`Dialect`] for [MySQL](https://www.mysql.com/)
|
/// A [`Dialect`] for [MySQL](https://www.mysql.com/)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MySqlDialect {}
|
pub struct MySqlDialect {}
|
||||||
|
@ -67,10 +53,6 @@ impl Dialect for MySqlDialect {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ignores_wildcard_escapes(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_numeric_prefix(&self) -> bool {
|
fn supports_numeric_prefix(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -102,54 +84,6 @@ impl Dialect for MySqlDialect {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_interval_qualifier(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_limit_comma(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table-select.html>
|
|
||||||
fn supports_create_table_select(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
|
|
||||||
fn supports_insert_set(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_user_host_grantee(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser: &mut Parser) -> bool {
|
|
||||||
explicit
|
|
||||||
|| (!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
|
|
||||||
&& !RESERVED_FOR_TABLE_ALIAS_MYSQL.contains(kw))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_table_hints(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn requires_single_line_comment_whitespace(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_match_against(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_set_names(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_comma_separated_set_assignments(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `LOCK TABLES`
|
/// `LOCK TABLES`
|
||||||
|
@ -161,7 +95,7 @@ fn parse_lock_tables(parser: &mut Parser) -> Result<Statement, ParserError> {
|
||||||
|
|
||||||
// tbl_name [[AS] alias] lock_type
|
// tbl_name [[AS] alias] lock_type
|
||||||
fn parse_lock_table(parser: &mut Parser) -> Result<LockTable, ParserError> {
|
fn parse_lock_table(parser: &mut Parser) -> Result<LockTable, ParserError> {
|
||||||
let table = parser.parse_identifier()?;
|
let table = parser.parse_identifier(false)?;
|
||||||
let alias =
|
let alias =
|
||||||
parser.parse_optional_alias(&[Keyword::READ, Keyword::WRITE, Keyword::LOW_PRIORITY])?;
|
parser.parse_optional_alias(&[Keyword::READ, Keyword::WRITE, Keyword::LOW_PRIORITY])?;
|
||||||
let lock_type = parse_lock_tables_type(parser)?;
|
let lock_type = parse_lock_tables_type(parser)?;
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
@ -26,9 +9,9 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
use crate::dialect::{Dialect, Precedence};
|
use crate::ast::{CommentObject, Statement};
|
||||||
|
use crate::dialect::Dialect;
|
||||||
use crate::keywords::Keyword;
|
use crate::keywords::Keyword;
|
||||||
use crate::parser::{Parser, ParserError};
|
use crate::parser::{Parser, ParserError};
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
|
@ -37,24 +20,6 @@ use crate::tokenizer::Token;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PostgreSqlDialect {}
|
pub struct PostgreSqlDialect {}
|
||||||
|
|
||||||
const PERIOD_PREC: u8 = 200;
|
|
||||||
const DOUBLE_COLON_PREC: u8 = 140;
|
|
||||||
const BRACKET_PREC: u8 = 130;
|
|
||||||
const COLLATE_PREC: u8 = 120;
|
|
||||||
const AT_TZ_PREC: u8 = 110;
|
|
||||||
const CARET_PREC: u8 = 100;
|
|
||||||
const MUL_DIV_MOD_OP_PREC: u8 = 90;
|
|
||||||
const PLUS_MINUS_PREC: u8 = 80;
|
|
||||||
// there's no XOR operator in PostgreSQL, but support it here to avoid breaking tests
|
|
||||||
const XOR_PREC: u8 = 75;
|
|
||||||
const PG_OTHER_PREC: u8 = 70;
|
|
||||||
const BETWEEN_LIKE_PREC: u8 = 60;
|
|
||||||
const EQ_PREC: u8 = 50;
|
|
||||||
const IS_PREC: u8 = 40;
|
|
||||||
const NOT_PREC: u8 = 30;
|
|
||||||
const AND_PREC: u8 = 20;
|
|
||||||
const OR_PREC: u8 = 10;
|
|
||||||
|
|
||||||
impl Dialect for PostgreSqlDialect {
|
impl Dialect for PostgreSqlDialect {
|
||||||
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
|
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
|
||||||
Some('"')
|
Some('"')
|
||||||
|
@ -75,10 +40,6 @@ impl Dialect for PostgreSqlDialect {
|
||||||
ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
|
ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_unicode_string_literal(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
|
/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
|
||||||
fn is_custom_operator_part(&self, ch: char) -> bool {
|
fn is_custom_operator_part(&self, ch: char) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -102,36 +63,11 @@ impl Dialect for PostgreSqlDialect {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
|
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
|
||||||
let token = parser.peek_token();
|
if parser.parse_keyword(Keyword::COMMENT) {
|
||||||
debug!("get_next_precedence() {token:?}");
|
Some(parse_comment(parser))
|
||||||
|
} else {
|
||||||
// we only return some custom value here when the behaviour (not merely the numeric value) differs
|
None
|
||||||
// from the default implementation
|
|
||||||
match token.token {
|
|
||||||
Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)),
|
|
||||||
Token::LBracket => Some(Ok(BRACKET_PREC)),
|
|
||||||
Token::Arrow
|
|
||||||
| Token::LongArrow
|
|
||||||
| Token::HashArrow
|
|
||||||
| Token::HashLongArrow
|
|
||||||
| Token::AtArrow
|
|
||||||
| Token::ArrowAt
|
|
||||||
| Token::HashMinus
|
|
||||||
| Token::AtQuestion
|
|
||||||
| Token::AtAt
|
|
||||||
| Token::Question
|
|
||||||
| Token::QuestionAnd
|
|
||||||
| Token::QuestionPipe
|
|
||||||
| Token::ExclamationMark
|
|
||||||
| Token::Overlap
|
|
||||||
| Token::CaretAt
|
|
||||||
| Token::StringConcat
|
|
||||||
| Token::Sharp
|
|
||||||
| Token::ShiftRight
|
|
||||||
| Token::ShiftLeft
|
|
||||||
| Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,124 +78,36 @@ impl Dialect for PostgreSqlDialect {
|
||||||
fn supports_group_by_expr(&self) -> bool {
|
fn supports_group_by_expr(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn prec_value(&self, prec: Precedence) -> u8 {
|
|
||||||
match prec {
|
pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
|
||||||
Precedence::Period => PERIOD_PREC,
|
let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||||
Precedence::DoubleColon => DOUBLE_COLON_PREC,
|
|
||||||
Precedence::AtTz => AT_TZ_PREC,
|
parser.expect_keyword(Keyword::ON)?;
|
||||||
Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
|
let token = parser.next_token();
|
||||||
Precedence::PlusMinus => PLUS_MINUS_PREC,
|
|
||||||
Precedence::Xor => XOR_PREC,
|
let (object_type, object_name) = match token.token {
|
||||||
Precedence::Ampersand => PG_OTHER_PREC,
|
Token::Word(w) if w.keyword == Keyword::COLUMN => {
|
||||||
Precedence::Caret => CARET_PREC,
|
let object_name = parser.parse_object_name(false)?;
|
||||||
Precedence::Pipe => PG_OTHER_PREC,
|
(CommentObject::Column, object_name)
|
||||||
Precedence::Between => BETWEEN_LIKE_PREC,
|
}
|
||||||
Precedence::Eq => EQ_PREC,
|
Token::Word(w) if w.keyword == Keyword::TABLE => {
|
||||||
Precedence::Like => BETWEEN_LIKE_PREC,
|
let object_name = parser.parse_object_name(false)?;
|
||||||
Precedence::Is => IS_PREC,
|
(CommentObject::Table, object_name)
|
||||||
Precedence::PgOther => PG_OTHER_PREC,
|
}
|
||||||
Precedence::UnaryNot => NOT_PREC,
|
_ => parser.expected("comment object_type", token)?,
|
||||||
Precedence::And => AND_PREC,
|
};
|
||||||
Precedence::Or => OR_PREC,
|
|
||||||
}
|
parser.expect_keyword(Keyword::IS)?;
|
||||||
}
|
let comment = if parser.parse_keyword(Keyword::NULL) {
|
||||||
|
None
|
||||||
fn allow_extract_custom(&self) -> bool {
|
} else {
|
||||||
true
|
Some(parser.parse_literal_string()?)
|
||||||
}
|
};
|
||||||
|
Ok(Statement::Comment {
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
object_type,
|
||||||
true
|
object_name,
|
||||||
}
|
comment,
|
||||||
|
if_exists,
|
||||||
fn supports_create_index_with_clause(&self) -> bool {
|
})
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// see <https://www.postgresql.org/docs/current/sql-explain.html>
|
|
||||||
fn supports_explain_with_utility_options(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// see <https://www.postgresql.org/docs/current/sql-listen.html>
|
|
||||||
/// see <https://www.postgresql.org/docs/current/sql-unlisten.html>
|
|
||||||
/// see <https://www.postgresql.org/docs/current/sql-notify.html>
|
|
||||||
fn supports_listen_notify(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// see <https://www.postgresql.org/docs/13/functions-math.html>
|
|
||||||
fn supports_factorial_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// see <https://www.postgresql.org/docs/current/sql-comment.html>
|
|
||||||
fn supports_comment_on(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://www.postgresql.org/docs/current/sql-load.html>
|
|
||||||
fn supports_load_extension(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://www.postgresql.org/docs/current/functions-json.html>
|
|
||||||
///
|
|
||||||
/// Required to support the colon in:
|
|
||||||
/// ```sql
|
|
||||||
/// SELECT json_object('a': 'b')
|
|
||||||
/// ```
|
|
||||||
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See <https://www.postgresql.org/docs/current/functions-json.html>
|
|
||||||
///
|
|
||||||
/// Required to support the label in:
|
|
||||||
/// ```sql
|
|
||||||
/// SELECT json_object('label': 'value')
|
|
||||||
/// ```
|
|
||||||
fn supports_named_fn_args_with_expr_name(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the dialect supports empty projections in SELECT statements
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// ```sql
|
|
||||||
/// SELECT from table_name
|
|
||||||
/// ```
|
|
||||||
fn supports_empty_projections(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_nested_comments(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_string_escape_constant(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_numeric_literal_underscores(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See: <https://www.postgresql.org/docs/current/arrays.html#ARRAYS-DECLARATION>
|
|
||||||
fn supports_array_typedef_with_brackets(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_geometric_types(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_set_names(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_alter_column_type_using(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
use core::iter::Peekable;
|
use core::iter::Peekable;
|
||||||
|
@ -32,63 +27,31 @@ pub struct RedshiftSqlDialect {}
|
||||||
// in the Postgres dialect, the query will be parsed as an array, while in the Redshift dialect it will
|
// in the Postgres dialect, the query will be parsed as an array, while in the Redshift dialect it will
|
||||||
// be a json path
|
// be a json path
|
||||||
impl Dialect for RedshiftSqlDialect {
|
impl Dialect for RedshiftSqlDialect {
|
||||||
/// Determine if a character starts a potential nested quoted identifier.
|
fn is_delimited_identifier_start(&self, ch: char) -> bool {
|
||||||
/// Example: RedShift supports the following quote styles to all mean the same thing:
|
ch == '"' || ch == '['
|
||||||
/// ```sql
|
|
||||||
/// SELECT 1 AS foo;
|
|
||||||
/// SELECT 1 AS "foo";
|
|
||||||
/// SELECT 1 AS [foo];
|
|
||||||
/// SELECT 1 AS ["foo"];
|
|
||||||
/// ```
|
|
||||||
fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
|
|
||||||
ch == '['
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only applicable whenever [`Self::is_nested_delimited_identifier_start`] returns true
|
/// Determine if quoted characters are proper for identifier
|
||||||
/// If the next sequence of tokens potentially represent a nested identifier, then this method
|
/// It's needed to distinguish treating square brackets as quotes from
|
||||||
/// returns a tuple containing the outer quote style, and if present, the inner (nested) quote style.
|
/// treating them as json path. If there is identifier then we assume
|
||||||
///
|
/// there is no json path.
|
||||||
/// Example (Redshift):
|
fn is_proper_identifier_inside_quotes(&self, mut chars: Peekable<Chars<'_>>) -> bool {
|
||||||
/// ```text
|
|
||||||
/// `["foo"]` => Some(`[`, Some(`"`))
|
|
||||||
/// `[foo]` => Some(`[`, None)
|
|
||||||
/// `[0]` => None
|
|
||||||
/// `"foo"` => None
|
|
||||||
/// ```
|
|
||||||
fn peek_nested_delimited_identifier_quotes(
|
|
||||||
&self,
|
|
||||||
mut chars: Peekable<Chars<'_>>,
|
|
||||||
) -> Option<(char, Option<char>)> {
|
|
||||||
if chars.peek() != Some(&'[') {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
chars.next();
|
chars.next();
|
||||||
|
|
||||||
let mut not_white_chars = chars.skip_while(|ch| ch.is_whitespace()).peekable();
|
let mut not_white_chars = chars.skip_while(|ch| ch.is_whitespace()).peekable();
|
||||||
|
|
||||||
if let Some(&ch) = not_white_chars.peek() {
|
if let Some(&ch) = not_white_chars.peek() {
|
||||||
if ch == '"' {
|
return self.is_identifier_start(ch);
|
||||||
return Some(('[', Some('"')));
|
|
||||||
}
|
|
||||||
if self.is_identifier_start(ch) {
|
|
||||||
return Some(('[', None));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
false
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_identifier_start(&self, ch: char) -> bool {
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
// Extends Postgres dialect with sharp and UTF-8 multibyte chars
|
// Extends Postgres dialect with sharp
|
||||||
// https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
|
PostgreSqlDialect {}.is_identifier_start(ch) || ch == '#'
|
||||||
PostgreSqlDialect {}.is_identifier_start(ch) || ch == '#' || !ch.is_ascii()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_identifier_part(&self, ch: char) -> bool {
|
fn is_identifier_part(&self, ch: char) -> bool {
|
||||||
// Extends Postgres dialect with sharp and UTF-8 multibyte chars
|
// Extends Postgres dialect with sharp
|
||||||
// https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
|
PostgreSqlDialect {}.is_identifier_part(ch) || ch == '#'
|
||||||
PostgreSqlDialect {}.is_identifier_part(ch) || ch == '#' || !ch.is_ascii()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// redshift has `CONVERT(type, value)` instead of `CONVERT(value, type)`
|
/// redshift has `CONVERT(type, value)` instead of `CONVERT(value, type)`
|
||||||
|
@ -100,43 +63,4 @@ impl Dialect for RedshiftSqlDialect {
|
||||||
fn supports_connect_by(&self) -> bool {
|
fn supports_connect_by(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redshift expects the `TOP` option before the `ALL/DISTINCT` option:
|
|
||||||
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_SELECT_list.html#r_SELECT_list-parameters>
|
|
||||||
fn supports_top_before_distinct(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Redshift supports PartiQL: <https://docs.aws.amazon.com/redshift/latest/dg/super-overview.html>
|
|
||||||
fn supports_partiql(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_string_escape_constant(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_geometric_types(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_array_typedef_with_brackets(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_string_literal_backslash_escape(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_select_wildcard_exclude(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_select_exclude(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,25 +1,16 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
use crate::ast::Statement;
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
use crate::ast::BinaryOperator;
|
|
||||||
use crate::ast::{Expr, Statement};
|
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
use crate::keywords::Keyword;
|
use crate::keywords::Keyword;
|
||||||
use crate::parser::{Parser, ParserError};
|
use crate::parser::{Parser, ParserError};
|
||||||
|
@ -50,6 +41,7 @@ impl Dialect for SQLiteDialect {
|
||||||
ch.is_ascii_lowercase()
|
ch.is_ascii_lowercase()
|
||||||
|| ch.is_ascii_uppercase()
|
|| ch.is_ascii_uppercase()
|
||||||
|| ch == '_'
|
|| ch == '_'
|
||||||
|
|| ch == '$'
|
||||||
|| ('\u{007f}'..='\u{ffff}').contains(&ch)
|
|| ('\u{007f}'..='\u{ffff}').contains(&ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,40 +66,7 @@ impl Dialect for SQLiteDialect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_infix(
|
|
||||||
&self,
|
|
||||||
parser: &mut crate::parser::Parser,
|
|
||||||
expr: &crate::ast::Expr,
|
|
||||||
_precedence: u8,
|
|
||||||
) -> Option<Result<crate::ast::Expr, ParserError>> {
|
|
||||||
// Parse MATCH and REGEXP as operators
|
|
||||||
// See <https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators>
|
|
||||||
for (keyword, op) in [
|
|
||||||
(Keyword::REGEXP, BinaryOperator::Regexp),
|
|
||||||
(Keyword::MATCH, BinaryOperator::Match),
|
|
||||||
] {
|
|
||||||
if parser.parse_keyword(keyword) {
|
|
||||||
let left = Box::new(expr.clone());
|
|
||||||
let right = Box::new(parser.parse_expr().unwrap());
|
|
||||||
return Some(Ok(Expr::BinaryOp { left, op, right }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_in_empty_list(&self) -> bool {
|
fn supports_in_empty_list(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_limit_comma(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_asc_desc_in_column_definition(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_dollar_placeholder(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! Utilities for formatting SQL AST nodes with pretty printing support.
|
|
||||||
//!
|
|
||||||
//! The module provides formatters that implement the `Display` trait with support
|
|
||||||
//! for both regular (`{}`) and pretty (`{:#}`) formatting modes. Pretty printing
|
|
||||||
//! adds proper indentation and line breaks to make SQL statements more readable.
|
|
||||||
|
|
||||||
use core::fmt::{self, Display, Write};
|
|
||||||
|
|
||||||
/// A wrapper around a value that adds an indent to the value when displayed with {:#}.
|
|
||||||
pub(crate) struct Indent<T>(pub T);
|
|
||||||
|
|
||||||
const INDENT: &str = " ";
|
|
||||||
|
|
||||||
impl<T> Display for Indent<T>
|
|
||||||
where
|
|
||||||
T: Display,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if f.alternate() {
|
|
||||||
f.write_str(INDENT)?;
|
|
||||||
write!(Indent(f), "{:#}", self.0)
|
|
||||||
} else {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an indent to the inner writer
|
|
||||||
impl<T> Write for Indent<T>
|
|
||||||
where
|
|
||||||
T: Write,
|
|
||||||
{
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
self.0.write_str(s)?;
|
|
||||||
// Our NewLine and SpaceOrNewline utils always print individual newlines as a single-character string.
|
|
||||||
if s == "\n" {
|
|
||||||
self.0.write_str(INDENT)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value that inserts a newline when displayed with {:#}, but not when displayed with {}.
|
|
||||||
pub(crate) struct NewLine;
|
|
||||||
|
|
||||||
impl Display for NewLine {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if f.alternate() {
|
|
||||||
f.write_char('\n')
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value that inserts a space when displayed with {}, but a newline when displayed with {:#}.
|
|
||||||
pub(crate) struct SpaceOrNewline;
|
|
||||||
|
|
||||||
impl Display for SpaceOrNewline {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if f.alternate() {
|
|
||||||
f.write_char('\n')
|
|
||||||
} else {
|
|
||||||
f.write_char(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value that displays a comma-separated list of values.
|
|
||||||
/// When pretty-printed (using {:#}), it displays each value on a new line.
|
|
||||||
pub(crate) struct DisplayCommaSeparated<'a, T: fmt::Display>(pub(crate) &'a [T]);
|
|
||||||
|
|
||||||
impl<T: fmt::Display> fmt::Display for DisplayCommaSeparated<'_, T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let mut first = true;
|
|
||||||
for t in self.0 {
|
|
||||||
if !first {
|
|
||||||
f.write_char(',')?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
t.fmt(f)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Displays a whitespace, followed by a comma-separated list that is indented when pretty-printed.
|
|
||||||
pub(crate) fn indented_list<T: fmt::Display>(f: &mut fmt::Formatter, items: &[T]) -> fmt::Result {
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
Indent(DisplayCommaSeparated(items)).fmt(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_indent() {
|
|
||||||
struct TwoLines;
|
|
||||||
|
|
||||||
impl Display for TwoLines {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.write_str("line 1")?;
|
|
||||||
SpaceOrNewline.fmt(f)?;
|
|
||||||
f.write_str("line 2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let indent = Indent(TwoLines);
|
|
||||||
assert_eq!(
|
|
||||||
indent.to_string(),
|
|
||||||
TwoLines.to_string(),
|
|
||||||
"Only the alternate form should be indented"
|
|
||||||
);
|
|
||||||
assert_eq!(format!("{:#}", indent), " line 1\n line 2");
|
|
||||||
}
|
|
||||||
}
|
|
282
src/keywords.rs
282
src/keywords.rs
|
@ -1,31 +1,26 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! This module defines
|
//! This module defines
|
||||||
//! 1) a list of constants for every keyword
|
//! 1) a list of constants for every keyword
|
||||||
//! 2) an `ALL_KEYWORDS` array with every keyword in it
|
//! 2) an `ALL_KEYWORDS` array with every keyword in it
|
||||||
//! This is not a list of *reserved* keywords: some of these can be
|
//! This is not a list of *reserved* keywords: some of these can be
|
||||||
//! parsed as identifiers if the parser decides so. This means that
|
//! parsed as identifiers if the parser decides so. This means that
|
||||||
//! new keywords can be added here without affecting the parse result.
|
//! new keywords can be added here without affecting the parse result.
|
||||||
//!
|
//!
|
||||||
//! As a matter of fact, most of these keywords are not used at all
|
//! As a matter of fact, most of these keywords are not used at all
|
||||||
//! and could be removed.
|
//! and could be removed.
|
||||||
//! 3) a `RESERVED_FOR_TABLE_ALIAS` array with keywords reserved in a
|
//! 3) a `RESERVED_FOR_TABLE_ALIAS` array with keywords reserved in a
|
||||||
//! "table alias" context.
|
//! "table alias" context.
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -74,19 +69,14 @@ macro_rules! define_keywords {
|
||||||
define_keywords!(
|
define_keywords!(
|
||||||
ABORT,
|
ABORT,
|
||||||
ABS,
|
ABS,
|
||||||
ABSENT,
|
|
||||||
ABSOLUTE,
|
ABSOLUTE,
|
||||||
ACCESS,
|
ACCESS,
|
||||||
ACCOUNT,
|
|
||||||
ACTION,
|
ACTION,
|
||||||
ADD,
|
ADD,
|
||||||
ADMIN,
|
ADMIN,
|
||||||
AFTER,
|
AFTER,
|
||||||
AGAINST,
|
AGAINST,
|
||||||
AGGREGATE,
|
|
||||||
AGGREGATION,
|
AGGREGATION,
|
||||||
ALERT,
|
|
||||||
ALGORITHM,
|
|
||||||
ALIAS,
|
ALIAS,
|
||||||
ALL,
|
ALL,
|
||||||
ALLOCATE,
|
ALLOCATE,
|
||||||
|
@ -96,9 +86,7 @@ define_keywords!(
|
||||||
AND,
|
AND,
|
||||||
ANTI,
|
ANTI,
|
||||||
ANY,
|
ANY,
|
||||||
APPLICATION,
|
|
||||||
APPLY,
|
APPLY,
|
||||||
APPLYBUDGET,
|
|
||||||
ARCHIVE,
|
ARCHIVE,
|
||||||
ARE,
|
ARE,
|
||||||
ARRAY,
|
ARRAY,
|
||||||
|
@ -112,45 +100,30 @@ define_keywords!(
|
||||||
AT,
|
AT,
|
||||||
ATOMIC,
|
ATOMIC,
|
||||||
ATTACH,
|
ATTACH,
|
||||||
AUDIT,
|
|
||||||
AUTHENTICATION,
|
|
||||||
AUTHORIZATION,
|
AUTHORIZATION,
|
||||||
AUTO,
|
AUTO,
|
||||||
AUTOEXTEND_SIZE,
|
|
||||||
AUTOINCREMENT,
|
AUTOINCREMENT,
|
||||||
AUTO_INCREMENT,
|
AUTO_INCREMENT,
|
||||||
AVG,
|
AVG,
|
||||||
AVG_ROW_LENGTH,
|
|
||||||
AVRO,
|
AVRO,
|
||||||
BACKWARD,
|
BACKWARD,
|
||||||
BASE64,
|
BASE64,
|
||||||
BASE_LOCATION,
|
|
||||||
BEFORE,
|
|
||||||
BEGIN,
|
BEGIN,
|
||||||
BEGIN_FRAME,
|
BEGIN_FRAME,
|
||||||
BEGIN_PARTITION,
|
BEGIN_PARTITION,
|
||||||
BERNOULLI,
|
|
||||||
BETWEEN,
|
BETWEEN,
|
||||||
BIGDECIMAL,
|
BIGDECIMAL,
|
||||||
BIGINT,
|
BIGINT,
|
||||||
BIGNUMERIC,
|
BIGNUMERIC,
|
||||||
BINARY,
|
BINARY,
|
||||||
BIND,
|
|
||||||
BINDING,
|
BINDING,
|
||||||
BIT,
|
|
||||||
BLOB,
|
BLOB,
|
||||||
BLOCK,
|
|
||||||
BLOOM,
|
|
||||||
BLOOMFILTER,
|
BLOOMFILTER,
|
||||||
BOOL,
|
BOOL,
|
||||||
BOOLEAN,
|
BOOLEAN,
|
||||||
BOTH,
|
BOTH,
|
||||||
BOX,
|
|
||||||
BRIN,
|
|
||||||
BROWSE,
|
BROWSE,
|
||||||
BTREE,
|
BTREE,
|
||||||
BUCKET,
|
|
||||||
BUCKETS,
|
|
||||||
BY,
|
BY,
|
||||||
BYPASSRLS,
|
BYPASSRLS,
|
||||||
BYTEA,
|
BYTEA,
|
||||||
|
@ -162,11 +135,7 @@ define_keywords!(
|
||||||
CASCADE,
|
CASCADE,
|
||||||
CASCADED,
|
CASCADED,
|
||||||
CASE,
|
CASE,
|
||||||
CASES,
|
|
||||||
CAST,
|
CAST,
|
||||||
CATALOG,
|
|
||||||
CATALOG_SYNC,
|
|
||||||
CATCH,
|
|
||||||
CEIL,
|
CEIL,
|
||||||
CEILING,
|
CEILING,
|
||||||
CENTURY,
|
CENTURY,
|
||||||
|
@ -176,21 +145,15 @@ define_keywords!(
|
||||||
CHANNEL,
|
CHANNEL,
|
||||||
CHAR,
|
CHAR,
|
||||||
CHARACTER,
|
CHARACTER,
|
||||||
CHARACTERISTICS,
|
|
||||||
CHARACTERS,
|
CHARACTERS,
|
||||||
CHARACTER_LENGTH,
|
CHARACTER_LENGTH,
|
||||||
CHARSET,
|
CHARSET,
|
||||||
CHAR_LENGTH,
|
CHAR_LENGTH,
|
||||||
CHECK,
|
CHECK,
|
||||||
CHECKSUM,
|
|
||||||
CIRCLE,
|
|
||||||
CLEAR,
|
|
||||||
CLOB,
|
CLOB,
|
||||||
CLONE,
|
CLONE,
|
||||||
CLOSE,
|
CLOSE,
|
||||||
CLUSTER,
|
CLUSTER,
|
||||||
CLUSTERED,
|
|
||||||
CLUSTERING,
|
|
||||||
COALESCE,
|
COALESCE,
|
||||||
COLLATE,
|
COLLATE,
|
||||||
COLLATION,
|
COLLATION,
|
||||||
|
@ -198,11 +161,9 @@ define_keywords!(
|
||||||
COLLECTION,
|
COLLECTION,
|
||||||
COLUMN,
|
COLUMN,
|
||||||
COLUMNS,
|
COLUMNS,
|
||||||
COLUMNSTORE,
|
|
||||||
COMMENT,
|
COMMENT,
|
||||||
COMMIT,
|
COMMIT,
|
||||||
COMMITTED,
|
COMMITTED,
|
||||||
COMPATIBLE,
|
|
||||||
COMPRESSION,
|
COMPRESSION,
|
||||||
COMPUTE,
|
COMPUTE,
|
||||||
CONCURRENTLY,
|
CONCURRENTLY,
|
||||||
|
@ -210,11 +171,8 @@ define_keywords!(
|
||||||
CONFLICT,
|
CONFLICT,
|
||||||
CONNECT,
|
CONNECT,
|
||||||
CONNECTION,
|
CONNECTION,
|
||||||
CONNECTOR,
|
|
||||||
CONNECT_BY_ROOT,
|
|
||||||
CONSTRAINT,
|
CONSTRAINT,
|
||||||
CONTAINS,
|
CONTAINS,
|
||||||
CONTINUE,
|
|
||||||
CONVERT,
|
CONVERT,
|
||||||
COPY,
|
COPY,
|
||||||
COPY_OPTIONS,
|
COPY_OPTIONS,
|
||||||
|
@ -247,7 +205,6 @@ define_keywords!(
|
||||||
CYCLE,
|
CYCLE,
|
||||||
DATA,
|
DATA,
|
||||||
DATABASE,
|
DATABASE,
|
||||||
DATABASES,
|
|
||||||
DATA_RETENTION_TIME_IN_DAYS,
|
DATA_RETENTION_TIME_IN_DAYS,
|
||||||
DATE,
|
DATE,
|
||||||
DATE32,
|
DATE32,
|
||||||
|
@ -256,29 +213,23 @@ define_keywords!(
|
||||||
DAY,
|
DAY,
|
||||||
DAYOFWEEK,
|
DAYOFWEEK,
|
||||||
DAYOFYEAR,
|
DAYOFYEAR,
|
||||||
DAYS,
|
|
||||||
DCPROPERTIES,
|
|
||||||
DEALLOCATE,
|
DEALLOCATE,
|
||||||
DEC,
|
DEC,
|
||||||
DECADE,
|
DECADE,
|
||||||
DECIMAL,
|
DECIMAL,
|
||||||
DECLARE,
|
DECLARE,
|
||||||
DEDUPLICATE,
|
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
DEFAULT_DDL_COLLATION,
|
DEFAULT_DDL_COLLATION,
|
||||||
DEFERRABLE,
|
DEFERRABLE,
|
||||||
DEFERRED,
|
DEFERRED,
|
||||||
DEFINE,
|
DEFINE,
|
||||||
DEFINED,
|
DEFINED,
|
||||||
DEFINER,
|
|
||||||
DELAYED,
|
DELAYED,
|
||||||
DELAY_KEY_WRITE,
|
|
||||||
DELETE,
|
DELETE,
|
||||||
DELIMITED,
|
DELIMITED,
|
||||||
DELIMITER,
|
DELIMITER,
|
||||||
DELTA,
|
DELTA,
|
||||||
DENSE_RANK,
|
DENSE_RANK,
|
||||||
DENY,
|
|
||||||
DEREF,
|
DEREF,
|
||||||
DESC,
|
DESC,
|
||||||
DESCRIBE,
|
DESCRIBE,
|
||||||
|
@ -293,7 +244,6 @@ define_keywords!(
|
||||||
DISTRIBUTE,
|
DISTRIBUTE,
|
||||||
DIV,
|
DIV,
|
||||||
DO,
|
DO,
|
||||||
DOMAIN,
|
|
||||||
DOUBLE,
|
DOUBLE,
|
||||||
DOW,
|
DOW,
|
||||||
DOY,
|
DOY,
|
||||||
|
@ -305,7 +255,6 @@ define_keywords!(
|
||||||
ELEMENT,
|
ELEMENT,
|
||||||
ELEMENTS,
|
ELEMENTS,
|
||||||
ELSE,
|
ELSE,
|
||||||
ELSEIF,
|
|
||||||
EMPTY,
|
EMPTY,
|
||||||
ENABLE,
|
ENABLE,
|
||||||
ENABLE_SCHEMA_EVOLUTION,
|
ENABLE_SCHEMA_EVOLUTION,
|
||||||
|
@ -318,42 +267,32 @@ define_keywords!(
|
||||||
END_PARTITION,
|
END_PARTITION,
|
||||||
ENFORCED,
|
ENFORCED,
|
||||||
ENGINE,
|
ENGINE,
|
||||||
ENGINE_ATTRIBUTE,
|
|
||||||
ENUM,
|
ENUM,
|
||||||
ENUM16,
|
|
||||||
ENUM8,
|
|
||||||
EPHEMERAL,
|
EPHEMERAL,
|
||||||
EPOCH,
|
EPOCH,
|
||||||
EQUALS,
|
EQUALS,
|
||||||
ERROR,
|
ERROR,
|
||||||
ESCAPE,
|
ESCAPE,
|
||||||
ESCAPED,
|
ESCAPED,
|
||||||
ESTIMATE,
|
|
||||||
EVENT,
|
EVENT,
|
||||||
EVERY,
|
EVERY,
|
||||||
EVOLVE,
|
|
||||||
EXCEPT,
|
EXCEPT,
|
||||||
EXCEPTION,
|
EXCEPTION,
|
||||||
EXCHANGE,
|
|
||||||
EXCLUDE,
|
EXCLUDE,
|
||||||
EXCLUSIVE,
|
EXCLUSIVE,
|
||||||
EXEC,
|
EXEC,
|
||||||
EXECUTE,
|
EXECUTE,
|
||||||
EXECUTION,
|
|
||||||
EXISTS,
|
EXISTS,
|
||||||
EXP,
|
EXP,
|
||||||
EXPANSION,
|
EXPANSION,
|
||||||
EXPLAIN,
|
EXPLAIN,
|
||||||
EXPLICIT,
|
EXPLICIT,
|
||||||
EXPORT,
|
EXPORT,
|
||||||
EXTEND,
|
|
||||||
EXTENDED,
|
EXTENDED,
|
||||||
EXTENSION,
|
EXTENSION,
|
||||||
EXTERNAL,
|
EXTERNAL,
|
||||||
EXTERNAL_VOLUME,
|
|
||||||
EXTRACT,
|
EXTRACT,
|
||||||
FAIL,
|
FAIL,
|
||||||
FAILOVER,
|
|
||||||
FALSE,
|
FALSE,
|
||||||
FETCH,
|
FETCH,
|
||||||
FIELDS,
|
FIELDS,
|
||||||
|
@ -362,7 +301,6 @@ define_keywords!(
|
||||||
FILE_FORMAT,
|
FILE_FORMAT,
|
||||||
FILL,
|
FILL,
|
||||||
FILTER,
|
FILTER,
|
||||||
FINAL,
|
|
||||||
FIRST,
|
FIRST,
|
||||||
FIRST_VALUE,
|
FIRST_VALUE,
|
||||||
FIXEDSTRING,
|
FIXEDSTRING,
|
||||||
|
@ -373,7 +311,6 @@ define_keywords!(
|
||||||
FLOAT8,
|
FLOAT8,
|
||||||
FLOOR,
|
FLOOR,
|
||||||
FLUSH,
|
FLUSH,
|
||||||
FN,
|
|
||||||
FOLLOWING,
|
FOLLOWING,
|
||||||
FOR,
|
FOR,
|
||||||
FORCE,
|
FORCE,
|
||||||
|
@ -389,20 +326,16 @@ define_keywords!(
|
||||||
FREEZE,
|
FREEZE,
|
||||||
FROM,
|
FROM,
|
||||||
FSCK,
|
FSCK,
|
||||||
FULFILLMENT,
|
|
||||||
FULL,
|
FULL,
|
||||||
FULLTEXT,
|
FULLTEXT,
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
FUNCTIONS,
|
FUNCTIONS,
|
||||||
FUSION,
|
FUSION,
|
||||||
FUTURE,
|
|
||||||
GENERAL,
|
GENERAL,
|
||||||
GENERATE,
|
GENERATE,
|
||||||
GENERATED,
|
GENERATED,
|
||||||
GEOGRAPHY,
|
GEOGRAPHY,
|
||||||
GET,
|
GET,
|
||||||
GIN,
|
|
||||||
GIST,
|
|
||||||
GLOBAL,
|
GLOBAL,
|
||||||
GRANT,
|
GRANT,
|
||||||
GRANTED,
|
GRANTED,
|
||||||
|
@ -414,7 +347,6 @@ define_keywords!(
|
||||||
HASH,
|
HASH,
|
||||||
HAVING,
|
HAVING,
|
||||||
HEADER,
|
HEADER,
|
||||||
HEAP,
|
|
||||||
HIGH_PRIORITY,
|
HIGH_PRIORITY,
|
||||||
HISTORY,
|
HISTORY,
|
||||||
HIVEVAR,
|
HIVEVAR,
|
||||||
|
@ -422,18 +354,12 @@ define_keywords!(
|
||||||
HOSTS,
|
HOSTS,
|
||||||
HOUR,
|
HOUR,
|
||||||
HOURS,
|
HOURS,
|
||||||
HUGEINT,
|
|
||||||
ICEBERG,
|
|
||||||
ID,
|
|
||||||
IDENTITY,
|
IDENTITY,
|
||||||
IDENTITY_INSERT,
|
|
||||||
IF,
|
IF,
|
||||||
IGNORE,
|
IGNORE,
|
||||||
ILIKE,
|
ILIKE,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
IMMUTABLE,
|
IMMUTABLE,
|
||||||
IMPORT,
|
|
||||||
IMPORTED,
|
|
||||||
IN,
|
IN,
|
||||||
INCLUDE,
|
INCLUDE,
|
||||||
INCLUDE_NULL_VALUES,
|
INCLUDE_NULL_VALUES,
|
||||||
|
@ -441,20 +367,14 @@ define_keywords!(
|
||||||
INDEX,
|
INDEX,
|
||||||
INDICATOR,
|
INDICATOR,
|
||||||
INHERIT,
|
INHERIT,
|
||||||
INHERITS,
|
|
||||||
INITIALLY,
|
INITIALLY,
|
||||||
INNER,
|
INNER,
|
||||||
INOUT,
|
INOUT,
|
||||||
INPATH,
|
|
||||||
INPLACE,
|
|
||||||
INPUT,
|
INPUT,
|
||||||
INPUTFORMAT,
|
INPUTFORMAT,
|
||||||
INSENSITIVE,
|
INSENSITIVE,
|
||||||
INSERT,
|
INSERT,
|
||||||
INSERT_METHOD,
|
|
||||||
INSTALL,
|
INSTALL,
|
||||||
INSTANT,
|
|
||||||
INSTEAD,
|
|
||||||
INT,
|
INT,
|
||||||
INT128,
|
INT128,
|
||||||
INT16,
|
INT16,
|
||||||
|
@ -465,14 +385,11 @@ define_keywords!(
|
||||||
INT64,
|
INT64,
|
||||||
INT8,
|
INT8,
|
||||||
INTEGER,
|
INTEGER,
|
||||||
INTEGRATION,
|
|
||||||
INTERPOLATE,
|
INTERPOLATE,
|
||||||
INTERSECT,
|
INTERSECT,
|
||||||
INTERSECTION,
|
INTERSECTION,
|
||||||
INTERVAL,
|
INTERVAL,
|
||||||
INTO,
|
INTO,
|
||||||
INVOKER,
|
|
||||||
IO,
|
|
||||||
IS,
|
IS,
|
||||||
ISODOW,
|
ISODOW,
|
||||||
ISOLATION,
|
ISOLATION,
|
||||||
|
@ -488,7 +405,6 @@ define_keywords!(
|
||||||
JULIAN,
|
JULIAN,
|
||||||
KEY,
|
KEY,
|
||||||
KEYS,
|
KEYS,
|
||||||
KEY_BLOCK_SIZE,
|
|
||||||
KILL,
|
KILL,
|
||||||
LAG,
|
LAG,
|
||||||
LANGUAGE,
|
LANGUAGE,
|
||||||
|
@ -503,11 +419,7 @@ define_keywords!(
|
||||||
LIKE,
|
LIKE,
|
||||||
LIKE_REGEX,
|
LIKE_REGEX,
|
||||||
LIMIT,
|
LIMIT,
|
||||||
LINE,
|
|
||||||
LINES,
|
LINES,
|
||||||
LIST,
|
|
||||||
LISTEN,
|
|
||||||
LISTING,
|
|
||||||
LN,
|
LN,
|
||||||
LOAD,
|
LOAD,
|
||||||
LOCAL,
|
LOCAL,
|
||||||
|
@ -516,43 +428,29 @@ define_keywords!(
|
||||||
LOCATION,
|
LOCATION,
|
||||||
LOCK,
|
LOCK,
|
||||||
LOCKED,
|
LOCKED,
|
||||||
LOG,
|
|
||||||
LOGIN,
|
LOGIN,
|
||||||
LOGS,
|
LOGS,
|
||||||
LONGBLOB,
|
|
||||||
LONGTEXT,
|
|
||||||
LOWCARDINALITY,
|
LOWCARDINALITY,
|
||||||
LOWER,
|
LOWER,
|
||||||
LOW_PRIORITY,
|
LOW_PRIORITY,
|
||||||
LS,
|
|
||||||
LSEG,
|
|
||||||
MACRO,
|
MACRO,
|
||||||
MANAGE,
|
|
||||||
MANAGED,
|
|
||||||
MANAGEDLOCATION,
|
MANAGEDLOCATION,
|
||||||
MAP,
|
MAP,
|
||||||
MASKING,
|
|
||||||
MATCH,
|
MATCH,
|
||||||
MATCHED,
|
MATCHED,
|
||||||
MATCHES,
|
MATCHES,
|
||||||
MATCH_CONDITION,
|
MATCH_CONDITION,
|
||||||
MATCH_RECOGNIZE,
|
MATCH_RECOGNIZE,
|
||||||
MATERIALIZE,
|
|
||||||
MATERIALIZED,
|
MATERIALIZED,
|
||||||
MAX,
|
MAX,
|
||||||
MAXVALUE,
|
MAXVALUE,
|
||||||
MAX_DATA_EXTENSION_TIME_IN_DAYS,
|
MAX_DATA_EXTENSION_TIME_IN_DAYS,
|
||||||
MAX_ROWS,
|
|
||||||
MEASURES,
|
MEASURES,
|
||||||
MEDIUMBLOB,
|
|
||||||
MEDIUMINT,
|
MEDIUMINT,
|
||||||
MEDIUMTEXT,
|
|
||||||
MEMBER,
|
MEMBER,
|
||||||
MERGE,
|
MERGE,
|
||||||
MESSAGE,
|
|
||||||
METADATA,
|
METADATA,
|
||||||
METHOD,
|
METHOD,
|
||||||
METRIC,
|
|
||||||
MICROSECOND,
|
MICROSECOND,
|
||||||
MICROSECONDS,
|
MICROSECONDS,
|
||||||
MILLENIUM,
|
MILLENIUM,
|
||||||
|
@ -560,24 +458,18 @@ define_keywords!(
|
||||||
MILLISECOND,
|
MILLISECOND,
|
||||||
MILLISECONDS,
|
MILLISECONDS,
|
||||||
MIN,
|
MIN,
|
||||||
MINUS,
|
|
||||||
MINUTE,
|
MINUTE,
|
||||||
MINUTES,
|
|
||||||
MINVALUE,
|
MINVALUE,
|
||||||
MIN_ROWS,
|
|
||||||
MOD,
|
MOD,
|
||||||
MODE,
|
MODE,
|
||||||
MODIFIES,
|
MODIFIES,
|
||||||
MODIFY,
|
MODIFY,
|
||||||
MODULE,
|
MODULE,
|
||||||
MONITOR,
|
|
||||||
MONTH,
|
MONTH,
|
||||||
MONTHS,
|
|
||||||
MSCK,
|
MSCK,
|
||||||
MULTISET,
|
MULTISET,
|
||||||
MUTATION,
|
MUTATION,
|
||||||
NAME,
|
NAME,
|
||||||
NAMES,
|
|
||||||
NANOSECOND,
|
NANOSECOND,
|
||||||
NANOSECONDS,
|
NANOSECONDS,
|
||||||
NATIONAL,
|
NATIONAL,
|
||||||
|
@ -585,13 +477,8 @@ define_keywords!(
|
||||||
NCHAR,
|
NCHAR,
|
||||||
NCLOB,
|
NCLOB,
|
||||||
NESTED,
|
NESTED,
|
||||||
NETWORK,
|
|
||||||
NEW,
|
NEW,
|
||||||
NEXT,
|
NEXT,
|
||||||
NFC,
|
|
||||||
NFD,
|
|
||||||
NFKC,
|
|
||||||
NFKD,
|
|
||||||
NO,
|
NO,
|
||||||
NOBYPASSRLS,
|
NOBYPASSRLS,
|
||||||
NOCREATEDB,
|
NOCREATEDB,
|
||||||
|
@ -599,15 +486,12 @@ define_keywords!(
|
||||||
NOINHERIT,
|
NOINHERIT,
|
||||||
NOLOGIN,
|
NOLOGIN,
|
||||||
NONE,
|
NONE,
|
||||||
NOORDER,
|
|
||||||
NOREPLICATION,
|
NOREPLICATION,
|
||||||
NORMALIZE,
|
NORMALIZE,
|
||||||
NORMALIZED,
|
|
||||||
NOSCAN,
|
NOSCAN,
|
||||||
NOSUPERUSER,
|
NOSUPERUSER,
|
||||||
NOT,
|
NOT,
|
||||||
NOTHING,
|
NOTHING,
|
||||||
NOTIFY,
|
|
||||||
NOWAIT,
|
NOWAIT,
|
||||||
NO_WRITE_TO_BINLOG,
|
NO_WRITE_TO_BINLOG,
|
||||||
NTH_VALUE,
|
NTH_VALUE,
|
||||||
|
@ -619,26 +503,19 @@ define_keywords!(
|
||||||
NUMERIC,
|
NUMERIC,
|
||||||
NVARCHAR,
|
NVARCHAR,
|
||||||
OBJECT,
|
OBJECT,
|
||||||
OBJECTS,
|
|
||||||
OCCURRENCES_REGEX,
|
OCCURRENCES_REGEX,
|
||||||
OCTETS,
|
OCTETS,
|
||||||
OCTET_LENGTH,
|
OCTET_LENGTH,
|
||||||
OF,
|
OF,
|
||||||
OFF,
|
|
||||||
OFFSET,
|
OFFSET,
|
||||||
OFFSETS,
|
|
||||||
OLD,
|
OLD,
|
||||||
OMIT,
|
OMIT,
|
||||||
ON,
|
ON,
|
||||||
ONE,
|
ONE,
|
||||||
ONLY,
|
ONLY,
|
||||||
OPEN,
|
OPEN,
|
||||||
OPENJSON,
|
|
||||||
OPERATE,
|
|
||||||
OPERATOR,
|
OPERATOR,
|
||||||
OPTIMIZATION,
|
|
||||||
OPTIMIZE,
|
OPTIMIZE,
|
||||||
OPTIMIZED,
|
|
||||||
OPTIMIZER_COSTS,
|
OPTIMIZER_COSTS,
|
||||||
OPTION,
|
OPTION,
|
||||||
OPTIONS,
|
OPTIONS,
|
||||||
|
@ -646,32 +523,22 @@ define_keywords!(
|
||||||
ORC,
|
ORC,
|
||||||
ORDER,
|
ORDER,
|
||||||
ORDINALITY,
|
ORDINALITY,
|
||||||
ORGANIZATION,
|
|
||||||
OTHER,
|
|
||||||
OUT,
|
OUT,
|
||||||
OUTER,
|
OUTER,
|
||||||
OUTPUT,
|
|
||||||
OUTPUTFORMAT,
|
OUTPUTFORMAT,
|
||||||
OVER,
|
OVER,
|
||||||
OVERFLOW,
|
OVERFLOW,
|
||||||
OVERLAPS,
|
OVERLAPS,
|
||||||
OVERLAY,
|
OVERLAY,
|
||||||
OVERRIDE,
|
|
||||||
OVERWRITE,
|
OVERWRITE,
|
||||||
OWNED,
|
OWNED,
|
||||||
OWNER,
|
OWNER,
|
||||||
OWNERSHIP,
|
|
||||||
PACKAGE,
|
|
||||||
PACKAGES,
|
|
||||||
PACK_KEYS,
|
|
||||||
PARALLEL,
|
PARALLEL,
|
||||||
PARAMETER,
|
PARAMETER,
|
||||||
PARQUET,
|
PARQUET,
|
||||||
PART,
|
|
||||||
PARTITION,
|
PARTITION,
|
||||||
PARTITIONED,
|
PARTITIONED,
|
||||||
PARTITIONS,
|
PARTITIONS,
|
||||||
PASSING,
|
|
||||||
PASSWORD,
|
PASSWORD,
|
||||||
PAST,
|
PAST,
|
||||||
PATH,
|
PATH,
|
||||||
|
@ -682,16 +549,11 @@ define_keywords!(
|
||||||
PERCENTILE_DISC,
|
PERCENTILE_DISC,
|
||||||
PERCENT_RANK,
|
PERCENT_RANK,
|
||||||
PERIOD,
|
PERIOD,
|
||||||
PERMISSIVE,
|
|
||||||
PERSISTENT,
|
PERSISTENT,
|
||||||
PIVOT,
|
PIVOT,
|
||||||
PLACING,
|
PLACING,
|
||||||
PLAN,
|
|
||||||
PLANS,
|
PLANS,
|
||||||
POINT,
|
|
||||||
POLICY,
|
POLICY,
|
||||||
POLYGON,
|
|
||||||
POOL,
|
|
||||||
PORTION,
|
PORTION,
|
||||||
POSITION,
|
POSITION,
|
||||||
POSITION_REGEX,
|
POSITION_REGEX,
|
||||||
|
@ -704,22 +566,15 @@ define_keywords!(
|
||||||
PRESERVE,
|
PRESERVE,
|
||||||
PREWHERE,
|
PREWHERE,
|
||||||
PRIMARY,
|
PRIMARY,
|
||||||
PRINT,
|
|
||||||
PRIOR,
|
PRIOR,
|
||||||
PRIVILEGES,
|
PRIVILEGES,
|
||||||
PROCEDURE,
|
PROCEDURE,
|
||||||
PROFILE,
|
|
||||||
PROGRAM,
|
PROGRAM,
|
||||||
PROJECTION,
|
|
||||||
PUBLIC,
|
|
||||||
PURCHASE,
|
|
||||||
PURGE,
|
PURGE,
|
||||||
QUALIFY,
|
QUALIFY,
|
||||||
QUARTER,
|
QUARTER,
|
||||||
QUERY,
|
QUERY,
|
||||||
QUOTE,
|
QUOTE,
|
||||||
RAISE,
|
|
||||||
RAISERROR,
|
|
||||||
RANGE,
|
RANGE,
|
||||||
RANK,
|
RANK,
|
||||||
RAW,
|
RAW,
|
||||||
|
@ -728,7 +583,6 @@ define_keywords!(
|
||||||
READS,
|
READS,
|
||||||
READ_ONLY,
|
READ_ONLY,
|
||||||
REAL,
|
REAL,
|
||||||
RECLUSTER,
|
|
||||||
RECURSIVE,
|
RECURSIVE,
|
||||||
REF,
|
REF,
|
||||||
REFERENCES,
|
REFERENCES,
|
||||||
|
@ -747,29 +601,21 @@ define_keywords!(
|
||||||
RELATIVE,
|
RELATIVE,
|
||||||
RELAY,
|
RELAY,
|
||||||
RELEASE,
|
RELEASE,
|
||||||
RELEASES,
|
|
||||||
REMOTE,
|
REMOTE,
|
||||||
REMOVE,
|
|
||||||
RENAME,
|
RENAME,
|
||||||
REORG,
|
REORG,
|
||||||
REPAIR,
|
REPAIR,
|
||||||
REPEATABLE,
|
REPEATABLE,
|
||||||
REPLACE,
|
REPLACE,
|
||||||
REPLICA,
|
REPLICA,
|
||||||
REPLICATE,
|
|
||||||
REPLICATION,
|
REPLICATION,
|
||||||
RESET,
|
RESET,
|
||||||
RESOLVE,
|
|
||||||
RESOURCE,
|
|
||||||
RESPECT,
|
RESPECT,
|
||||||
RESTART,
|
RESTART,
|
||||||
RESTRICT,
|
RESTRICT,
|
||||||
RESTRICTED,
|
RESTRICTED,
|
||||||
RESTRICTIONS,
|
|
||||||
RESTRICTIVE,
|
|
||||||
RESULT,
|
RESULT,
|
||||||
RESULTSET,
|
RESULTSET,
|
||||||
RESUME,
|
|
||||||
RETAIN,
|
RETAIN,
|
||||||
RETURN,
|
RETURN,
|
||||||
RETURNING,
|
RETURNING,
|
||||||
|
@ -777,35 +623,26 @@ define_keywords!(
|
||||||
REVOKE,
|
REVOKE,
|
||||||
RIGHT,
|
RIGHT,
|
||||||
RLIKE,
|
RLIKE,
|
||||||
RM,
|
|
||||||
ROLE,
|
ROLE,
|
||||||
ROLES,
|
|
||||||
ROLLBACK,
|
ROLLBACK,
|
||||||
ROLLUP,
|
ROLLUP,
|
||||||
ROOT,
|
ROOT,
|
||||||
ROW,
|
ROW,
|
||||||
ROWID,
|
ROWID,
|
||||||
ROWS,
|
ROWS,
|
||||||
ROW_FORMAT,
|
|
||||||
ROW_NUMBER,
|
ROW_NUMBER,
|
||||||
RULE,
|
RULE,
|
||||||
RUN,
|
RUN,
|
||||||
SAFE,
|
SAFE,
|
||||||
SAFE_CAST,
|
SAFE_CAST,
|
||||||
SAMPLE,
|
|
||||||
SAVEPOINT,
|
SAVEPOINT,
|
||||||
SCHEMA,
|
SCHEMA,
|
||||||
SCHEMAS,
|
|
||||||
SCOPE,
|
SCOPE,
|
||||||
SCROLL,
|
SCROLL,
|
||||||
SEARCH,
|
SEARCH,
|
||||||
SECOND,
|
SECOND,
|
||||||
SECONDARY,
|
|
||||||
SECONDARY_ENGINE_ATTRIBUTE,
|
|
||||||
SECONDS,
|
|
||||||
SECRET,
|
SECRET,
|
||||||
SECURITY,
|
SECURITY,
|
||||||
SEED,
|
|
||||||
SELECT,
|
SELECT,
|
||||||
SEMI,
|
SEMI,
|
||||||
SENSITIVE,
|
SENSITIVE,
|
||||||
|
@ -816,19 +653,13 @@ define_keywords!(
|
||||||
SERDE,
|
SERDE,
|
||||||
SERDEPROPERTIES,
|
SERDEPROPERTIES,
|
||||||
SERIALIZABLE,
|
SERIALIZABLE,
|
||||||
SERVER,
|
|
||||||
SERVICE,
|
|
||||||
SESSION,
|
SESSION,
|
||||||
SESSION_USER,
|
SESSION_USER,
|
||||||
SET,
|
SET,
|
||||||
SETERROR,
|
|
||||||
SETS,
|
SETS,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
SHARE,
|
SHARE,
|
||||||
SHARED,
|
|
||||||
SHARING,
|
|
||||||
SHOW,
|
SHOW,
|
||||||
SIGNED,
|
|
||||||
SIMILAR,
|
SIMILAR,
|
||||||
SKIP,
|
SKIP,
|
||||||
SLOW,
|
SLOW,
|
||||||
|
@ -836,52 +667,38 @@ define_keywords!(
|
||||||
SNAPSHOT,
|
SNAPSHOT,
|
||||||
SOME,
|
SOME,
|
||||||
SORT,
|
SORT,
|
||||||
SORTED,
|
|
||||||
SOURCE,
|
SOURCE,
|
||||||
SPATIAL,
|
SPATIAL,
|
||||||
SPECIFIC,
|
SPECIFIC,
|
||||||
SPECIFICTYPE,
|
SPECIFICTYPE,
|
||||||
SPGIST,
|
|
||||||
SQL,
|
SQL,
|
||||||
SQLEXCEPTION,
|
SQLEXCEPTION,
|
||||||
SQLSTATE,
|
SQLSTATE,
|
||||||
SQLWARNING,
|
SQLWARNING,
|
||||||
SQRT,
|
SQRT,
|
||||||
SRID,
|
|
||||||
STABLE,
|
STABLE,
|
||||||
STAGE,
|
STAGE,
|
||||||
START,
|
START,
|
||||||
STARTS,
|
|
||||||
STATEMENT,
|
|
||||||
STATIC,
|
STATIC,
|
||||||
STATISTICS,
|
STATISTICS,
|
||||||
STATS_AUTO_RECALC,
|
|
||||||
STATS_PERSISTENT,
|
|
||||||
STATS_SAMPLE_PAGES,
|
|
||||||
STATUS,
|
STATUS,
|
||||||
STDDEV_POP,
|
STDDEV_POP,
|
||||||
STDDEV_SAMP,
|
STDDEV_SAMP,
|
||||||
STDIN,
|
STDIN,
|
||||||
STDOUT,
|
STDOUT,
|
||||||
STEP,
|
STEP,
|
||||||
STORAGE,
|
|
||||||
STORAGE_INTEGRATION,
|
STORAGE_INTEGRATION,
|
||||||
STORAGE_SERIALIZATION_POLICY,
|
|
||||||
STORED,
|
STORED,
|
||||||
STRAIGHT_JOIN,
|
|
||||||
STRICT,
|
STRICT,
|
||||||
STRING,
|
STRING,
|
||||||
STRUCT,
|
STRUCT,
|
||||||
SUBMULTISET,
|
SUBMULTISET,
|
||||||
SUBSTR,
|
|
||||||
SUBSTRING,
|
SUBSTRING,
|
||||||
SUBSTRING_REGEX,
|
SUBSTRING_REGEX,
|
||||||
SUCCEEDS,
|
SUCCEEDS,
|
||||||
SUM,
|
SUM,
|
||||||
SUPER,
|
SUPER,
|
||||||
SUPERUSER,
|
SUPERUSER,
|
||||||
SUPPORT,
|
|
||||||
SUSPEND,
|
|
||||||
SWAP,
|
SWAP,
|
||||||
SYMMETRIC,
|
SYMMETRIC,
|
||||||
SYNC,
|
SYNC,
|
||||||
|
@ -891,16 +708,12 @@ define_keywords!(
|
||||||
TABLE,
|
TABLE,
|
||||||
TABLES,
|
TABLES,
|
||||||
TABLESAMPLE,
|
TABLESAMPLE,
|
||||||
TABLESPACE,
|
|
||||||
TAG,
|
TAG,
|
||||||
TARGET,
|
TARGET,
|
||||||
TASK,
|
|
||||||
TBLPROPERTIES,
|
TBLPROPERTIES,
|
||||||
TEMP,
|
TEMP,
|
||||||
TEMPORARY,
|
TEMPORARY,
|
||||||
TEMPTABLE,
|
|
||||||
TERMINATED,
|
TERMINATED,
|
||||||
TERSE,
|
|
||||||
TEXT,
|
TEXT,
|
||||||
TEXTFILE,
|
TEXTFILE,
|
||||||
THEN,
|
THEN,
|
||||||
|
@ -908,20 +721,16 @@ define_keywords!(
|
||||||
TIME,
|
TIME,
|
||||||
TIMESTAMP,
|
TIMESTAMP,
|
||||||
TIMESTAMPTZ,
|
TIMESTAMPTZ,
|
||||||
TIMESTAMP_NTZ,
|
|
||||||
TIMETZ,
|
TIMETZ,
|
||||||
TIMEZONE,
|
TIMEZONE,
|
||||||
TIMEZONE_ABBR,
|
TIMEZONE_ABBR,
|
||||||
TIMEZONE_HOUR,
|
TIMEZONE_HOUR,
|
||||||
TIMEZONE_MINUTE,
|
TIMEZONE_MINUTE,
|
||||||
TIMEZONE_REGION,
|
TIMEZONE_REGION,
|
||||||
TINYBLOB,
|
|
||||||
TINYINT,
|
TINYINT,
|
||||||
TINYTEXT,
|
|
||||||
TO,
|
TO,
|
||||||
TOP,
|
TOP,
|
||||||
TOTALS,
|
TOTALS,
|
||||||
TRACE,
|
|
||||||
TRAILING,
|
TRAILING,
|
||||||
TRANSACTION,
|
TRANSACTION,
|
||||||
TRANSIENT,
|
TRANSIENT,
|
||||||
|
@ -934,16 +743,10 @@ define_keywords!(
|
||||||
TRIM_ARRAY,
|
TRIM_ARRAY,
|
||||||
TRUE,
|
TRUE,
|
||||||
TRUNCATE,
|
TRUNCATE,
|
||||||
TRY,
|
|
||||||
TRY_CAST,
|
TRY_CAST,
|
||||||
TRY_CONVERT,
|
|
||||||
TSQUERY,
|
|
||||||
TSVECTOR,
|
|
||||||
TUPLE,
|
TUPLE,
|
||||||
TYPE,
|
TYPE,
|
||||||
UBIGINT,
|
|
||||||
UESCAPE,
|
UESCAPE,
|
||||||
UHUGEINT,
|
|
||||||
UINT128,
|
UINT128,
|
||||||
UINT16,
|
UINT16,
|
||||||
UINT256,
|
UINT256,
|
||||||
|
@ -953,12 +756,9 @@ define_keywords!(
|
||||||
UNBOUNDED,
|
UNBOUNDED,
|
||||||
UNCACHE,
|
UNCACHE,
|
||||||
UNCOMMITTED,
|
UNCOMMITTED,
|
||||||
UNDEFINED,
|
|
||||||
UNFREEZE,
|
|
||||||
UNION,
|
UNION,
|
||||||
UNIQUE,
|
UNIQUE,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
UNLISTEN,
|
|
||||||
UNLOAD,
|
UNLOAD,
|
||||||
UNLOCK,
|
UNLOCK,
|
||||||
UNLOGGED,
|
UNLOGGED,
|
||||||
|
@ -966,7 +766,6 @@ define_keywords!(
|
||||||
UNNEST,
|
UNNEST,
|
||||||
UNPIVOT,
|
UNPIVOT,
|
||||||
UNSAFE,
|
UNSAFE,
|
||||||
UNSET,
|
|
||||||
UNSIGNED,
|
UNSIGNED,
|
||||||
UNTIL,
|
UNTIL,
|
||||||
UPDATE,
|
UPDATE,
|
||||||
|
@ -977,18 +776,14 @@ define_keywords!(
|
||||||
USER,
|
USER,
|
||||||
USER_RESOURCES,
|
USER_RESOURCES,
|
||||||
USING,
|
USING,
|
||||||
USMALLINT,
|
|
||||||
UTINYINT,
|
|
||||||
UUID,
|
UUID,
|
||||||
VACUUM,
|
VACUUM,
|
||||||
VALID,
|
VALID,
|
||||||
VALIDATE,
|
|
||||||
VALIDATION_MODE,
|
VALIDATION_MODE,
|
||||||
VALUE,
|
VALUE,
|
||||||
VALUES,
|
VALUES,
|
||||||
VALUE_OF,
|
VALUE_OF,
|
||||||
VARBINARY,
|
VARBINARY,
|
||||||
VARBIT,
|
|
||||||
VARCHAR,
|
VARCHAR,
|
||||||
VARIABLES,
|
VARIABLES,
|
||||||
VARYING,
|
VARYING,
|
||||||
|
@ -997,20 +792,13 @@ define_keywords!(
|
||||||
VERBOSE,
|
VERBOSE,
|
||||||
VERSION,
|
VERSION,
|
||||||
VERSIONING,
|
VERSIONING,
|
||||||
VERSIONS,
|
|
||||||
VIEW,
|
VIEW,
|
||||||
VIEWS,
|
|
||||||
VIRTUAL,
|
VIRTUAL,
|
||||||
VOLATILE,
|
VOLATILE,
|
||||||
VOLUME,
|
|
||||||
WAREHOUSE,
|
|
||||||
WAREHOUSES,
|
|
||||||
WEEK,
|
WEEK,
|
||||||
WEEKS,
|
|
||||||
WHEN,
|
WHEN,
|
||||||
WHENEVER,
|
WHENEVER,
|
||||||
WHERE,
|
WHERE,
|
||||||
WHILE,
|
|
||||||
WIDTH_BUCKET,
|
WIDTH_BUCKET,
|
||||||
WINDOW,
|
WINDOW,
|
||||||
WITH,
|
WITH,
|
||||||
|
@ -1018,14 +806,10 @@ define_keywords!(
|
||||||
WITHOUT,
|
WITHOUT,
|
||||||
WITHOUT_ARRAY_WRAPPER,
|
WITHOUT_ARRAY_WRAPPER,
|
||||||
WORK,
|
WORK,
|
||||||
WRAPPER,
|
|
||||||
WRITE,
|
WRITE,
|
||||||
XML,
|
XML,
|
||||||
XMLNAMESPACES,
|
|
||||||
XMLTABLE,
|
|
||||||
XOR,
|
XOR,
|
||||||
YEAR,
|
YEAR,
|
||||||
YEARS,
|
|
||||||
ZONE,
|
ZONE,
|
||||||
ZORDER
|
ZORDER
|
||||||
);
|
);
|
||||||
|
@ -1054,7 +838,6 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
|
||||||
Keyword::UNION,
|
Keyword::UNION,
|
||||||
Keyword::EXCEPT,
|
Keyword::EXCEPT,
|
||||||
Keyword::INTERSECT,
|
Keyword::INTERSECT,
|
||||||
Keyword::MINUS,
|
|
||||||
// Reserved only as a table alias in the `FROM`/`JOIN` clauses:
|
// Reserved only as a table alias in the `FROM`/`JOIN` clauses:
|
||||||
Keyword::ON,
|
Keyword::ON,
|
||||||
Keyword::JOIN,
|
Keyword::JOIN,
|
||||||
|
@ -1067,12 +850,6 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
|
||||||
Keyword::USING,
|
Keyword::USING,
|
||||||
Keyword::CLUSTER,
|
Keyword::CLUSTER,
|
||||||
Keyword::DISTRIBUTE,
|
Keyword::DISTRIBUTE,
|
||||||
Keyword::GLOBAL,
|
|
||||||
Keyword::ANTI,
|
|
||||||
Keyword::SEMI,
|
|
||||||
Keyword::RETURNING,
|
|
||||||
Keyword::ASOF,
|
|
||||||
Keyword::MATCH_CONDITION,
|
|
||||||
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
|
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
|
||||||
Keyword::OUTER,
|
Keyword::OUTER,
|
||||||
Keyword::SET,
|
Keyword::SET,
|
||||||
|
@ -1084,18 +861,15 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
|
||||||
Keyword::PARTITION,
|
Keyword::PARTITION,
|
||||||
// for Clickhouse PREWHERE
|
// for Clickhouse PREWHERE
|
||||||
Keyword::PREWHERE,
|
Keyword::PREWHERE,
|
||||||
|
// for ClickHouse SELECT * FROM t SETTINGS ...
|
||||||
Keyword::SETTINGS,
|
Keyword::SETTINGS,
|
||||||
|
// for ClickHouse SELECT * FROM t FORMAT...
|
||||||
Keyword::FORMAT,
|
Keyword::FORMAT,
|
||||||
// for Snowflake START WITH .. CONNECT BY
|
// for Snowflake START WITH .. CONNECT BY
|
||||||
Keyword::START,
|
Keyword::START,
|
||||||
Keyword::CONNECT,
|
Keyword::CONNECT,
|
||||||
// Reserved for snowflake MATCH_RECOGNIZE
|
// Reserved for snowflake MATCH_RECOGNIZE
|
||||||
Keyword::MATCH_RECOGNIZE,
|
Keyword::MATCH_RECOGNIZE,
|
||||||
// Reserved for Snowflake table sample
|
|
||||||
Keyword::SAMPLE,
|
|
||||||
Keyword::TABLESAMPLE,
|
|
||||||
Keyword::FROM,
|
|
||||||
Keyword::OPEN,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Can't be used as a column alias, so that `SELECT <expr> alias`
|
/// Can't be used as a column alias, so that `SELECT <expr> alias`
|
||||||
|
@ -1119,9 +893,7 @@ pub const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
|
||||||
Keyword::FETCH,
|
Keyword::FETCH,
|
||||||
Keyword::UNION,
|
Keyword::UNION,
|
||||||
Keyword::EXCEPT,
|
Keyword::EXCEPT,
|
||||||
Keyword::EXCLUDE,
|
|
||||||
Keyword::INTERSECT,
|
Keyword::INTERSECT,
|
||||||
Keyword::MINUS,
|
|
||||||
Keyword::CLUSTER,
|
Keyword::CLUSTER,
|
||||||
Keyword::DISTRIBUTE,
|
Keyword::DISTRIBUTE,
|
||||||
Keyword::RETURNING,
|
Keyword::RETURNING,
|
||||||
|
@ -1130,23 +902,3 @@ pub const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
|
||||||
Keyword::INTO,
|
Keyword::INTO,
|
||||||
Keyword::END,
|
Keyword::END,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Global list of reserved keywords allowed after FROM.
|
|
||||||
// Parser should call Dialect::get_reserved_keyword_after_from
|
|
||||||
// to allow for each dialect to customize the list.
|
|
||||||
pub const RESERVED_FOR_TABLE_FACTOR: &[Keyword] = &[
|
|
||||||
Keyword::INTO,
|
|
||||||
Keyword::LIMIT,
|
|
||||||
Keyword::HAVING,
|
|
||||||
Keyword::WHERE,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Global list of reserved keywords that cannot be parsed as identifiers
|
|
||||||
/// without special handling like quoting. Parser should call `Dialect::is_reserved_for_identifier`
|
|
||||||
/// to allow for each dialect to customize the list.
|
|
||||||
pub const RESERVED_FOR_IDENTIFIER: &[Keyword] = &[
|
|
||||||
Keyword::EXISTS,
|
|
||||||
Keyword::INTERVAL,
|
|
||||||
Keyword::STRUCT,
|
|
||||||
Keyword::TRIM,
|
|
||||||
];
|
|
||||||
|
|
106
src/lib.rs
106
src/lib.rs
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
//! # SQL Parser for Rust
|
//! # SQL Parser for Rust
|
||||||
//!
|
//!
|
||||||
|
@ -25,9 +20,6 @@
|
||||||
//! 1. [`Parser::parse_sql`] and [`Parser::new`] for the Parsing API
|
//! 1. [`Parser::parse_sql`] and [`Parser::new`] for the Parsing API
|
||||||
//! 2. [`ast`] for the AST structure
|
//! 2. [`ast`] for the AST structure
|
||||||
//! 3. [`Dialect`] for supported SQL dialects
|
//! 3. [`Dialect`] for supported SQL dialects
|
||||||
//! 4. [`Spanned`] for source text locations (see "Source Spans" below for details)
|
|
||||||
//!
|
|
||||||
//! [`Spanned`]: ast::Spanned
|
|
||||||
//!
|
//!
|
||||||
//! # Example parsing SQL text
|
//! # Example parsing SQL text
|
||||||
//!
|
//!
|
||||||
|
@ -65,94 +57,15 @@
|
||||||
//! assert_eq!(ast[0].to_string(), sql);
|
//! assert_eq!(ast[0].to_string(), sql);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! # Pretty Printing
|
|
||||||
//!
|
|
||||||
//! SQL statements can be pretty-printed with proper indentation and line breaks using the alternate flag (`{:#}`):
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! # use sqlparser::dialect::GenericDialect;
|
|
||||||
//! # use sqlparser::parser::Parser;
|
|
||||||
//! let sql = "SELECT a, b FROM table_1";
|
|
||||||
//! let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
|
|
||||||
//!
|
|
||||||
//! // Pretty print with indentation and line breaks
|
|
||||||
//! let pretty_sql = format!("{:#}", ast[0]);
|
|
||||||
//! assert_eq!(pretty_sql, r#"
|
|
||||||
//! SELECT
|
|
||||||
//! a,
|
|
||||||
//! b
|
|
||||||
//! FROM
|
|
||||||
//! table_1
|
|
||||||
//! "#.trim());
|
|
||||||
//! ```
|
|
||||||
//! [sqlparser crates.io page]: https://crates.io/crates/sqlparser
|
//! [sqlparser crates.io page]: https://crates.io/crates/sqlparser
|
||||||
//! [`Parser::parse_sql`]: crate::parser::Parser::parse_sql
|
//! [`Parser::parse_sql`]: crate::parser::Parser::parse_sql
|
||||||
//! [`Parser::new`]: crate::parser::Parser::new
|
//! [`Parser::new`]: crate::parser::Parser::new
|
||||||
//! [`AST`]: crate::ast
|
//! [`AST`]: crate::ast
|
||||||
//! [`ast`]: crate::ast
|
//! [`ast`]: crate::ast
|
||||||
//! [`Dialect`]: crate::dialect::Dialect
|
//! [`Dialect`]: crate::dialect::Dialect
|
||||||
//!
|
|
||||||
//! # Source Spans
|
|
||||||
//!
|
|
||||||
//! Starting with version `0.53.0` sqlparser introduced source spans to the
|
|
||||||
//! AST. This feature provides source information for syntax errors, enabling
|
|
||||||
//! better error messages. See [issue #1548] for more information and the
|
|
||||||
//! [`Spanned`] trait to access the spans.
|
|
||||||
//!
|
|
||||||
//! [issue #1548]: https://github.com/apache/datafusion-sqlparser-rs/issues/1548
|
|
||||||
//! [`Spanned`]: ast::Spanned
|
|
||||||
//!
|
|
||||||
//! ## Migration Guide
|
|
||||||
//!
|
|
||||||
//! For the next few releases, we will be incrementally adding source spans to the
|
|
||||||
//! AST nodes, trying to minimize the impact on existing users. Some breaking
|
|
||||||
//! changes are inevitable, and the following is a summary of the changes:
|
|
||||||
//!
|
|
||||||
//! #### New fields for spans (must be added to any existing pattern matches)
|
|
||||||
//!
|
|
||||||
//! The primary change is that new fields will be added to AST nodes to store the source `Span` or `TokenWithLocation`.
|
|
||||||
//!
|
|
||||||
//! This will require
|
|
||||||
//! 1. Adding new fields to existing pattern matches.
|
|
||||||
//! 2. Filling in the proper span information when constructing AST nodes.
|
|
||||||
//!
|
|
||||||
//! For example, since `Ident` now stores a `Span`, to construct an `Ident` you
|
|
||||||
//! must provide now provide one:
|
|
||||||
//!
|
|
||||||
//! Previously:
|
|
||||||
//! ```text
|
|
||||||
//! # use sqlparser::ast::Ident;
|
|
||||||
//! Ident {
|
|
||||||
//! value: "name".into(),
|
|
||||||
//! quote_style: None,
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//! Now
|
|
||||||
//! ```rust
|
|
||||||
//! # use sqlparser::ast::Ident;
|
|
||||||
//! # use sqlparser::tokenizer::Span;
|
|
||||||
//! Ident {
|
|
||||||
//! value: "name".into(),
|
|
||||||
//! quote_style: None,
|
|
||||||
//! span: Span::empty(),
|
|
||||||
//! };
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Similarly, when pattern matching on `Ident`, you must now account for the
|
|
||||||
//! `span` field.
|
|
||||||
//!
|
|
||||||
//! #### Misc.
|
|
||||||
//! - [`TokenWithLocation`] stores a full `Span`, rather than just a source location.
|
|
||||||
//! Users relying on `token.location` should use `token.location.start` instead.
|
|
||||||
//!
|
|
||||||
//![`TokenWithLocation`]: tokenizer::TokenWithLocation
|
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![allow(clippy::upper_case_acronyms)]
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
// Permit large enum variants to keep a unified, expressive AST.
|
|
||||||
// Splitting complex nodes (expressions, statements, types) into separate types
|
|
||||||
// would bloat the API and hide intent. Extra memory is a worthwhile tradeoff.
|
|
||||||
#![allow(clippy::large_enum_variant)]
|
|
||||||
|
|
||||||
// Allow proc-macros to find this crate
|
// Allow proc-macros to find this crate
|
||||||
extern crate self as sqlparser;
|
extern crate self as sqlparser;
|
||||||
|
@ -167,7 +80,6 @@ extern crate pretty_assertions;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod dialect;
|
pub mod dialect;
|
||||||
mod display_utils;
|
|
||||||
pub mod keywords;
|
pub mod keywords;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod tokenizer;
|
pub mod tokenizer;
|
||||||
|
|
|
@ -17,16 +17,13 @@ use alloc::vec;
|
||||||
|
|
||||||
use super::{Parser, ParserError};
|
use super::{Parser, ParserError};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{AlterRoleOperation, Expr, Password, ResetConfig, RoleOption, SetConfigValue, Statement},
|
||||||
AlterConnectorOwner, AlterPolicyOperation, AlterRoleOperation, Expr, Password, ResetConfig,
|
|
||||||
RoleOption, SetConfigValue, Statement,
|
|
||||||
},
|
|
||||||
dialect::{MsSqlDialect, PostgreSqlDialect},
|
dialect::{MsSqlDialect, PostgreSqlDialect},
|
||||||
keywords::Keyword,
|
keywords::Keyword,
|
||||||
tokenizer::Token,
|
tokenizer::Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Parser<'_> {
|
impl<'a> Parser<'a> {
|
||||||
pub fn parse_alter_role(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||||
if dialect_of!(self is PostgreSqlDialect) {
|
if dialect_of!(self is PostgreSqlDialect) {
|
||||||
return self.parse_pg_alter_role();
|
return self.parse_pg_alter_role();
|
||||||
|
@ -39,119 +36,18 @@ impl Parser<'_> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse ALTER POLICY statement
|
|
||||||
/// ```sql
|
|
||||||
/// ALTER POLICY policy_name ON table_name [ RENAME TO new_name ]
|
|
||||||
/// or
|
|
||||||
/// ALTER POLICY policy_name ON table_name
|
|
||||||
/// [ TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ]
|
|
||||||
/// [ USING ( using_expression ) ]
|
|
||||||
/// [ WITH CHECK ( check_expression ) ]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterpolicy.html)
|
|
||||||
pub fn parse_alter_policy(&mut self) -> Result<Statement, ParserError> {
|
|
||||||
let name = self.parse_identifier()?;
|
|
||||||
self.expect_keyword_is(Keyword::ON)?;
|
|
||||||
let table_name = self.parse_object_name(false)?;
|
|
||||||
|
|
||||||
if self.parse_keyword(Keyword::RENAME) {
|
|
||||||
self.expect_keyword_is(Keyword::TO)?;
|
|
||||||
let new_name = self.parse_identifier()?;
|
|
||||||
Ok(Statement::AlterPolicy {
|
|
||||||
name,
|
|
||||||
table_name,
|
|
||||||
operation: AlterPolicyOperation::Rename { new_name },
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let to = if self.parse_keyword(Keyword::TO) {
|
|
||||||
Some(self.parse_comma_separated(|p| p.parse_owner())?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let using = if self.parse_keyword(Keyword::USING) {
|
|
||||||
self.expect_token(&Token::LParen)?;
|
|
||||||
let expr = self.parse_expr()?;
|
|
||||||
self.expect_token(&Token::RParen)?;
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let with_check = if self.parse_keywords(&[Keyword::WITH, Keyword::CHECK]) {
|
|
||||||
self.expect_token(&Token::LParen)?;
|
|
||||||
let expr = self.parse_expr()?;
|
|
||||||
self.expect_token(&Token::RParen)?;
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(Statement::AlterPolicy {
|
|
||||||
name,
|
|
||||||
table_name,
|
|
||||||
operation: AlterPolicyOperation::Apply {
|
|
||||||
to,
|
|
||||||
using,
|
|
||||||
with_check,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse an `ALTER CONNECTOR` statement
|
|
||||||
/// ```sql
|
|
||||||
/// ALTER CONNECTOR connector_name SET DCPROPERTIES(property_name=property_value, ...);
|
|
||||||
///
|
|
||||||
/// ALTER CONNECTOR connector_name SET URL new_url;
|
|
||||||
///
|
|
||||||
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
|
|
||||||
/// ```
|
|
||||||
pub fn parse_alter_connector(&mut self) -> Result<Statement, ParserError> {
|
|
||||||
let name = self.parse_identifier()?;
|
|
||||||
self.expect_keyword_is(Keyword::SET)?;
|
|
||||||
|
|
||||||
let properties = match self.parse_options_with_keywords(&[Keyword::DCPROPERTIES])? {
|
|
||||||
properties if !properties.is_empty() => Some(properties),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let url = if self.parse_keyword(Keyword::URL) {
|
|
||||||
Some(self.parse_literal_string()?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let owner = if self.parse_keywords(&[Keyword::OWNER, Keyword::USER]) {
|
|
||||||
let owner = self.parse_identifier()?;
|
|
||||||
Some(AlterConnectorOwner::User(owner))
|
|
||||||
} else if self.parse_keywords(&[Keyword::OWNER, Keyword::ROLE]) {
|
|
||||||
let owner = self.parse_identifier()?;
|
|
||||||
Some(AlterConnectorOwner::Role(owner))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Statement::AlterConnector {
|
|
||||||
name,
|
|
||||||
properties,
|
|
||||||
url,
|
|
||||||
owner,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
|
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||||
let role_name = self.parse_identifier()?;
|
let role_name = self.parse_identifier(false)?;
|
||||||
|
|
||||||
let operation = if self.parse_keywords(&[Keyword::ADD, Keyword::MEMBER]) {
|
let operation = if self.parse_keywords(&[Keyword::ADD, Keyword::MEMBER]) {
|
||||||
let member_name = self.parse_identifier()?;
|
let member_name = self.parse_identifier(false)?;
|
||||||
AlterRoleOperation::AddMember { member_name }
|
AlterRoleOperation::AddMember { member_name }
|
||||||
} else if self.parse_keywords(&[Keyword::DROP, Keyword::MEMBER]) {
|
} else if self.parse_keywords(&[Keyword::DROP, Keyword::MEMBER]) {
|
||||||
let member_name = self.parse_identifier()?;
|
let member_name = self.parse_identifier(false)?;
|
||||||
AlterRoleOperation::DropMember { member_name }
|
AlterRoleOperation::DropMember { member_name }
|
||||||
} else if self.parse_keywords(&[Keyword::WITH, Keyword::NAME]) {
|
} else if self.parse_keywords(&[Keyword::WITH, Keyword::NAME]) {
|
||||||
if self.consume_token(&Token::Eq) {
|
if self.consume_token(&Token::Eq) {
|
||||||
let role_name = self.parse_identifier()?;
|
let role_name = self.parse_identifier(false)?;
|
||||||
AlterRoleOperation::RenameRole { role_name }
|
AlterRoleOperation::RenameRole { role_name }
|
||||||
} else {
|
} else {
|
||||||
return self.expected("= after WITH NAME ", self.peek_token());
|
return self.expected("= after WITH NAME ", self.peek_token());
|
||||||
|
@ -167,7 +63,7 @@ impl Parser<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pg_alter_role(&mut self) -> Result<Statement, ParserError> {
|
fn parse_pg_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||||
let role_name = self.parse_identifier()?;
|
let role_name = self.parse_identifier(false)?;
|
||||||
|
|
||||||
// [ IN DATABASE _`database_name`_ ]
|
// [ IN DATABASE _`database_name`_ ]
|
||||||
let in_database = if self.parse_keywords(&[Keyword::IN, Keyword::DATABASE]) {
|
let in_database = if self.parse_keywords(&[Keyword::IN, Keyword::DATABASE]) {
|
||||||
|
@ -178,7 +74,7 @@ impl Parser<'_> {
|
||||||
|
|
||||||
let operation = if self.parse_keyword(Keyword::RENAME) {
|
let operation = if self.parse_keyword(Keyword::RENAME) {
|
||||||
if self.parse_keyword(Keyword::TO) {
|
if self.parse_keyword(Keyword::TO) {
|
||||||
let role_name = self.parse_identifier()?;
|
let role_name = self.parse_identifier(false)?;
|
||||||
AlterRoleOperation::RenameRole { role_name }
|
AlterRoleOperation::RenameRole { role_name }
|
||||||
} else {
|
} else {
|
||||||
return self.expected("TO after RENAME", self.peek_token());
|
return self.expected("TO after RENAME", self.peek_token());
|
||||||
|
@ -233,7 +129,7 @@ impl Parser<'_> {
|
||||||
let _ = self.parse_keyword(Keyword::WITH);
|
let _ = self.parse_keyword(Keyword::WITH);
|
||||||
// option
|
// option
|
||||||
let mut options = vec![];
|
let mut options = vec![];
|
||||||
while let Some(opt) = self.maybe_parse(|parser| parser.parse_pg_role_option())? {
|
while let Some(opt) = self.maybe_parse(|parser| parser.parse_pg_role_option()) {
|
||||||
options.push(opt);
|
options.push(opt);
|
||||||
}
|
}
|
||||||
// check option
|
// check option
|
||||||
|
@ -273,7 +169,7 @@ impl Parser<'_> {
|
||||||
Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true),
|
Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true),
|
||||||
Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false),
|
Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false),
|
||||||
Some(Keyword::CONNECTION) => {
|
Some(Keyword::CONNECTION) => {
|
||||||
self.expect_keyword_is(Keyword::LIMIT)?;
|
self.expect_keyword(Keyword::LIMIT)?;
|
||||||
RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?))
|
RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?))
|
||||||
}
|
}
|
||||||
Some(Keyword::CREATEDB) => RoleOption::CreateDB(true),
|
Some(Keyword::CREATEDB) => RoleOption::CreateDB(true),
|
||||||
|
@ -297,7 +193,7 @@ impl Parser<'_> {
|
||||||
Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true),
|
Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true),
|
||||||
Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false),
|
Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false),
|
||||||
Some(Keyword::VALID) => {
|
Some(Keyword::VALID) => {
|
||||||
self.expect_keyword_is(Keyword::UNTIL)?;
|
self.expect_keyword(Keyword::UNTIL)?;
|
||||||
RoleOption::ValidUntil(Expr::Value(self.parse_value()?))
|
RoleOption::ValidUntil(Expr::Value(self.parse_value()?))
|
||||||
}
|
}
|
||||||
_ => self.expected("option", self.peek_token())?,
|
_ => self.expected("option", self.peek_token())?,
|
||||||
|
|
9569
src/parser/mod.rs
9569
src/parser/mod.rs
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,14 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// you may not use this file except in compliance with the License.
|
||||||
// distributed with this work for additional information
|
// You may obtain a copy of the License at
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// software distributed under the License is distributed on an
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// KIND, either express or implied. See the License for the
|
// See the License for the specific language governing permissions and
|
||||||
// specific language governing permissions and limitations
|
// limitations under the License.
|
||||||
// under the License.
|
|
||||||
|
|
||||||
/// This module contains internal utilities used for testing the library.
|
/// This module contains internal utilities used for testing the library.
|
||||||
/// While technically public, the library's users are not supposed to rely
|
/// While technically public, the library's users are not supposed to rely
|
||||||
|
@ -33,7 +28,7 @@ use core::fmt::Debug;
|
||||||
|
|
||||||
use crate::dialect::*;
|
use crate::dialect::*;
|
||||||
use crate::parser::{Parser, ParserError};
|
use crate::parser::{Parser, ParserError};
|
||||||
use crate::tokenizer::{Token, Tokenizer};
|
use crate::tokenizer::Tokenizer;
|
||||||
use crate::{ast::*, parser::ParserOptions};
|
use crate::{ast::*, parser::ParserOptions};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -44,47 +39,16 @@ use pretty_assertions::assert_eq;
|
||||||
pub struct TestedDialects {
|
pub struct TestedDialects {
|
||||||
pub dialects: Vec<Box<dyn Dialect>>,
|
pub dialects: Vec<Box<dyn Dialect>>,
|
||||||
pub options: Option<ParserOptions>,
|
pub options: Option<ParserOptions>,
|
||||||
pub recursion_limit: Option<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestedDialects {
|
impl TestedDialects {
|
||||||
/// Create a TestedDialects with default options and the given dialects.
|
|
||||||
pub fn new(dialects: Vec<Box<dyn Dialect>>) -> Self {
|
|
||||||
Self {
|
|
||||||
dialects,
|
|
||||||
options: None,
|
|
||||||
recursion_limit: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_options(dialects: Vec<Box<dyn Dialect>>, options: ParserOptions) -> Self {
|
|
||||||
Self {
|
|
||||||
dialects,
|
|
||||||
options: Some(options),
|
|
||||||
recursion_limit: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_recursion_limit(mut self, recursion_limit: usize) -> Self {
|
|
||||||
self.recursion_limit = Some(recursion_limit);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_parser<'a>(&self, dialect: &'a dyn Dialect) -> Parser<'a> {
|
fn new_parser<'a>(&self, dialect: &'a dyn Dialect) -> Parser<'a> {
|
||||||
let parser = Parser::new(dialect);
|
let parser = Parser::new(dialect);
|
||||||
let parser = if let Some(options) = &self.options {
|
if let Some(options) = &self.options {
|
||||||
parser.with_options(options.clone())
|
parser.with_options(options.clone())
|
||||||
} else {
|
} else {
|
||||||
parser
|
parser
|
||||||
};
|
}
|
||||||
|
|
||||||
let parser = if let Some(recursion_limit) = &self.recursion_limit {
|
|
||||||
parser.with_recursion_limit(*recursion_limit)
|
|
||||||
} else {
|
|
||||||
parser
|
|
||||||
};
|
|
||||||
|
|
||||||
parser
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the given function for all of `self.dialects`, assert that they
|
/// Run the given function for all of `self.dialects`, assert that they
|
||||||
|
@ -147,45 +111,25 @@ impl TestedDialects {
|
||||||
/// that:
|
/// that:
|
||||||
///
|
///
|
||||||
/// 1. parsing `sql` results in the same [`Statement`] as parsing
|
/// 1. parsing `sql` results in the same [`Statement`] as parsing
|
||||||
/// `canonical`.
|
/// `canonical`.
|
||||||
///
|
///
|
||||||
/// 2. re-serializing the result of parsing `sql` produces the same
|
/// 2. re-serializing the result of parsing `sql` produces the same
|
||||||
/// `canonical` sql string
|
/// `canonical` sql string
|
||||||
///
|
|
||||||
/// For multiple statements, use [`statements_parse_to`].
|
|
||||||
pub fn one_statement_parses_to(&self, sql: &str, canonical: &str) -> Statement {
|
pub fn one_statement_parses_to(&self, sql: &str, canonical: &str) -> Statement {
|
||||||
let mut statements = self.parse_sql_statements(sql).expect(sql);
|
let mut statements = self.parse_sql_statements(sql).expect(sql);
|
||||||
assert_eq!(statements.len(), 1);
|
assert_eq!(statements.len(), 1);
|
||||||
|
|
||||||
if !canonical.is_empty() && sql != canonical {
|
if !canonical.is_empty() && sql != canonical {
|
||||||
assert_eq!(self.parse_sql_statements(canonical).unwrap(), statements);
|
assert_eq!(self.parse_sql_statements(canonical).unwrap(), statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
let only_statement = statements.pop().unwrap();
|
let only_statement = statements.pop().unwrap();
|
||||||
|
|
||||||
if !canonical.is_empty() {
|
if !canonical.is_empty() {
|
||||||
assert_eq!(canonical, only_statement.to_string())
|
assert_eq!(canonical, only_statement.to_string())
|
||||||
}
|
}
|
||||||
only_statement
|
only_statement
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as [`one_statement_parses_to`] but it works for a multiple statements
|
|
||||||
pub fn statements_parse_to(&self, sql: &str, canonical: &str) -> Vec<Statement> {
|
|
||||||
let statements = self.parse_sql_statements(sql).expect(sql);
|
|
||||||
if !canonical.is_empty() && sql != canonical {
|
|
||||||
assert_eq!(self.parse_sql_statements(canonical).unwrap(), statements);
|
|
||||||
} else {
|
|
||||||
assert_eq!(
|
|
||||||
sql,
|
|
||||||
statements
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("; ")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
statements
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensures that `sql` parses as an [`Expr`], and that
|
/// Ensures that `sql` parses as an [`Expr`], and that
|
||||||
/// re-serializing the parse result produces canonical
|
/// re-serializing the parse result produces canonical
|
||||||
pub fn expr_parses_to(&self, sql: &str, canonical: &str) -> Expr {
|
pub fn expr_parses_to(&self, sql: &str, canonical: &str) -> Expr {
|
||||||
|
@ -236,10 +180,10 @@ impl TestedDialects {
|
||||||
/// Ensures that `sql` parses as a single [`Select`], and that additionally:
|
/// Ensures that `sql` parses as a single [`Select`], and that additionally:
|
||||||
///
|
///
|
||||||
/// 1. parsing `sql` results in the same [`Statement`] as parsing
|
/// 1. parsing `sql` results in the same [`Statement`] as parsing
|
||||||
/// `canonical`.
|
/// `canonical`.
|
||||||
///
|
///
|
||||||
/// 2. re-serializing the result of parsing `sql` produces the same
|
/// 2. re-serializing the result of parsing `sql` produces the same
|
||||||
/// `canonical` sql string
|
/// `canonical` sql string
|
||||||
pub fn verified_only_select_with_canonical(&self, query: &str, canonical: &str) -> Select {
|
pub fn verified_only_select_with_canonical(&self, query: &str, canonical: &str) -> Select {
|
||||||
let q = match self.one_statement_parses_to(query, canonical) {
|
let q = match self.one_statement_parses_to(query, canonical) {
|
||||||
Statement::Query(query) => *query,
|
Statement::Query(query) => *query,
|
||||||
|
@ -257,46 +201,28 @@ impl TestedDialects {
|
||||||
pub fn verified_expr(&self, sql: &str) -> Expr {
|
pub fn verified_expr(&self, sql: &str) -> Expr {
|
||||||
self.expr_parses_to(sql, sql)
|
self.expr_parses_to(sql, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that the tokenizer returns the expected tokens for the given SQL.
|
|
||||||
pub fn tokenizes_to(&self, sql: &str, expected: Vec<Token>) {
|
|
||||||
if self.dialects.is_empty() {
|
|
||||||
panic!("No dialects to test");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dialects.iter().for_each(|dialect| {
|
|
||||||
let mut tokenizer = Tokenizer::new(&**dialect, sql);
|
|
||||||
if let Some(options) = &self.options {
|
|
||||||
tokenizer = tokenizer.with_unescape(options.unescape);
|
|
||||||
}
|
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
|
||||||
assert_eq!(expected, tokens, "Tokenized differently for {dialect:?}");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all available dialects.
|
/// Returns all available dialects.
|
||||||
pub fn all_dialects() -> TestedDialects {
|
pub fn all_dialects() -> TestedDialects {
|
||||||
TestedDialects::new(vec![
|
let all_dialects = vec![
|
||||||
Box::new(GenericDialect {}),
|
Box::new(GenericDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(PostgreSqlDialect {}),
|
Box::new(PostgreSqlDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(MsSqlDialect {}),
|
Box::new(MsSqlDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(AnsiDialect {}),
|
Box::new(AnsiDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(SnowflakeDialect {}),
|
Box::new(SnowflakeDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(HiveDialect {}),
|
Box::new(HiveDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(RedshiftSqlDialect {}),
|
Box::new(RedshiftSqlDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(MySqlDialect {}),
|
Box::new(MySqlDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(BigQueryDialect {}),
|
Box::new(BigQueryDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(SQLiteDialect {}),
|
Box::new(SQLiteDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(DuckDbDialect {}),
|
Box::new(DuckDbDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(DatabricksDialect {}),
|
Box::new(DatabricksDialect {}) as Box<dyn Dialect>,
|
||||||
Box::new(ClickHouseDialect {}),
|
];
|
||||||
])
|
TestedDialects {
|
||||||
}
|
dialects: all_dialects,
|
||||||
|
options: None,
|
||||||
// Returns all available dialects with the specified parser options
|
}
|
||||||
pub fn all_dialects_with_options(options: ParserOptions) -> TestedDialects {
|
|
||||||
TestedDialects::new_with_options(all_dialects().dialects, options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all dialects matching the given predicate.
|
/// Returns all dialects matching the given predicate.
|
||||||
|
@ -348,14 +274,11 @@ pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTa
|
||||||
if_exists,
|
if_exists,
|
||||||
only: is_only,
|
only: is_only,
|
||||||
operations,
|
operations,
|
||||||
on_cluster: _,
|
|
||||||
location: _,
|
location: _,
|
||||||
iceberg,
|
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(name.to_string(), expected_name);
|
assert_eq!(name.to_string(), expected_name);
|
||||||
assert!(!if_exists);
|
assert!(!if_exists);
|
||||||
assert!(!is_only);
|
assert!(!is_only);
|
||||||
assert!(!iceberg);
|
|
||||||
only(operations)
|
only(operations)
|
||||||
}
|
}
|
||||||
_ => panic!("Expected ALTER TABLE statement"),
|
_ => panic!("Expected ALTER TABLE statement"),
|
||||||
|
@ -371,11 +294,6 @@ pub fn number(n: &str) -> Value {
|
||||||
Value::Number(n.parse().unwrap(), false)
|
Value::Number(n.parse().unwrap(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [Value::SingleQuotedString]
|
|
||||||
pub fn single_quoted_string(s: impl Into<String>) -> Value {
|
|
||||||
Value::SingleQuotedString(s.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
|
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
|
||||||
Some(TableAlias {
|
Some(TableAlias {
|
||||||
name: Ident::new(name),
|
name: Ident::new(name),
|
||||||
|
@ -385,37 +303,19 @@ pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
|
||||||
|
|
||||||
pub fn table(name: impl Into<String>) -> TableFactor {
|
pub fn table(name: impl Into<String>) -> TableFactor {
|
||||||
TableFactor::Table {
|
TableFactor::Table {
|
||||||
name: ObjectName::from(vec![Ident::new(name.into())]),
|
name: ObjectName(vec![Ident::new(name.into())]),
|
||||||
alias: None,
|
alias: None,
|
||||||
args: None,
|
args: None,
|
||||||
with_hints: vec![],
|
with_hints: vec![],
|
||||||
version: None,
|
version: None,
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
json_path: None,
|
|
||||||
sample: None,
|
|
||||||
index_hints: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn table_from_name(name: ObjectName) -> TableFactor {
|
|
||||||
TableFactor::Table {
|
|
||||||
name,
|
|
||||||
alias: None,
|
|
||||||
args: None,
|
|
||||||
with_hints: vec![],
|
|
||||||
version: None,
|
|
||||||
partitions: vec![],
|
|
||||||
with_ordinality: false,
|
|
||||||
json_path: None,
|
|
||||||
sample: None,
|
|
||||||
index_hints: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
|
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
|
||||||
TableFactor::Table {
|
TableFactor::Table {
|
||||||
name: ObjectName::from(vec![Ident::new(name)]),
|
name: ObjectName(vec![Ident::new(name)]),
|
||||||
alias: Some(TableAlias {
|
alias: Some(TableAlias {
|
||||||
name: Ident::new(alias),
|
name: Ident::new(alias),
|
||||||
columns: vec![],
|
columns: vec![],
|
||||||
|
@ -425,24 +325,19 @@ pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> Ta
|
||||||
version: None,
|
version: None,
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
with_ordinality: false,
|
with_ordinality: false,
|
||||||
json_path: None,
|
|
||||||
sample: None,
|
|
||||||
index_hints: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(relation: TableFactor) -> Join {
|
pub fn join(relation: TableFactor) -> Join {
|
||||||
Join {
|
Join {
|
||||||
relation,
|
relation,
|
||||||
global: false,
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
join_operator: JoinOperator::Join(JoinConstraint::Natural),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
|
pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
|
||||||
Expr::Function(Function {
|
Expr::Function(Function {
|
||||||
name: ObjectName::from(vec![Ident::new(function)]),
|
name: ObjectName(vec![Ident::new(function)]),
|
||||||
uses_odbc_syntax: false,
|
|
||||||
parameters: FunctionArguments::None,
|
parameters: FunctionArguments::None,
|
||||||
args: FunctionArguments::List(FunctionArgumentList {
|
args: FunctionArguments::List(FunctionArgumentList {
|
||||||
duplicate_treatment: None,
|
duplicate_treatment: None,
|
||||||
|
@ -458,52 +353,3 @@ pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
|
||||||
within_group: vec![],
|
within_group: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the first index column (mysql calls it a key part) of the first index found in a
|
|
||||||
/// [`Statement::CreateIndex`], [`Statement::CreateTable`], or [`Statement::AlterTable`].
|
|
||||||
pub fn index_column(stmt: Statement) -> Expr {
|
|
||||||
match stmt {
|
|
||||||
Statement::CreateIndex(CreateIndex { columns, .. }) => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
Statement::CreateTable(CreateTable { constraints, .. }) => {
|
|
||||||
match constraints.first().unwrap() {
|
|
||||||
TableConstraint::Index { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::Unique { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::PrimaryKey { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::FulltextOrSpatial { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
|
|
||||||
AlterTableOperation::AddConstraint { constraint, .. } => {
|
|
||||||
match constraint {
|
|
||||||
TableConstraint::Index { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::Unique { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::PrimaryKey { columns, .. } => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
TableConstraint::FulltextOrSpatial {
|
|
||||||
columns,
|
|
||||||
..
|
|
||||||
} => columns.first().unwrap().column.expr.clone(),
|
|
||||||
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("Expected a constraint"),
|
|
||||||
},
|
|
||||||
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
1527
src/tokenizer.rs
1527
src/tokenizer.rs
File diff suppressed because it is too large
Load diff
|
@ -1,414 +0,0 @@
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
// or more contributor license agreements. See the NOTICE file
|
|
||||||
// distributed with this work for additional information
|
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
|
||||||
// to you under the Apache License, Version 2.0 (the
|
|
||||||
// "License"); you may not use this file except in compliance
|
|
||||||
// with the License. You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing,
|
|
||||||
// software distributed under the License is distributed on an
|
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
// KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations
|
|
||||||
// under the License.
|
|
||||||
|
|
||||||
use sqlparser::dialect::GenericDialect;
|
|
||||||
use sqlparser::parser::Parser;
|
|
||||||
|
|
||||||
fn prettify(sql: &str) -> String {
|
|
||||||
let ast = Parser::parse_sql(&GenericDialect {}, sql).unwrap();
|
|
||||||
format!("{:#}", ast[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_select() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT a, b, c FROM my_table WHERE x = 1 AND y = 2"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
WHERE
|
|
||||||
x = 1 AND y = 2
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_join() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT a FROM table1 JOIN table2 ON table1.id = table2.id"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
a
|
|
||||||
FROM
|
|
||||||
table1
|
|
||||||
JOIN table2 ON table1.id = table2.id
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_subquery() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT * FROM (SELECT a, b FROM my_table) AS subquery"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
*
|
|
||||||
FROM
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
a,
|
|
||||||
b
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
) AS subquery
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_union() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT a FROM table1 UNION SELECT b FROM table2"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
a
|
|
||||||
FROM
|
|
||||||
table1
|
|
||||||
UNION
|
|
||||||
SELECT
|
|
||||||
b
|
|
||||||
FROM
|
|
||||||
table2
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_group_by() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT a, COUNT(*) FROM my_table GROUP BY a HAVING COUNT(*) > 1"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
a,
|
|
||||||
COUNT(*)
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
GROUP BY
|
|
||||||
a
|
|
||||||
HAVING
|
|
||||||
COUNT(*) > 1
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_cte() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("WITH cte AS (SELECT a, b FROM my_table) SELECT * FROM cte"),
|
|
||||||
r#"
|
|
||||||
WITH cte AS (
|
|
||||||
SELECT
|
|
||||||
a,
|
|
||||||
b
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
*
|
|
||||||
FROM
|
|
||||||
cte
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_case_when() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT CASE WHEN x > 0 THEN 'positive' WHEN x < 0 THEN 'negative' ELSE 'zero' END FROM my_table"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
CASE
|
|
||||||
WHEN x > 0 THEN
|
|
||||||
'positive'
|
|
||||||
WHEN x < 0 THEN
|
|
||||||
'negative'
|
|
||||||
ELSE
|
|
||||||
'zero'
|
|
||||||
END
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
"#.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_window_function() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT id, value, ROW_NUMBER() OVER (PARTITION BY category ORDER BY value DESC) as rank FROM my_table"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
value,
|
|
||||||
ROW_NUMBER() OVER (
|
|
||||||
PARTITION BY category
|
|
||||||
ORDER BY value DESC
|
|
||||||
) AS rank
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
"#.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_multiline_string() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT 'multiline\nstring' AS str"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
'multiline
|
|
||||||
string' AS str
|
|
||||||
"#
|
|
||||||
.trim(),
|
|
||||||
"A literal string with a newline should be kept as is. The contents of the string should not be indented."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_insert_values() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("INSERT INTO my_table (a, b, c) VALUES (1, 2, 3), (4, 5, 6)"),
|
|
||||||
r#"
|
|
||||||
INSERT INTO my_table (a, b, c)
|
|
||||||
VALUES
|
|
||||||
(1, 2, 3),
|
|
||||||
(4, 5, 6)
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_insert_select() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("INSERT INTO my_table (a, b) SELECT x, y FROM source_table RETURNING a AS id"),
|
|
||||||
r#"
|
|
||||||
INSERT INTO my_table (a, b)
|
|
||||||
SELECT
|
|
||||||
x,
|
|
||||||
y
|
|
||||||
FROM
|
|
||||||
source_table
|
|
||||||
RETURNING
|
|
||||||
a AS id
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_update() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("UPDATE my_table SET a = 1, b = 2 WHERE x > 0 RETURNING id, name"),
|
|
||||||
r#"
|
|
||||||
UPDATE my_table
|
|
||||||
SET
|
|
||||||
a = 1,
|
|
||||||
b = 2
|
|
||||||
WHERE
|
|
||||||
x > 0
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_delete() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("DELETE FROM my_table WHERE x > 0 RETURNING id, name"),
|
|
||||||
r#"
|
|
||||||
DELETE FROM
|
|
||||||
my_table
|
|
||||||
WHERE
|
|
||||||
x > 0
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
prettify("DELETE table1, table2"),
|
|
||||||
r#"
|
|
||||||
DELETE
|
|
||||||
table1,
|
|
||||||
table2
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_create_table() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("CREATE TABLE my_table (id INT PRIMARY KEY, name VARCHAR(255) NOT NULL, CONSTRAINT fk_other FOREIGN KEY (id) REFERENCES other_table(id))"),
|
|
||||||
r#"
|
|
||||||
CREATE TABLE my_table (
|
|
||||||
id INT PRIMARY KEY,
|
|
||||||
name VARCHAR(255) NOT NULL,
|
|
||||||
CONSTRAINT fk_other FOREIGN KEY (id) REFERENCES other_table(id)
|
|
||||||
)
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pretty_print_create_view() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("CREATE VIEW my_view AS SELECT a, b FROM my_table WHERE x > 0"),
|
|
||||||
r#"
|
|
||||||
CREATE VIEW my_view AS
|
|
||||||
SELECT
|
|
||||||
a,
|
|
||||||
b
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
WHERE
|
|
||||||
x > 0
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_create_function() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("CREATE FUNCTION my_func() RETURNS INT BEGIN SELECT COUNT(*) INTO @count FROM my_table; RETURN @count; END"),
|
|
||||||
r#"
|
|
||||||
CREATE FUNCTION my_func() RETURNS INT
|
|
||||||
BEGIN
|
|
||||||
SELECT COUNT(*) INTO @count FROM my_table;
|
|
||||||
RETURN @count;
|
|
||||||
END
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_json_table() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("SELECT * FROM JSON_TABLE(@json, '$[*]' COLUMNS (id INT PATH '$.id', name VARCHAR(255) PATH '$.name')) AS jt"),
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
*
|
|
||||||
FROM
|
|
||||||
JSON_TABLE(
|
|
||||||
@json,
|
|
||||||
'$[*]' COLUMNS (
|
|
||||||
id INT PATH '$.id',
|
|
||||||
name VARCHAR(255) PATH '$.name'
|
|
||||||
)
|
|
||||||
) AS jt
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_transaction_blocks() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("BEGIN; UPDATE my_table SET x = 1; COMMIT;"),
|
|
||||||
r#"
|
|
||||||
BEGIN;
|
|
||||||
UPDATE my_table SET x = 1;
|
|
||||||
COMMIT;
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_control_flow() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("IF x > 0 THEN SELECT 'positive'; ELSE SELECT 'negative'; END IF;"),
|
|
||||||
r#"
|
|
||||||
IF x > 0 THEN
|
|
||||||
SELECT 'positive';
|
|
||||||
ELSE
|
|
||||||
SELECT 'negative';
|
|
||||||
END IF;
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_merge() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("MERGE INTO target_table t USING source_table s ON t.id = s.id WHEN MATCHED THEN UPDATE SET t.value = s.value WHEN NOT MATCHED THEN INSERT (id, value) VALUES (s.id, s.value)"),
|
|
||||||
r#"
|
|
||||||
MERGE INTO target_table t
|
|
||||||
USING source_table s ON t.id = s.id
|
|
||||||
WHEN MATCHED THEN
|
|
||||||
UPDATE SET t.value = s.value
|
|
||||||
WHEN NOT MATCHED THEN
|
|
||||||
INSERT (id, value) VALUES (s.id, s.value)
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_create_index() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("CREATE INDEX idx_name ON my_table (column1, column2)"),
|
|
||||||
r#"
|
|
||||||
CREATE INDEX idx_name
|
|
||||||
ON my_table (column1, column2)
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
|
|
||||||
fn test_pretty_print_explain() {
|
|
||||||
assert_eq!(
|
|
||||||
prettify("EXPLAIN ANALYZE SELECT * FROM my_table WHERE x > 0"),
|
|
||||||
r#"
|
|
||||||
EXPLAIN ANALYZE
|
|
||||||
SELECT
|
|
||||||
*
|
|
||||||
FROM
|
|
||||||
my_table
|
|
||||||
WHERE
|
|
||||||
x > 0
|
|
||||||
"#
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,21 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
|
|
||||||
select
|
select
|
||||||
l_returnflag,
|
l_returnflag,
|
||||||
l_linestatus,
|
l_linestatus,
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
create view revenue0 (supplier_no, total_revenue) as
|
create view revenue0 (supplier_no, total_revenue) as
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,6 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
select
|
select
|
||||||
s_acctbal,
|
s_acctbal,
|
||||||
s_name,
|
s_name,
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,3 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,6 @@
|
||||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
-- or more contributor license agreements. See the NOTICE file
|
|
||||||
-- distributed with this work for additional information
|
|
||||||
-- regarding copyright ownership. The ASF licenses this file
|
|
||||||
-- to you under the Apache License, Version 2.0 (the
|
|
||||||
-- "License"); you may not use this file except in compliance
|
|
||||||
-- with the License. You may obtain a copy of the License at
|
|
||||||
--
|
|
||||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
--
|
|
||||||
-- Unless required by applicable law or agreed to in writing,
|
|
||||||
-- software distributed under the License is distributed on an
|
|
||||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
-- KIND, either express or implied. See the License for the
|
|
||||||
-- specific language governing permissions and limitations
|
|
||||||
-- under the License.
|
|
||||||
|
|
||||||
|
|
||||||
-- using default substitutions
|
-- using default substitutions
|
||||||
|
|
||||||
|
|
||||||
select
|
select
|
||||||
sum(l_extendedprice * l_discount) as revenue
|
sum(l_extendedprice * l_discount) as revenue
|
||||||
from
|
from
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue