mirror of
https://github.com/neilotoole/sq.git
synced 2024-11-27 15:43:21 +03:00
Add flag --src.schema (#326)
* Support for --src.schema in commands "slq", "sql", and "inspect"
This commit is contained in:
parent
3735e803b0
commit
f07edef14d
21
.github/workflows/codacy.yml
vendored
21
.github/workflows/codacy.yml
vendored
@ -14,27 +14,8 @@
|
||||
name: Codacy Security Scan
|
||||
|
||||
on:
|
||||
# push:
|
||||
# branches: [ "master" ]
|
||||
# paths-ignore:
|
||||
# - '**.md'
|
||||
# - 'sq.json' # This is updated by scoop; no need to run a new build
|
||||
# - '.github/**'
|
||||
# pull_request:
|
||||
# # The branches below must be a subset of the branches above
|
||||
# branches: [ "master" ]
|
||||
# paths-ignore:
|
||||
# - '**.md'
|
||||
# - 'sq.json' # This is updated by scoop; no need to run a new build
|
||||
# - '.github/**'
|
||||
schedule:
|
||||
- cron: '43 3 * * 0'
|
||||
paths-ignore:
|
||||
- 'grammar/grun/**'
|
||||
- 'cli/testdata/*.rb'
|
||||
- 'magefile.go'
|
||||
# jcolorenc has a bunch of "unsafe" stuff in it
|
||||
- 'cli/output/jsonw/internal/jcolorenc/**'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@ -64,7 +45,7 @@ jobs:
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
|
||||
uses: codacy/codacy-analysis-cli-action@master
|
||||
with:
|
||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||
# You can also omit the token and run the tools that support default configurations
|
||||
|
146
.github/workflows/main.yml
vendored
146
.github/workflows/main.yml
vendored
@ -12,6 +12,7 @@ env:
|
||||
GO_VERSION: 1.21.0
|
||||
GORELEASER_VERSION: 1.20.0
|
||||
GOLANGCI_LINT_VERSION: v1.54.1
|
||||
TPARSE_VERSION: v0.11.1
|
||||
BUILD_TAGS: 'sqlite_vtable sqlite_stat4 sqlite_fts5 sqlite_introspect sqlite_json sqlite_math_functions'
|
||||
|
||||
jobs:
|
||||
@ -24,41 +25,36 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
# Install gotestfmt on the VM running the action.
|
||||
- name: Set up gotestfmt
|
||||
uses: gotesttools/gotestfmt-action@v2
|
||||
with:
|
||||
# Optional: pass GITHUB_TOKEN to avoid rate limiting.
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
go-version-file: go.mod
|
||||
|
||||
|
||||
- name: Build
|
||||
run: go build -tags '${{ env.BUILD_TAGS }}' -v ./...
|
||||
|
||||
# Run tests with nice formatting. Save the original log in /tmp/gotest.log
|
||||
# https://github.com/GoTestTools/gotestfmt#github-actions
|
||||
- name: Run tests
|
||||
- name: 'Go tests'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
go test -tags '${{ env.BUILD_TAGS }}' -json -v ./... 2>&1 | tee gotest.log | gotestfmt
|
||||
set -e
|
||||
|
||||
# Upload the original go test log as an artifact for later review.
|
||||
- name: Upload test log
|
||||
uses: actions/upload-artifact@v3
|
||||
# We tee the go test output to a file, so that "tparse" can
|
||||
# render pretty output below.
|
||||
go test -tags '${{ env.BUILD_TAGS }}' -timeout 20m -v -json -cover ./... | tee gotest.out.json
|
||||
|
||||
- name: 'Test output'
|
||||
if: always()
|
||||
with:
|
||||
name: test-log
|
||||
path: gotest.log
|
||||
if-no-files-found: warn
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go install github.com/mfridman/tparse@${{ env.TPARSE_VERSION }}
|
||||
tparse -all -sort=elapsed -file gotest.out.json
|
||||
|
||||
|
||||
test-windows:
|
||||
runs-on: windows-2022
|
||||
@ -72,69 +68,69 @@ jobs:
|
||||
# path-type: inherit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Build
|
||||
run: go build -tags '${{ env.BUILD_TAGS }}' -v ./...
|
||||
# shell: msys2 {0}
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
go test -tags '${{ env.BUILD_TAGS }}' -v ./...
|
||||
# shell: msys2 {0}
|
||||
# - name: Run tests
|
||||
# run: |
|
||||
# go test -tags '${{ env.BUILD_TAGS }}' -v ./...
|
||||
## shell: msys2 {0}
|
||||
|
||||
go-lint:
|
||||
- name: 'Go tests'
|
||||
shell: bash
|
||||
run: |
|
||||
# set -e
|
||||
|
||||
# We send the Go test output to a file, so that "tparse" can
|
||||
# render pretty output below.
|
||||
go test -tags '${{ env.BUILD_TAGS }}' -timeout 20m -v -json -cover ./... > gotest.out.json
|
||||
|
||||
- name: 'Test output'
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go install github.com/mfridman/tparse@${{ env.TPARSE_VERSION }}
|
||||
tparse -all -sort=elapsed -file gotest.out.json
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Lint GH workflow files
|
||||
run: |
|
||||
# From https://github.com/rhysd/actionlint
|
||||
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
|
||||
./actionlint -color
|
||||
|
||||
- name: shellcheck
|
||||
run: |
|
||||
shellcheck ./install.sh
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: ${{ env.GOLANGCI_LINT_VERSION }}
|
||||
|
||||
# coverage:
|
||||
# runs-on: ubuntu-22.04
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
#
|
||||
# - name: Set up Go
|
||||
# uses: actions/setup-go@v3
|
||||
# with:
|
||||
# go-version: ${{ env.GO_VERSION }}
|
||||
#
|
||||
# - name: Test
|
||||
# run: go test -v ./...
|
||||
#
|
||||
# # https://github.com/ncruces/go-coverage-report
|
||||
# - name: Update coverage report
|
||||
# uses: ncruces/go-coverage-report@v0
|
||||
# with:
|
||||
# report: 'true'
|
||||
# chart: 'true'
|
||||
# amend: 'false'
|
||||
# if: |
|
||||
# github.event_name == 'push'
|
||||
# continue-on-error: true
|
||||
|
||||
|
||||
binaries-darwin:
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
@ -142,14 +138,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: GoReleaser (build darwin binaries)
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
@ -173,14 +169,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: GoReleaser (build linux-amd64 binaries)
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
@ -204,14 +200,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Install toolchain dependencies
|
||||
run: |
|
||||
@ -241,14 +237,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: GoReleaser (build windows binaries)
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
@ -271,7 +267,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs:
|
||||
- go-lint
|
||||
- lint
|
||||
- test-linux-darwin
|
||||
- test-windows
|
||||
- binaries-darwin
|
||||
@ -280,14 +276,14 @@ jobs:
|
||||
- binaries-windows
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Download darwin artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
|
36
.github/workflows/test-install.yml
vendored
36
.github/workflows/test-install.yml
vendored
@ -16,10 +16,10 @@ jobs:
|
||||
|
||||
- name: Test brew
|
||||
shell: bash
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
brew install neilotoole/sq/sq
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -33,10 +33,10 @@ jobs:
|
||||
|
||||
- name: Test install.sh
|
||||
shell: bash
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
/bin/sh -c "$(curl -fsSL https://sq.io/install.sh)"
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -57,7 +57,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Test install.sh
|
||||
run: |-
|
||||
run: |
|
||||
set pipefail
|
||||
set +e
|
||||
|
||||
@ -71,7 +71,7 @@ jobs:
|
||||
set -e
|
||||
|
||||
/bin/sh -c "$(curl -fsSL https://sq.io/install.sh)"
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -82,11 +82,11 @@ jobs:
|
||||
container: alpine:latest
|
||||
steps:
|
||||
- name: Test install
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
apk add curl
|
||||
/bin/sh -c "$(curl -fsSL https://sq.io/install.sh)"
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -97,7 +97,7 @@ jobs:
|
||||
container: archlinux:latest
|
||||
steps:
|
||||
- name: Create non-root user
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
pacman -Syu --noconfirm
|
||||
@ -111,7 +111,7 @@ jobs:
|
||||
chown -R "$uname:$uname" /home/$uname
|
||||
|
||||
- name: Test install (pacman)
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
# Run as non-root user
|
||||
@ -119,7 +119,7 @@ jobs:
|
||||
|
||||
# Should be installed via pacman
|
||||
sudo -u moi /bin/sh -c "$(curl -fsSL https://sq.io/install.sh)"
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -130,7 +130,7 @@ jobs:
|
||||
container: archlinux:latest
|
||||
steps:
|
||||
- name: Create non-root user
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
pacman -Syu --noconfirm
|
||||
@ -144,7 +144,7 @@ jobs:
|
||||
chown -R "$uname:$uname" /home/$uname
|
||||
|
||||
- name: Install yay
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
cd /tmp
|
||||
curl -sO https://aur.archlinux.org/cgit/aur.git/snapshot/yay-bin.tar.gz
|
||||
@ -154,12 +154,12 @@ jobs:
|
||||
sudo -u moi makepkg -sri --noconfirm
|
||||
|
||||
- name: Test install (yay)
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
|
||||
# Should be installed via yay
|
||||
sudo -u moi /bin/sh -c "$(curl -fsSL https://sq.io/install.sh)"
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -174,10 +174,10 @@ jobs:
|
||||
|
||||
- name: Test install via brew
|
||||
shell: bash
|
||||
run: |-
|
||||
run: |
|
||||
set -e pipefail
|
||||
brew install neilotoole/sq/sq
|
||||
if [ $(sq version | awk '{print $2}') != "${{github.ref_name}}" ]; then
|
||||
if [ "$(sq version | awk '{print $2}')" != "${{github.ref_name}}" ]; then
|
||||
echo "Expected sq ${{github.ref_name}} but got: $(sq version)"
|
||||
exit 1
|
||||
fi
|
||||
@ -205,7 +205,7 @@ jobs:
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Test install (scoop)
|
||||
run: |-
|
||||
run: |
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
|
||||
|
||||
|
1
.shellcheckrc
Normal file
1
.shellcheckrc
Normal file
@ -0,0 +1 @@
|
||||
external-sources=true
|
22
CHANGELOG.md
22
CHANGELOG.md
@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
Breaking changes are annotated with ☢️, and alpha/beta features with 🐥.
|
||||
|
||||
## Upcoming
|
||||
|
||||
### Added
|
||||
|
||||
- [#270]: Flag `--src.schema` permits switching the source's schema (and catalog)
|
||||
for the duration of the command. It is supported for the
|
||||
[`sq`](https://sq.io/docs/cmd/sq), [`sql`](https://sq.io/docs/cmd/sql)
|
||||
and [`inspect`](https://sq.io/docs/cmd/sq) commands.
|
||||
- New SLQ functions [`catalog()`](https://sq.io/docs/query#catalog) and
|
||||
[`schema()`](https://sq.io/docs/query#schema) return the catalog and schema of the DB connection.
|
||||
- The SLQ [`unique`](https://sq.io/docs/query#unique) function now has a synonym `uniq`.
|
||||
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- `sq src --text` now outputs only the handle of the active source. Previously it
|
||||
also printed the driver type and short location. Instead use `sq src --text --verbose` to
|
||||
see those details.
|
||||
|
||||
## [v0.42.1] - 2023-09-10
|
||||
|
||||
### Fixed
|
||||
@ -800,10 +820,12 @@ make working with lots of sources much easier.
|
||||
[#258]: https://github.com/neilotoole/sq/issues/258
|
||||
[#261]: https://github.com/neilotoole/sq/issues/261
|
||||
[#263]: https://github.com/neilotoole/sq/issues/263
|
||||
[#270]: https://github.com/neilotoole/sq/issues/270
|
||||
[#277]: https://github.com/neilotoole/sq/issues/277
|
||||
[#279]: https://github.com/neilotoole/sq/issues/279
|
||||
[#308]: https://github.com/neilotoole/sq/pull/308
|
||||
|
||||
|
||||
[v0.15.2]: https://github.com/neilotoole/sq/releases/tag/v0.15.2
|
||||
[v0.15.3]: https://github.com/neilotoole/sq/compare/v0.15.2...v0.15.3
|
||||
[v0.15.4]: https://github.com/neilotoole/sq/compare/v0.15.3...v0.15.4
|
||||
|
3
Makefile
3
Makefile
@ -3,7 +3,7 @@ VERSION_PKG := $(PKG)/cli/buildinfo
|
||||
BUILD_VERSION := $(shell git describe --tags --always --dirty)
|
||||
BUILD_COMMIT := $(shell git rev-parse HEAD)
|
||||
BUILD_TIMESTAMP := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
|
||||
LDFLAGS ?= -s -w -X $(VERSION_PKG).Version=$(BUILD_VERSION) -X $(VERSION_PKG).Commit=$(BUILD_COMMIT) -X $(VERSION_PKG).Timestamp=$(BUILD_TIMESTAMP)
|
||||
LDFLAGS := -X $(VERSION_PKG).Version=$(BUILD_VERSION) -X $(VERSION_PKG).Commit=$(BUILD_COMMIT) -X $(VERSION_PKG).Timestamp=$(BUILD_TIMESTAMP)
|
||||
BUILD_TAGS := sqlite_vtable sqlite_stat4 sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_math_functions
|
||||
|
||||
.PHONY: test
|
||||
@ -17,6 +17,7 @@ install:
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@golangci-lint run --out-format tab --sort-results
|
||||
@shellcheck ./install.sh
|
||||
|
||||
.PHONY: gen
|
||||
gen:
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
@ -95,7 +97,7 @@ func TestCreateTblTestBytes(t *testing.T) {
|
||||
|
||||
require.Equal(t, int64(1), th.CreateTable(true, src, tblDef, data))
|
||||
t.Logf(src.Location)
|
||||
th.DropTable(src, tblDef.Name)
|
||||
th.DropTable(src, tablefq.From(tblDef.Name))
|
||||
}
|
||||
|
||||
// TestOutputRaw verifies that the raw output format works.
|
||||
@ -126,12 +128,12 @@ func TestOutputRaw(t *testing.T) {
|
||||
// Create the table and insert data
|
||||
insertRow := []any{fixt.GopherFilename, wantBytes}
|
||||
require.Equal(t, int64(1), th.CreateTable(true, src, tblDef, insertRow))
|
||||
defer th.DropTable(src, tblDef.Name)
|
||||
defer th.DropTable(src, tablefq.From(tblDef.Name))
|
||||
|
||||
// 1. Query and check that libsq is returning bytes correctly.
|
||||
query := fmt.Sprintf("SELECT col_bytes FROM %s WHERE col_name = '%s'",
|
||||
tblDef.Name, fixt.GopherFilename)
|
||||
sink, err := th.QuerySQL(src, query)
|
||||
sink, err := th.QuerySQL(src, nil, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
|
@ -8,6 +8,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
"github.com/neilotoole/sq/libsq/core/lg/lga"
|
||||
|
||||
"github.com/neilotoole/sq/cli/run"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/csv"
|
||||
@ -178,7 +181,8 @@ More examples:
|
||||
}
|
||||
|
||||
func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
ru := run.FromContext(cmd.Context())
|
||||
ctx := cmd.Context()
|
||||
ru := run.FromContext(ctx)
|
||||
cfg := ru.Config
|
||||
|
||||
loc := source.AbsLocation(strings.TrimSpace(args[0]))
|
||||
@ -189,7 +193,7 @@ func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
val, _ := cmd.Flags().GetString(flag.AddDriver)
|
||||
typ = source.DriverType(strings.TrimSpace(val))
|
||||
} else {
|
||||
typ, err = ru.Files.DriverType(cmd.Context(), loc)
|
||||
typ, err = ru.Files.DriverType(ctx, loc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -225,18 +229,21 @@ func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if typ == sqlite3.Type {
|
||||
locBefore := loc
|
||||
// Special handling for SQLite, because it's a file-based DB.
|
||||
loc, err = sqlite3.MungeLocation(loc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lg.FromContext(ctx).Debug("Munged sqlite loc", lga.Before, locBefore, lga.After, loc)
|
||||
}
|
||||
|
||||
// If the -p flag is set, sq looks for password input on stdin,
|
||||
// or sq prompts the user.
|
||||
if cmdFlagIsSetTrue(cmd, flag.PasswordPrompt) {
|
||||
var passwd []byte
|
||||
if passwd, err = readPassword(cmd.Context(), ru.Stdin, ru.Out, ru.Writers.Printing); err != nil {
|
||||
if passwd, err = readPassword(ctx, ru.Stdin, ru.Out, ru.Writers.Printing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -251,7 +258,7 @@ func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
src, err := newSource(
|
||||
cmd.Context(),
|
||||
ctx,
|
||||
ru.DriverRegistry,
|
||||
typ,
|
||||
handle,
|
||||
@ -285,12 +292,12 @@ func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
if !cmdFlagIsSetTrue(cmd, flag.SkipVerify) {
|
||||
// Typically we want to ping the source before adding it.
|
||||
// But, sometimes not, for example if a source is temporarily offline.
|
||||
if err = drvr.Ping(cmd.Context(), src); err != nil {
|
||||
if err = drvr.Ping(ctx, src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = ru.ConfigStore.Save(cmd.Context(), ru.Config); err != nil {
|
||||
if err = ru.ConfigStore.Save(ctx, ru.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -298,7 +305,7 @@ func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return ru.Writers.Source.Source(ru.Config.Collection, src)
|
||||
return ru.Writers.Source.Added(ru.Config.Collection, src)
|
||||
}
|
||||
|
||||
// readPassword reads a password from stdin pipe, or if nothing on stdin,
|
||||
|
@ -223,8 +223,7 @@ func TestCmdAdd(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
tr = testrun.New(th.Context, t, tr)
|
||||
err = tr.Exec(tc.query.q, "--json")
|
||||
err = tr.Reset().Exec(tc.query.q, "--json")
|
||||
require.NoError(t, err)
|
||||
var results []map[string]any
|
||||
tr.Bind(&results)
|
||||
|
@ -135,11 +135,30 @@ func execConfigEditSource(cmd *cobra.Command, args []string) error {
|
||||
|
||||
tmpSrc := src.Clone()
|
||||
tmpSrc.Options = nil
|
||||
|
||||
// The Catalog and Schema fields have yaml tag 'omitempty',
|
||||
// so they wouldn't be rendered in the editor yaml if empty.
|
||||
// However, we to render the fields commented-out if empty.
|
||||
// Hence this little hack.
|
||||
if tmpSrc.Catalog == "" {
|
||||
// Forces yaml rendering
|
||||
tmpSrc.Catalog = " "
|
||||
}
|
||||
|
||||
if tmpSrc.Schema == "" {
|
||||
// Forces yaml rendering
|
||||
tmpSrc.Schema = " "
|
||||
}
|
||||
|
||||
header, err := ioz.MarshalYAML(tmpSrc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// And now we replace the rendered values with commented-out values.
|
||||
header = bytes.Replace(header, []byte("catalog: \n"), []byte("#catalog: \n"), 1)
|
||||
header = bytes.Replace(header, []byte("schema: \n"), []byte("#schema: \n"), 1)
|
||||
|
||||
sb := strings.Builder{}
|
||||
sb.Write(header)
|
||||
sb.WriteString("options:\n")
|
||||
@ -197,6 +216,9 @@ func execConfigEditSource(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should validate the source here. For example, the MySQL driver
|
||||
// doesn't support the Catalog field.
|
||||
|
||||
*src = *src2
|
||||
|
||||
// TODO: if --verbose, show diff between config before and after.
|
||||
|
@ -62,10 +62,17 @@ formats both show extensive detail.`,
|
||||
# Inspect "actor" in active data source.
|
||||
$ sq inspect .actor
|
||||
|
||||
# Inspect a non-default schema in source @my1.
|
||||
$ sq inspect @my1 --src.schema information_schema
|
||||
|
||||
# Inspect piped data.
|
||||
$ cat data.xlsx | sq inspect`,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flag.ActiveSchema, "", flag.ActiveSchemaUsage)
|
||||
panicOn(cmd.RegisterFlagCompletionFunc(flag.ActiveSchema,
|
||||
activeSchemaCompleter{getActiveSourceViaArgs}.complete))
|
||||
|
||||
addTextFlags(cmd)
|
||||
cmd.Flags().BoolP(flag.JSON, flag.JSONShort, false, flag.JSONUsage)
|
||||
cmd.Flags().BoolP(flag.Compact, flag.CompactShort, false, flag.CompactUsage)
|
||||
@ -83,11 +90,12 @@ func execInspect(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
ru := run.FromContext(ctx)
|
||||
|
||||
coll := ru.Config.Collection
|
||||
|
||||
var src *source.Source
|
||||
var table string
|
||||
var err error
|
||||
var (
|
||||
coll = ru.Config.Collection
|
||||
src *source.Source
|
||||
table string
|
||||
err error
|
||||
)
|
||||
|
||||
if len(args) == 0 {
|
||||
// No args supplied.
|
||||
@ -148,6 +156,12 @@ func execInspect(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle flag.ActiveSchema (--src.schema=SCHEMA). This func will mutate
|
||||
// src's Catalog and Schema fields if appropriate.
|
||||
if err = processFlagActiveSchema(cmd, src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = applySourceOptions(cmd, src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,7 +104,14 @@ func execMoveRenameGroup(cmd *cobra.Command, oldGroup, newGroup string) error {
|
||||
// @sakiladb
|
||||
func execMoveHandleToGroup(cmd *cobra.Command, oldHandle, newGroup string) error {
|
||||
ru := run.FromContext(cmd.Context())
|
||||
src, err := ru.Config.Collection.MoveHandleToGroup(oldHandle, newGroup)
|
||||
oldSrc, err := ru.Config.Collection.Get(oldHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make a clone, because the original may get modified.
|
||||
oldSrc = oldSrc.Clone()
|
||||
newSrc, err := ru.Config.Collection.MoveHandleToGroup(oldHandle, newGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,7 +124,7 @@ func execMoveHandleToGroup(cmd *cobra.Command, oldHandle, newGroup string) error
|
||||
return err
|
||||
}
|
||||
|
||||
return ru.Writers.Source.Source(ru.Config.Collection, src)
|
||||
return ru.Writers.Source.Moved(ru.Config.Collection, oldSrc, newSrc)
|
||||
}
|
||||
|
||||
// execMoveRenameHandle renames a handle.
|
||||
@ -126,7 +133,15 @@ func execMoveHandleToGroup(cmd *cobra.Command, oldHandle, newGroup string) error
|
||||
// $ sq mv @sakiladb @sakila/db
|
||||
func execMoveRenameHandle(cmd *cobra.Command, oldHandle, newHandle string) error {
|
||||
ru := run.FromContext(cmd.Context())
|
||||
src, err := ru.Config.Collection.RenameSource(oldHandle, newHandle)
|
||||
oldSrc, err := ru.Config.Collection.Get(oldHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make a clone, because the original may get modified.
|
||||
oldSrc = oldSrc.Clone()
|
||||
|
||||
newSrc, err := ru.Config.Collection.RenameSource(oldHandle, newHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -139,7 +154,7 @@ func execMoveRenameHandle(cmd *cobra.Command, oldHandle, newHandle string) error
|
||||
return err
|
||||
}
|
||||
|
||||
return ru.Writers.Source.Source(ru.Config.Collection, src)
|
||||
return ru.Writers.Source.Moved(ru.Config.Collection, oldSrc, newSrc)
|
||||
}
|
||||
|
||||
// completeMove is a completionFunc for the "mv" command.
|
||||
|
@ -27,8 +27,9 @@ to copy, truncate and drop tables. Use "sq diff" to compare source metadata
|
||||
and row data.
|
||||
|
||||
See docs and more: https://sq.io`,
|
||||
Example: `# Add Postgres source identified by handle @sakila_pg
|
||||
$ sq add --handle=@sakila_pg 'postgres://user:pass@localhost:5432/sakila'
|
||||
Example: ` # Add Postgres source.
|
||||
$ sq add postgres://user@localhost/sakila -p
|
||||
Password: ****
|
||||
|
||||
# List available data sources.
|
||||
$ sq ls
|
||||
|
@ -65,26 +65,13 @@ func execSLQ(cmd *cobra.Command, args []string) error {
|
||||
ru := run.FromContext(ctx)
|
||||
coll := ru.Config.Collection
|
||||
|
||||
// check if there's input on stdin
|
||||
src, err := checkStdinSource(ctx, ru)
|
||||
err := determineSources(ctx, ru, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if src != nil {
|
||||
// We have a valid source on stdin.
|
||||
|
||||
// Add the source to the set.
|
||||
if err = coll.Add(src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the stdin pipe data source as the active source,
|
||||
// as it's commonly the only data source the user is acting upon.
|
||||
if _, err = coll.SetActive(src.Handle, false); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if coll.Active() == nil {
|
||||
activeSrc := coll.Active()
|
||||
if activeSrc == nil {
|
||||
lg.FromContext(ctx).Debug("No active source; continuing regardless...")
|
||||
// Previously, an error was returned if there was no active source.
|
||||
// However, we want to support the use case of being able to
|
||||
@ -351,6 +338,10 @@ func addQueryCmdFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String(flag.ActiveSrc, "", flag.ActiveSrcUsage)
|
||||
panicOn(cmd.RegisterFlagCompletionFunc(flag.ActiveSrc, completeHandle(0)))
|
||||
|
||||
cmd.Flags().String(flag.ActiveSchema, "", flag.ActiveSchemaUsage)
|
||||
panicOn(cmd.RegisterFlagCompletionFunc(flag.ActiveSchema,
|
||||
activeSchemaCompleter{getActiveSourceViaFlag}.complete))
|
||||
|
||||
// The driver flag can be used if data is piped to sq over stdin
|
||||
cmd.Flags().String(flag.IngestDriver, "", flag.IngestDriverUsage)
|
||||
panicOn(cmd.RegisterFlagCompletionFunc(flag.IngestDriver, completeDriverType))
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -8,6 +9,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/testh/proj"
|
||||
|
||||
"github.com/neilotoole/sq/cli"
|
||||
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
@ -44,7 +49,7 @@ func TestCmdSLQ_Insert_Create(t *testing.T) {
|
||||
err := tr.Exec("slq", "--insert="+insertTo, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
sink, err := th.QuerySQL(destSrc, "select * from "+destTbl)
|
||||
sink, err := th.QuerySQL(destSrc, nil, "select * from "+destTbl)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
}
|
||||
@ -70,7 +75,13 @@ func TestCmdSLQ_Insert(t *testing.T) {
|
||||
|
||||
// To avoid dirtying the destination table, we make a copy
|
||||
// of it (without data).
|
||||
tblName := th.CopyTable(true, destSrc, sakila.TblActor, "", false)
|
||||
tblName := th.CopyTable(
|
||||
true,
|
||||
destSrc,
|
||||
tablefq.From(sakila.TblActor),
|
||||
tablefq.T{},
|
||||
false,
|
||||
)
|
||||
|
||||
tr := testrun.New(th.Context, t, nil).Add(*originSrc)
|
||||
if destSrc.Handle != originSrc.Handle {
|
||||
@ -84,7 +95,7 @@ func TestCmdSLQ_Insert(t *testing.T) {
|
||||
err := tr.Exec("slq", "--insert="+insertTo, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
sink, err := th.QuerySQL(destSrc, "select * from "+tblName)
|
||||
sink, err := th.QuerySQL(destSrc, nil, "select * from "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
})
|
||||
@ -195,7 +206,7 @@ func TestCmdSLQ_ActiveSrcHandle(t *testing.T) {
|
||||
require.Equal(t, sakila.TblActorCount, len(recs))
|
||||
}
|
||||
|
||||
func TestPreprocessFlagArgVars(t *testing.T) {
|
||||
func TestCmdSLQ_PreprocessFlagArgVars(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in []string
|
||||
@ -274,3 +285,160 @@ func TestPreprocessFlagArgVars(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmdSLQ_FlagActiveSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
tr := testrun.New(ctx, t, nil)
|
||||
|
||||
// @sqlite will be the active source
|
||||
require.NoError(t, tr.Exec("add", proj.Abs(sakila.PathSL3), "--handle", "@sqlite"))
|
||||
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec("add", proj.Abs(sakila.PathCSVActor), "--handle", "@csv"))
|
||||
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec(
|
||||
"--csv",
|
||||
"--no-header",
|
||||
".actor",
|
||||
))
|
||||
require.Len(t, tr.BindCSV(), sakila.TblActorCount)
|
||||
|
||||
// Now, use flag.ActiveSrc to switch the source.
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec(
|
||||
"--csv",
|
||||
"--no-header",
|
||||
"--src", "@csv",
|
||||
".data",
|
||||
))
|
||||
require.Len(t, tr.BindCSV(), sakila.TblActorCount)
|
||||
|
||||
// Double check that we didn't change the persisted active source
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec("src", "--json"))
|
||||
require.Equal(t, "@sqlite", tr.BindMap()["handle"])
|
||||
}
|
||||
|
||||
func TestCmdSLQ_FlagActiveSchema(t *testing.T) {
|
||||
testCases := []struct {
|
||||
handle string
|
||||
|
||||
// skipReason is the reason to skip the test case.
|
||||
skipReason string
|
||||
|
||||
// defaultCatalog is the default catalog for the source.
|
||||
defaultCatalog string
|
||||
|
||||
// defaultSchema is the default schema for the source,
|
||||
// e.g. "public" for Pg, or "dbo" for SQL Server.
|
||||
defaultSchema string
|
||||
|
||||
// altCatalog is the name of a second catalog that
|
||||
// we know to exist in the source. For example, "model"
|
||||
// for SQL Server, or "postgres" for Postgres.
|
||||
altCatalog string
|
||||
|
||||
// expectSchemaFuncValue is the value we expect
|
||||
// the SLQ "schema()" func to return. Generally one would
|
||||
// expect this to be the same as the value supplied
|
||||
// to --src.schema, but for SQL Server, the SLQ "schema()"
|
||||
// func does not honor --src.schema. This is a limitation in
|
||||
// SQL Server itself; it's not possible to change the default
|
||||
// schema for a connection.
|
||||
expectSchemaFuncValue string
|
||||
}{
|
||||
{
|
||||
handle: sakila.Pg,
|
||||
defaultCatalog: "sakila",
|
||||
defaultSchema: "public",
|
||||
altCatalog: "postgres",
|
||||
expectSchemaFuncValue: "information_schema",
|
||||
},
|
||||
{
|
||||
handle: sakila.MS,
|
||||
defaultCatalog: "sakila",
|
||||
defaultSchema: "dbo",
|
||||
altCatalog: "model",
|
||||
expectSchemaFuncValue: "dbo",
|
||||
},
|
||||
{
|
||||
handle: sakila.My,
|
||||
defaultCatalog: "def",
|
||||
defaultSchema: "sakila",
|
||||
altCatalog: "model",
|
||||
expectSchemaFuncValue: "information_schema",
|
||||
},
|
||||
{
|
||||
handle: sakila.SL3,
|
||||
skipReason: `SQLite 'schema' support requires implementing 'ATTACH DATABASE'.
|
||||
See: https://github.com/neilotoole/sq/issues/324`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.handle, func(t *testing.T) {
|
||||
if tc.skipReason != "" {
|
||||
t.Skip(tc.skipReason)
|
||||
return
|
||||
}
|
||||
th := testh.New(t)
|
||||
src := th.Source(tc.handle)
|
||||
|
||||
tr := testrun.New(th.Context, t, nil).
|
||||
Add(*th.Source(sakila.CSVActor), *src)
|
||||
|
||||
// Confirm that sakila.CSVActor is the active source.
|
||||
require.NoError(t, tr.Exec("src"))
|
||||
require.Equal(t, sakila.CSVActor, tr.OutString())
|
||||
|
||||
// Test combination of --src and --src.schema
|
||||
const qInfoSchemaActor = `.tables | .table_catalog, .table_schema, .table_name, .table_type | where(.table_name == "actor")` //nolint:lll
|
||||
require.NoError(t, tr.Reset().Exec("--csv", "-H",
|
||||
"--src", tc.handle,
|
||||
"--src.schema", "information_schema",
|
||||
qInfoSchemaActor,
|
||||
))
|
||||
|
||||
want := [][]string{{tc.defaultCatalog, tc.defaultSchema, "actor", "BASE TABLE"}}
|
||||
got := tr.BindCSV()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
require.NoError(t, tr.Reset().Exec("src", tc.handle))
|
||||
|
||||
require.NoError(t, tr.Reset().Exec("-H", "schema()"))
|
||||
require.Equal(t, tc.defaultSchema, tr.OutString())
|
||||
|
||||
// Test just --src.schema (schema part only)
|
||||
require.NoError(t, tr.Reset().Exec("--csv", "-H",
|
||||
"--src.schema", "information_schema",
|
||||
qInfoSchemaActor,
|
||||
))
|
||||
got = tr.BindCSV()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
if th.SQLDriverFor(src).Dialect().Catalog {
|
||||
// Test --src.schema (catalog and schema parts)
|
||||
require.NoError(t, tr.Reset().Exec("--csv", "-H",
|
||||
"--src.schema", tc.altCatalog+".information_schema",
|
||||
`.schemata | .catalog_name | unique`,
|
||||
))
|
||||
|
||||
got = tr.BindCSV()
|
||||
require.Equal(t, tc.altCatalog, got[0][0])
|
||||
}
|
||||
|
||||
// Note that for SQL Server, the SLQ "schema()"
|
||||
// func does not honor --src.schema. This is a limitation in
|
||||
// SQL Server itself; it's not possible to change the default
|
||||
// schema for a connection.
|
||||
require.NoError(t, tr.Reset().Exec("-H",
|
||||
"--src.schema", "information_schema",
|
||||
"schema()"))
|
||||
require.Equal(t, tc.expectSchemaFuncValue, tr.OutString())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func execSQL(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
err := determineSources(cmd.Context(), ru)
|
||||
err := determineSources(cmd.Context(), ru, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -124,7 +124,7 @@ func execSQLPrint(ctx context.Context, ru *run.Run, fromSrc *source.Source) erro
|
||||
}
|
||||
|
||||
recw := output.NewRecordWriterAdapter(ctx, ru.Writers.Record)
|
||||
err = libsq.QuerySQL(ctx, dbase, recw, args[0])
|
||||
err = libsq.QuerySQL(ctx, dbase, nil, recw, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -163,7 +163,7 @@ func execSQLInsert(ctx context.Context, ru *run.Run,
|
||||
driver.OptTuningRecChanSize.Get(destSrc.Options),
|
||||
libsq.DBWriterCreateTableIfNotExistsHook(destTbl),
|
||||
)
|
||||
err = libsq.QuerySQL(ctx, fromDB, inserter, args[0])
|
||||
err = libsq.QuerySQL(ctx, fromDB, nil, inserter, args[0])
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "insert to {%s} failed", source.Target(destSrc, destTbl))
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
|
||||
"github.com/neilotoole/sq/cli/flag"
|
||||
@ -47,20 +49,20 @@ func TestCmdSQL_Insert(t *testing.T) {
|
||||
|
||||
// To avoid dirtying the destination table, we make a copy
|
||||
// of it (without data).
|
||||
tblName := th.CopyTable(true, destSrc, sakila.TblActor, "", false)
|
||||
destTbl := th.CopyTable(true, destSrc, tablefq.From(sakila.TblActor), tablefq.T{}, false)
|
||||
|
||||
tr := testrun.New(th.Context, t, nil).Add(*originSrc)
|
||||
if destSrc.Handle != originSrc.Handle {
|
||||
tr.Add(*destSrc)
|
||||
}
|
||||
|
||||
insertTo := fmt.Sprintf("%s.%s", destSrc.Handle, tblName)
|
||||
insertTo := fmt.Sprintf("%s.%s", destSrc.Handle, destTbl)
|
||||
query := fmt.Sprintf("SELECT %s FROM %s", strings.Join(sakila.TblActorCols(), ", "), originTbl)
|
||||
|
||||
err := tr.Exec("sql", "--insert="+insertTo, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
sink, err := th.QuerySQL(destSrc, "select * from "+tblName)
|
||||
sink, err := th.QuerySQL(destSrc, nil, "select * from "+destTbl)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
})
|
||||
@ -190,3 +192,45 @@ func TestCmdSQL_StdinQuery(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagActiveSource_sql(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
tr := testrun.New(ctx, t, nil)
|
||||
|
||||
// @sqlite will be the active source
|
||||
require.NoError(t, tr.Exec("add", proj.Abs(sakila.PathSL3), "--handle", "@sqlite"))
|
||||
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec("add", proj.Abs(sakila.PathCSVActor), "--handle", "@csv"))
|
||||
|
||||
t.Logf("\n\n\n QUERY 1 \n\n\n") // FIXME: delete
|
||||
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec(
|
||||
"sql",
|
||||
"--csv",
|
||||
"--no-header",
|
||||
`select * from actor`,
|
||||
))
|
||||
require.Len(t, tr.BindCSV(), sakila.TblActorCount)
|
||||
|
||||
t.Logf("\n\n\n QUERY 2 \n\n\n") // FIXME: delete
|
||||
|
||||
// Now, use flag.ActiveSrc to switch the source.
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec(
|
||||
"sql",
|
||||
"--csv",
|
||||
"--no-header",
|
||||
"--src", "@csv",
|
||||
"select * from data",
|
||||
))
|
||||
require.Len(t, tr.BindCSV(), sakila.TblActorCount)
|
||||
|
||||
// Double check that we didn't change the persisted active source
|
||||
tr = testrun.New(ctx, t, tr)
|
||||
require.NoError(t, tr.Exec("src", "--json"))
|
||||
require.Equal(t, "@sqlite", tr.BindMap()["handle"])
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/cli/run"
|
||||
|
||||
"github.com/neilotoole/sq/cli/flag"
|
||||
@ -133,7 +135,10 @@ func execTblCopy(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
copied, err := sqlDrvr.CopyTable(ctx, db, tblHandles[0].tbl, tblHandles[1].tbl, copyData)
|
||||
fromTbl := tablefq.New(tblHandles[0].tbl)
|
||||
toTbl := tablefq.New(tblHandles[1].tbl)
|
||||
|
||||
copied, err := sqlDrvr.CopyTable(ctx, db, fromTbl, toTbl, copyData)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "failed tbl copy %s.%s --> %s.%s",
|
||||
tblHandles[0].handle, tblHandles[0].tbl,
|
||||
@ -262,7 +267,8 @@ func execTblDrop(cmd *cobra.Command, args []string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sqlDrvr.DropTable(cmd.Context(), db, tblH.tbl, false); err != nil {
|
||||
targetTbl := tablefq.New(tblH.tbl)
|
||||
if err = sqlDrvr.DropTable(cmd.Context(), db, targetTbl, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ package cli_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -27,7 +29,7 @@ func TestCmdTblCopy(t *testing.T) { //nolint:tparallel
|
||||
tr1 := testrun.New(th.Context, t, nil).Add(*src)
|
||||
err := tr1.Exec("tbl", "copy", "--data=false", srcTblHandle, src.Handle+"."+destTbl1)
|
||||
require.NoError(t, err)
|
||||
defer th.DropTable(src, destTbl1)
|
||||
defer th.DropTable(src, tablefq.From(destTbl1))
|
||||
require.Equal(t, int64(0), th.RowCount(src, destTbl1),
|
||||
"should not have copied any rows because --data=false")
|
||||
|
||||
@ -36,7 +38,7 @@ func TestCmdTblCopy(t *testing.T) { //nolint:tparallel
|
||||
destTbl2 := stringz.UniqTableName(sakila.TblActor)
|
||||
err = tr2.Exec("tbl", "copy", "--data=true", srcTblHandle, src.Handle+"."+destTbl2)
|
||||
require.NoError(t, err)
|
||||
defer th.DropTable(src, destTbl2)
|
||||
defer th.DropTable(src, tablefq.From(destTbl2))
|
||||
require.Equal(t, int64(sakila.TblActorCount), th.RowCount(src, destTbl2),
|
||||
"should have copied rows because --data=true")
|
||||
})
|
||||
@ -52,12 +54,12 @@ func TestCmdTblDrop(t *testing.T) { //nolint:tparallel
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(handle)
|
||||
destTblName := th.CopyTable(false, src, sakila.TblActor, "", true)
|
||||
destTblName := th.CopyTable(false, src, tablefq.From(sakila.TblActor), tablefq.T{}, true)
|
||||
needsDrop := true
|
||||
|
||||
defer func() {
|
||||
if needsDrop {
|
||||
th.DropTable(src, destTblName)
|
||||
th.DropTable(src, tablefq.From(destTblName))
|
||||
}
|
||||
}()
|
||||
|
||||
@ -89,7 +91,7 @@ func TestCmdTblTruncate(t *testing.T) {
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(handle)
|
||||
destTblName := th.CopyTable(true, src, sakila.TblActor, "", true)
|
||||
destTblName := th.CopyTable(true, src, tablefq.From(sakila.TblActor), tablefq.T{}, true)
|
||||
|
||||
tblMeta, err := th.Open(src).TableMetadata(th.Context, destTblName)
|
||||
require.NoError(t, err) // verify that the table exists
|
||||
|
@ -69,6 +69,7 @@ func ExtractDirectives(result cobra.ShellCompDirective) []cobra.ShellCompDirecti
|
||||
cobra.ShellCompDirectiveNoFileComp,
|
||||
cobra.ShellCompDirectiveFilterFileExt,
|
||||
cobra.ShellCompDirectiveFilterDirs,
|
||||
cobra.ShellCompDirectiveKeepOrder,
|
||||
cobra.ShellCompDirectiveDefault,
|
||||
}
|
||||
|
||||
|
225
cli/complete.go
225
cli/complete.go
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/lg/lgm"
|
||||
|
||||
"github.com/neilotoole/sq/cli/run"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/timez"
|
||||
@ -287,6 +289,211 @@ func completeTblCopy(cmd *cobra.Command, args []string, toComplete string) ([]st
|
||||
}
|
||||
}
|
||||
|
||||
// activeSchemaCompleter encapsulates completion for flag.ActiveSchema.
|
||||
// The completionFunc is activeSchemaCompleter.complete.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// # Only schema
|
||||
// $ sq --src.schema information_schema '.tables'
|
||||
//
|
||||
// # Using catalog.schema
|
||||
// $ sq --src.schema postgres.information_schema '.tables'
|
||||
//
|
||||
// Note that some drivers don't support the catalog mechanism (e.g. SQLite).
|
||||
//
|
||||
// The returned slice contains the names of the schemas in the source, followed
|
||||
// by the names of the catalogs (suffixed with a period, e.g. "sakila.", so
|
||||
// that the user can complete the catalog.schema input, e.g. "sakila.public").
|
||||
// For example:
|
||||
//
|
||||
// information_schema <-- this a schema in the active source
|
||||
// pg_catalog
|
||||
// public
|
||||
// sakila. <-- note the trailing period, this is a catalog
|
||||
// customers.
|
||||
// postgres.
|
||||
//
|
||||
// If toComplete already contains a period (e.g. "sakila."), then the
|
||||
// returned slice contains only the matching catalog-qualified schemas,
|
||||
// e.g. "sakila.public", "sakila.information_schema", etc.
|
||||
//
|
||||
// Note the field activeSchemaCompleter.activeSourceFunc. This func is used to
|
||||
// determine the source to act against. This is configurable because some commands
|
||||
// may honor a flag (flag.ActiveSrc), but a different flag (or even cmd args)
|
||||
// could also be used. Func getActiveSourceViaFlag is one such func impl. When
|
||||
// that is used, if the command has flag.ActiveSrc set, it is honored. Otherwise,
|
||||
// the config's active source is used. For example:
|
||||
//
|
||||
// $ sq --src @sakila/pg12 --src.schema postgres.information_schema '.tables'
|
||||
//
|
||||
// Note also: if the targeted source is not SQL (e.g. CSV), an error is returned.
|
||||
type activeSchemaCompleter struct {
|
||||
// activeSourceFunc is a function that returns the active source.
|
||||
// Typically the active source comes from the config, but it can also
|
||||
// be supplied via other means, e.g. flag.ActiveSrc or a command arg.
|
||||
activeSourceFunc func(cmd *cobra.Command, args []string) (*source.Source, error)
|
||||
}
|
||||
|
||||
func (c activeSchemaCompleter) complete(cmd *cobra.Command, args []string, toComplete string,
|
||||
) ([]string, cobra.ShellCompDirective) {
|
||||
const baseDirective = cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder
|
||||
|
||||
log, ru := logFrom(cmd), getRun(cmd)
|
||||
if err := preRun(cmd, ru); err != nil {
|
||||
lg.Unexpected(log, err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
src, err := c.activeSourceFunc(cmd, args)
|
||||
if err != nil {
|
||||
lg.Unexpected(log, err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if src == nil {
|
||||
log.Debug("No active source, thus no completion for flag", lga.Flag, flag.ActiveSrc)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
// If toComplete contains a period, then we extract the part before
|
||||
// the period into inputCatalog.
|
||||
var inputCatalog string
|
||||
if toComplete != "" {
|
||||
if strings.ContainsRune(toComplete, '.') {
|
||||
// User has supplied a catalog.schema (or at least a "catalog.")
|
||||
parts := strings.Split(toComplete, ".")
|
||||
if len(parts) > 2 {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
inputCatalog = parts[0]
|
||||
if inputCatalog == "" {
|
||||
// User supplied input of the form ".schema" (leading period),
|
||||
// which is invalid.
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
src.Catalog = inputCatalog
|
||||
}
|
||||
}
|
||||
|
||||
if ok, _ := isSQLDriver(ru, src.Handle); !ok {
|
||||
// Not a SQL driver, completion is N/A.
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
drvr, err := ru.DriverRegistry.SQLDriverFor(src.Type)
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
// We don't want the user to wait around forever for
|
||||
// shell completion, so we set a timeout. Typically
|
||||
// this is something like 500ms.
|
||||
ctx, cancelFn := context.WithTimeout(cmd.Context(), OptShellCompletionTimeout.Get(ru.Config.Options))
|
||||
defer cancelFn()
|
||||
|
||||
dbase, err := ru.Databases.Open(ctx, src)
|
||||
if err != nil {
|
||||
lg.Unexpected(log, err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
db, err := dbase.DB(ctx)
|
||||
if err != nil {
|
||||
lg.Unexpected(log, err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
defer lg.WarnIfCloseError(log, lgm.CloseDB, db)
|
||||
|
||||
a, err := drvr.ListSchemas(ctx, db)
|
||||
if err != nil {
|
||||
lg.Unexpected(log, err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if len(a) == 0 {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if inputCatalog != "" {
|
||||
// We have a catalog, so we need to prepend it to each
|
||||
// schema name.
|
||||
for i := range a {
|
||||
a[i] = inputCatalog + "." + a[i]
|
||||
}
|
||||
|
||||
a = lo.Filter(a, func(item string, index int) bool {
|
||||
return strings.HasPrefix(item, toComplete)
|
||||
})
|
||||
|
||||
return a, baseDirective
|
||||
}
|
||||
|
||||
if drvr.Dialect().Catalog {
|
||||
var catalogs []string
|
||||
if catalogs, err = drvr.ListCatalogs(ctx, db); err != nil {
|
||||
// We continue even if an error occurs.
|
||||
log.Warn("List catalogs", lga.Err, err)
|
||||
}
|
||||
|
||||
for i := range catalogs {
|
||||
a = append(a, catalogs[i]+".")
|
||||
}
|
||||
}
|
||||
|
||||
a = lo.Filter(a, func(item string, index int) bool {
|
||||
return strings.HasPrefix(item, toComplete)
|
||||
})
|
||||
|
||||
for i := range a {
|
||||
// If any of the completions has a trailing period (i.e. they've
|
||||
// only typed the catalog name), then we need cobra.ShellCompDirectiveNoSpace,
|
||||
// because the user has more typing to do to complete the catalog.schema.
|
||||
if strings.HasSuffix(a[i], ".") {
|
||||
return a, baseDirective | cobra.ShellCompDirectiveNoSpace
|
||||
}
|
||||
}
|
||||
|
||||
return a, baseDirective
|
||||
}
|
||||
|
||||
// getActiveSourceViaFlag returns the active source, either from the
|
||||
// config or from flag.ActiveSrc. This function is intended for use
|
||||
// with activeSchemaCompleter.activeSourceFunc.
|
||||
func getActiveSourceViaFlag(cmd *cobra.Command, _ []string) (*source.Source, error) {
|
||||
if !cmdFlagChanged(cmd, flag.ActiveSrc) {
|
||||
// User has not supplied --src, so we'll use the
|
||||
// config's active source.
|
||||
return getRun(cmd).Config.Collection.Active(), nil
|
||||
}
|
||||
|
||||
handle, err := cmd.Flags().GetString(flag.ActiveSrc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var src *source.Source
|
||||
if src, err = getRun(cmd).Config.Collection.Get(handle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return src, nil
|
||||
}
|
||||
|
||||
// getActiveSourceViaArgs returns the active source, either from the
|
||||
// config or from the handle in the first cmd arg. This function is intended
|
||||
// for use with activeSchemaCompleter.activeSourceFunc.
|
||||
func getActiveSourceViaArgs(cmd *cobra.Command, args []string) (*source.Source, error) {
|
||||
if len(args) == 0 {
|
||||
// No args supplied, so we'll use the config's active source.
|
||||
return getRun(cmd).Config.Collection.Active(), nil
|
||||
}
|
||||
|
||||
handle := args[0]
|
||||
return getRun(cmd).Config.Collection.Get(handle)
|
||||
}
|
||||
|
||||
// handleTableCompleter encapsulates completion of a handle
|
||||
// ("@sakila_sl3"), table (".actor"), or @HANDLE.TABLE
|
||||
// ("@sakila_sl3.actor"). Its complete method is a completionFunc.
|
||||
@ -362,7 +569,7 @@ func (c *handleTableCompleter) completeTableOnly(ctx context.Context, ru *run.Ru
|
||||
}
|
||||
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(ru, activeSrc.Handle)
|
||||
isSQL, err := isSQLDriver(ru, activeSrc.Handle)
|
||||
if err != nil {
|
||||
lg.Unexpected(lg.FromContext(ctx), err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
@ -413,7 +620,7 @@ func (c *handleTableCompleter) completeHandle(ctx context.Context, ru *run.Run,
|
||||
|
||||
if c.onlySQL {
|
||||
var isSQL bool
|
||||
isSQL, err = handleIsSQLDriver(ru, handle)
|
||||
isSQL, err = isSQLDriver(ru, handle)
|
||||
if err != nil {
|
||||
lg.Unexpected(lg.FromContext(ctx), err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
@ -447,7 +654,7 @@ func (c *handleTableCompleter) completeHandle(ctx context.Context, ru *run.Run,
|
||||
for _, handle := range handles {
|
||||
if strings.HasPrefix(handle, toComplete) {
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(ru, handle)
|
||||
isSQL, err := isSQLDriver(ru, handle)
|
||||
if err != nil {
|
||||
lg.Unexpected(lg.FromContext(ctx), err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
@ -501,7 +708,7 @@ func (c *handleTableCompleter) completeEither(ctx context.Context, ru *run.Run,
|
||||
activeSrc := ru.Config.Collection.Active()
|
||||
if activeSrc != nil {
|
||||
var activeSrcTables []string
|
||||
isSQL, err := handleIsSQLDriver(ru, activeSrc.Handle)
|
||||
isSQL, err := isSQLDriver(ru, activeSrc.Handle)
|
||||
if err != nil {
|
||||
lg.Unexpected(lg.FromContext(ctx), err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
@ -525,7 +732,7 @@ func (c *handleTableCompleter) completeEither(ctx context.Context, ru *run.Run,
|
||||
|
||||
for _, src := range ru.Config.Collection.Sources() {
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(ru, src.Handle)
|
||||
isSQL, err := isSQLDriver(ru, src.Handle)
|
||||
if err != nil {
|
||||
lg.Unexpected(lg.FromContext(ctx), err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
@ -541,7 +748,7 @@ func (c *handleTableCompleter) completeEither(ctx context.Context, ru *run.Run,
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
|
||||
}
|
||||
|
||||
func handleIsSQLDriver(ru *run.Run, handle string) (bool, error) {
|
||||
func isSQLDriver(ru *run.Run, handle string) (bool, error) {
|
||||
src, err := ru.Config.Collection.Get(handle)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -561,12 +768,14 @@ func getTableNamesForHandle(ctx context.Context, ru *run.Run, handle string) ([]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := ru.Databases.Open(ctx, src)
|
||||
dbase, err := ru.Databases.Open(ctx, src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
md, err := db.SourceMetadata(ctx, false)
|
||||
// TODO: We shouldn't have to load the full metadata just to get
|
||||
// the table names. driver.SQLDriver should have a method ListTables.
|
||||
md, err := dbase.SourceMetadata(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ import (
|
||||
// returned by completeAddLocation.
|
||||
const locCompStdDirective = cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveKeepOrder
|
||||
|
||||
const localhost = "localhost"
|
||||
|
||||
// completeAddLocation provides completion for the "sq add LOCATION" arg.
|
||||
// This is a messy task, as LOCATION can be a database driver URL,
|
||||
// and it can also be a filepath. To complicate matters further, sqlite
|
||||
@ -216,12 +218,12 @@ func locCompDoGenericDriver(cmd *cobra.Command, _ []string, toComplete string, /
|
||||
if ploc.hostname == "" {
|
||||
if defaultPort == "" {
|
||||
a = []string{
|
||||
toComplete + "localhost" + afterHost,
|
||||
toComplete + localhost + afterHost,
|
||||
}
|
||||
} else {
|
||||
a = []string{
|
||||
toComplete + "localhost" + afterHost,
|
||||
toComplete + "localhost:" + defaultPort + afterHost,
|
||||
toComplete + localhost + afterHost,
|
||||
toComplete + localhost + ":" + defaultPort + afterHost,
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,14 +252,14 @@ func locCompDoGenericDriver(cmd *cobra.Command, _ []string, toComplete string, /
|
||||
if defaultPort == "" {
|
||||
a = []string{
|
||||
toComplete + afterHost,
|
||||
base + "localhost" + afterHost,
|
||||
base + localhost + afterHost,
|
||||
}
|
||||
} else {
|
||||
a = []string{
|
||||
toComplete + afterHost,
|
||||
toComplete + ":" + defaultPort + afterHost,
|
||||
base + "localhost" + afterHost,
|
||||
base + "localhost:" + defaultPort + afterHost,
|
||||
base + localhost + afterHost,
|
||||
base + localhost + ":" + defaultPort + afterHost,
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,13 +283,13 @@ func locCompDoGenericDriver(cmd *cobra.Command, _ []string, toComplete string, /
|
||||
|
||||
if defaultPort == "" {
|
||||
a = []string{
|
||||
base + "localhost" + afterHost,
|
||||
base + localhost + afterHost,
|
||||
toComplete + afterHost,
|
||||
}
|
||||
} else {
|
||||
a = []string{
|
||||
base + "localhost" + afterHost,
|
||||
base + "localhost:" + defaultPort + afterHost,
|
||||
base + localhost + afterHost,
|
||||
base + localhost + ":" + defaultPort + afterHost,
|
||||
toComplete + afterHost,
|
||||
}
|
||||
}
|
||||
|
@ -3,38 +3,24 @@ package cli_test
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/sqlite3"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/sqlserver"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/postgres"
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/stringz"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/neilotoole/sq/testh"
|
||||
|
||||
"github.com/neilotoole/sq/cli"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/neilotoole/sq/cli/cobraz"
|
||||
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/cli"
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
"github.com/neilotoole/sq/drivers/postgres"
|
||||
"github.com/neilotoole/sq/drivers/sqlite3"
|
||||
"github.com/neilotoole/sq/drivers/sqlserver"
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
"github.com/neilotoole/sq/libsq/core/stringz"
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
"github.com/neilotoole/sq/testh"
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var locSchemes = []string{
|
||||
@ -803,55 +789,6 @@ func TestCompleteAddLocation_SQLite3(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testComplete(t testing.TB, from *testrun.TestRun, args ...string) completion {
|
||||
ctx := lg.NewContext(context.Background(), slogt.New(t))
|
||||
|
||||
tr := testrun.New(ctx, t, from)
|
||||
args = append([]string{"__complete"}, args...)
|
||||
|
||||
err := tr.Exec(args...)
|
||||
require.NoError(t, err)
|
||||
|
||||
c := parseCompletion(tr)
|
||||
return c
|
||||
}
|
||||
|
||||
// parseCompletion parses the output of cobra "__complete".
|
||||
// Example output:
|
||||
//
|
||||
// @active
|
||||
// @sakila
|
||||
// :4
|
||||
// Completion ended with directive: ShellCompDirectiveNoFileComp
|
||||
//
|
||||
// The tr.T test will fail on any error.
|
||||
func parseCompletion(tr *testrun.TestRun) completion {
|
||||
c := completion{
|
||||
stdout: tr.Out.String(),
|
||||
stderr: tr.ErrOut.String(),
|
||||
}
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(c.stdout), "\n")
|
||||
require.True(tr.T, len(lines) >= 1)
|
||||
c.values = lines[:len(lines)-1]
|
||||
|
||||
result, err := strconv.Atoi(lines[len(lines)-1][1:])
|
||||
require.NoError(tr.T, err)
|
||||
c.result = cobra.ShellCompDirective(result)
|
||||
|
||||
c.directives = cobraz.ParseDirectivesLine(c.stderr)
|
||||
return c
|
||||
}
|
||||
|
||||
// completion models the result returned from the cobra "__complete" command.
|
||||
type completion struct {
|
||||
stdout string
|
||||
stderr string
|
||||
values []string
|
||||
result cobra.ShellCompDirective
|
||||
directives []cobra.ShellCompDirective
|
||||
}
|
||||
|
||||
func TestCompleteAddLocation_History_Postgres(t *testing.T) {
|
||||
tutil.SkipWindows(t, "Shell completion not fully implemented for windows")
|
||||
wd := tutil.Chdir(t, filepath.Join("testdata", "add_location"))
|
||||
|
297
cli/complete_test.go
Normal file
297
cli/complete_test.go
Normal file
@ -0,0 +1,297 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/slogt"
|
||||
"github.com/neilotoole/sq/cli/cobraz"
|
||||
"github.com/neilotoole/sq/cli/flag"
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
"github.com/neilotoole/sq/testh/sakila"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/testh"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
|
||||
"github.com/neilotoole/sq/cli/testrun"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// testComplete is a helper for testing cobra completion.
|
||||
func testComplete(t testing.TB, from *testrun.TestRun, args ...string) completion {
|
||||
ctx := lg.NewContext(context.Background(), slogt.New(t))
|
||||
|
||||
tr := testrun.New(ctx, t, from)
|
||||
args = append([]string{"__complete"}, args...)
|
||||
|
||||
err := tr.Exec(args...)
|
||||
require.NoError(t, err)
|
||||
|
||||
c := parseCompletion(tr)
|
||||
return c
|
||||
}
|
||||
|
||||
// parseCompletion parses the output of cobra "__complete".
|
||||
// Example output:
|
||||
//
|
||||
// @active
|
||||
// @sakila
|
||||
// :4
|
||||
// Completion ended with directive: ShellCompDirectiveNoFileComp
|
||||
//
|
||||
// The tr.T test will fail on any error.
|
||||
func parseCompletion(tr *testrun.TestRun) completion {
|
||||
c := completion{
|
||||
stdout: tr.Out.String(),
|
||||
stderr: tr.ErrOut.String(),
|
||||
}
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(c.stdout), "\n")
|
||||
require.True(tr.T, len(lines) >= 1)
|
||||
c.values = lines[:len(lines)-1]
|
||||
|
||||
result, err := strconv.Atoi(lines[len(lines)-1][1:])
|
||||
require.NoError(tr.T, err)
|
||||
c.result = cobra.ShellCompDirective(result)
|
||||
|
||||
c.directives = cobraz.ParseDirectivesLine(c.stderr)
|
||||
return c
|
||||
}
|
||||
|
||||
// completion models the result returned from the cobra "__complete" command.
|
||||
type completion struct {
|
||||
stdout string
|
||||
stderr string
|
||||
values []string
|
||||
result cobra.ShellCompDirective
|
||||
directives []cobra.ShellCompDirective
|
||||
}
|
||||
|
||||
// TestCompleteFlagActiveSchema_query_cmds tests flag.ActiveSchema
|
||||
// behavior for the query commands (slq, sql).
|
||||
//
|
||||
// See also: TestCompleteFlagActiveSchema_inspect.
|
||||
func TestCompleteFlagActiveSchema_query_cmds(t *testing.T) {
|
||||
t.Parallel()
|
||||
const wantDirective = cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder
|
||||
|
||||
testCases := []struct {
|
||||
handles []string
|
||||
arg string
|
||||
withFlagActiveSrc string
|
||||
wantContains []string
|
||||
wantDirective cobra.ShellCompDirective
|
||||
}{
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "saki",
|
||||
wantContains: []string{"sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "",
|
||||
wantContains: []string{"public", "sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "sakila",
|
||||
wantContains: []string{"sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "sakila.pub",
|
||||
wantContains: []string{"sakila.public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "pub",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "public",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.My, sakila.Pg},
|
||||
withFlagActiveSrc: sakila.Pg,
|
||||
arg: "publ",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg, sakila.My},
|
||||
withFlagActiveSrc: sakila.My,
|
||||
arg: "",
|
||||
wantContains: []string{"mysql", "sys", "information_schema", "sakila"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.My, sakila.Pg},
|
||||
withFlagActiveSrc: sakila.MS,
|
||||
arg: "publ",
|
||||
// Should error because sakila.MS isn't a loaded source (via "handles").
|
||||
wantDirective: cobra.ShellCompDirectiveError,
|
||||
},
|
||||
}
|
||||
|
||||
for _, cmdName := range []string{"slq", "sql"} {
|
||||
cmdName := cmdName
|
||||
t.Run(cmdName, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tutil.Name(i, tc.handles, tc.withFlagActiveSrc, tc.arg), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
th := testh.New(t)
|
||||
tr := testrun.New(th.Context, t, nil)
|
||||
for _, handle := range tc.handles {
|
||||
tr.Add(*th.Source(handle))
|
||||
}
|
||||
|
||||
args := []string{cmdName}
|
||||
if tc.withFlagActiveSrc != "" {
|
||||
args = append(args, "--"+flag.ActiveSrc, tc.withFlagActiveSrc)
|
||||
}
|
||||
args = append(args, "--"+flag.ActiveSchema, tc.arg)
|
||||
|
||||
got := testComplete(t, tr, args...)
|
||||
assert.Equal(t, tc.wantDirective, got.result,
|
||||
"wanted: %v\ngot : %v",
|
||||
cobraz.MarshalDirective(tc.wantDirective),
|
||||
cobraz.MarshalDirective(got.result))
|
||||
|
||||
if tc.wantDirective == cobra.ShellCompDirectiveError {
|
||||
require.Empty(t, got.values)
|
||||
} else {
|
||||
for j := range tc.wantContains {
|
||||
assert.Contains(t, got.values, tc.wantContains[j])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompleteFlagActiveSchema_inspect tests flag.ActiveSchema
|
||||
// behavior for the inspect command.
|
||||
//
|
||||
// See also: TestCompleteFlagActiveSchema_query_cmds.
|
||||
func TestCompleteFlagActiveSchema_inspect(t *testing.T) {
|
||||
t.Parallel()
|
||||
const wantDirective = cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder
|
||||
|
||||
testCases := []struct {
|
||||
handles []string
|
||||
arg string
|
||||
withArgActiveSrc string
|
||||
wantContains []string
|
||||
wantDirective cobra.ShellCompDirective
|
||||
}{
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "saki",
|
||||
wantContains: []string{"sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "",
|
||||
wantContains: []string{"public", "sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "sakila",
|
||||
wantContains: []string{"sakila."},
|
||||
wantDirective: wantDirective | cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "sakila.pub",
|
||||
wantContains: []string{"sakila.public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "pub",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg},
|
||||
arg: "public",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.My, sakila.Pg},
|
||||
withArgActiveSrc: sakila.Pg,
|
||||
arg: "publ",
|
||||
wantContains: []string{"public"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.Pg, sakila.My},
|
||||
withArgActiveSrc: sakila.My,
|
||||
arg: "",
|
||||
wantContains: []string{"mysql", "sys", "information_schema", "sakila"},
|
||||
wantDirective: wantDirective,
|
||||
},
|
||||
{
|
||||
handles: []string{sakila.My, sakila.Pg},
|
||||
withArgActiveSrc: sakila.MS,
|
||||
arg: "publ",
|
||||
// Should error because sakila.MS isn't a loaded source (via "handles").
|
||||
wantDirective: cobra.ShellCompDirectiveError,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tutil.Name(i, tc.handles, tc.withArgActiveSrc, tc.arg), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
th := testh.New(t)
|
||||
tr := testrun.New(th.Context, t, nil)
|
||||
for _, handle := range tc.handles {
|
||||
tr.Add(*th.Source(handle))
|
||||
}
|
||||
|
||||
args := []string{"inspect"}
|
||||
if tc.withArgActiveSrc != "" {
|
||||
args = append(args, tc.withArgActiveSrc)
|
||||
}
|
||||
args = append(args, "--"+flag.ActiveSchema, tc.arg)
|
||||
|
||||
got := testComplete(t, tr, args...)
|
||||
assert.Equal(t, tc.wantDirective, got.result,
|
||||
"wanted: %v\ngot : %v",
|
||||
cobraz.MarshalDirective(tc.wantDirective),
|
||||
cobraz.MarshalDirective(got.result))
|
||||
|
||||
if tc.wantDirective == cobra.ShellCompDirectiveError {
|
||||
require.Empty(t, got.values)
|
||||
} else {
|
||||
for j := range tc.wantContains {
|
||||
assert.Contains(t, got.values, tc.wantContains[j])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -109,8 +109,7 @@ func (fs *Store) doLoad(ctx context.Context) (*config.Config, error) {
|
||||
}
|
||||
|
||||
cfg := config.New()
|
||||
err = ioz.UnmarshallYAML(bytes, cfg)
|
||||
if err != nil {
|
||||
if err = ioz.UnmarshallYAML(bytes, cfg); err != nil {
|
||||
return nil, errz.Wrapf(err, "config: %s: failed to unmarshal config YAML", fs.Path)
|
||||
}
|
||||
|
||||
@ -122,8 +121,7 @@ func (fs *Store) doLoad(ctx context.Context) (*config.Config, error) {
|
||||
cfg.Options = options.Options{}
|
||||
}
|
||||
|
||||
cfg.Options, err = fs.OptionsRegistry.Process(cfg.Options)
|
||||
if err != nil {
|
||||
if cfg.Options, err = fs.OptionsRegistry.Process(cfg.Options); err != nil {
|
||||
return nil, errz.Wrapf(err, "config: %s", fs.Path)
|
||||
}
|
||||
|
||||
@ -140,8 +138,7 @@ func (fs *Store) doLoad(ctx context.Context) (*config.Config, error) {
|
||||
return nil, errz.Wrapf(err, "config: %s", fs.Path)
|
||||
}
|
||||
|
||||
err = fs.loadExt(cfg)
|
||||
if err != nil {
|
||||
if err = fs.loadExt(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,10 @@ package flag
|
||||
|
||||
const (
|
||||
ActiveSrc = "src"
|
||||
ActiveSrcUsage = "Override the active source for this query"
|
||||
ActiveSrcUsage = "Override active source for this query"
|
||||
|
||||
ActiveSchema = "src.schema"
|
||||
ActiveSchemaUsage = "Override active schema or catalog.schema for this query"
|
||||
|
||||
ConfigSrc = "src"
|
||||
ConfigSrcUsage = "Config for source"
|
||||
@ -14,10 +17,10 @@ const (
|
||||
|
||||
AddDriver = "driver"
|
||||
AddDriverShort = "d"
|
||||
AddDriverUsage = "Explicitly specify the driver to use"
|
||||
AddDriverUsage = "Explicitly specify driver to use"
|
||||
|
||||
IngestDriver = "ingest.driver"
|
||||
IngestDriverUsage = "Explicitly specify the driver to use for ingesting data"
|
||||
IngestDriverUsage = "Explicitly specify driver to use for ingesting data"
|
||||
|
||||
HTML = "html"
|
||||
HTMLUsage = "Output HTML table"
|
||||
@ -41,7 +44,7 @@ const (
|
||||
Help = "help"
|
||||
|
||||
Insert = "insert"
|
||||
InsertUsage = "Insert query results into @HANDLE.TABLE. If not existing, TABLE will be created."
|
||||
InsertUsage = "Insert query results into @HANDLE.TABLE; if not existing, TABLE will be created"
|
||||
|
||||
JSON = "json"
|
||||
JSONShort = "j"
|
||||
|
@ -52,8 +52,8 @@ func cmdFlagBool(cmd *cobra.Command, name string) bool { //nolint:unused
|
||||
}
|
||||
|
||||
// getBootstrapFlagValue parses osArgs looking for flg. The flag is always
|
||||
// treated as string. This function exists because some components such
|
||||
// as logging and config interrogate flags before cobra has loaded.
|
||||
// treated as string. This function exists because some components, such
|
||||
// as logging and config, interrogate flags before cobra has loaded.
|
||||
func getBootstrapFlagValue(flg, flgShort, flgUsage string, osArgs []string) (val string, ok bool, err error) {
|
||||
fs := pflag.NewFlagSet("bootstrap", pflag.ContinueOnError)
|
||||
fs.ParseErrorsWhitelist.UnknownFlags = true
|
||||
|
@ -55,7 +55,7 @@ func TestRecordWriterAdapter(t *testing.T) {
|
||||
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err := libsq.QuerySQL(th.Context, dbase, recw, tc.sqlQuery)
|
||||
err := libsq.QuerySQL(th.Context, dbase, nil, recw, tc.sqlQuery)
|
||||
require.NoError(t, err)
|
||||
written, err := recw.Wait()
|
||||
require.NoError(t, err)
|
||||
|
@ -67,6 +67,11 @@ func (w *sourceWriter) Collection(coll *source.Collection) error {
|
||||
return writeJSON(w.out, w.pr, coll.Data())
|
||||
}
|
||||
|
||||
// Added implements output.SourceWriter.
|
||||
func (w *sourceWriter) Added(coll *source.Collection, src *source.Source) error {
|
||||
return w.Source(coll, src)
|
||||
}
|
||||
|
||||
// Source implements output.SourceWriter.
|
||||
func (w *sourceWriter) Source(_ *source.Collection, src *source.Source) error {
|
||||
if src == nil {
|
||||
@ -78,6 +83,11 @@ func (w *sourceWriter) Source(_ *source.Collection, src *source.Source) error {
|
||||
return writeJSON(w.out, w.pr, src)
|
||||
}
|
||||
|
||||
// Moved implements output.SourceWriter.
|
||||
func (w *sourceWriter) Moved(coll *source.Collection, _, nu *source.Source) error {
|
||||
return w.Source(coll, nu)
|
||||
}
|
||||
|
||||
// Removed implements output.SourceWriter.
|
||||
func (w *sourceWriter) Removed(srcs ...*source.Source) error {
|
||||
if !w.pr.Verbose || len(srcs) == 0 {
|
||||
|
@ -55,7 +55,7 @@ func TestRecordWriter_TblBytes(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
th.Log = lg.Discard()
|
||||
src := th.Source(testsrc.MiscDB)
|
||||
sink, err := th.QuerySQL(src, "SELECT col_bytes FROM tbl_bytes WHERE col_name='gopher.gif'")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT col_bytes FROM tbl_bytes WHERE col_name='gopher.gif'")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
|
||||
|
@ -87,12 +87,41 @@ func (w *sourceWriter) Collection(coll *source.Collection) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Added implements output.SourceWriter.
|
||||
func (w *sourceWriter) Added(coll *source.Collection, src *source.Source) error {
|
||||
return w.doSource(coll, src)
|
||||
}
|
||||
|
||||
// Moved implements output.SourceWriter.
|
||||
func (w *sourceWriter) Moved(coll *source.Collection, _, nu *source.Source) error {
|
||||
return w.doSource(coll, nu)
|
||||
}
|
||||
|
||||
// Source implements output.SourceWriter.
|
||||
func (w *sourceWriter) Source(coll *source.Collection, src *source.Source) error {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if w.tbl.pr.Verbose {
|
||||
return w.doSource(coll, src)
|
||||
}
|
||||
|
||||
if coll != nil && coll.Active() == src {
|
||||
// src is the active source
|
||||
w.tbl.pr.Active.Fprintln(w.tbl.out, src.Handle)
|
||||
} else {
|
||||
w.tbl.pr.Handle.Fprintln(w.tbl.out, src.Handle)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *sourceWriter) doSource(coll *source.Collection, src *source.Source) error {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var isActiveSrc bool
|
||||
if coll != nil && coll.Active() == src {
|
||||
isActiveSrc = true
|
||||
|
@ -71,9 +71,15 @@ type SourceWriter interface {
|
||||
// Source outputs details of the source.
|
||||
Source(coll *source.Collection, src *source.Source) error
|
||||
|
||||
// Added is called when src is added to the collection.
|
||||
Added(coll *source.Collection, src *source.Source) error
|
||||
|
||||
// Removed is called when sources are removed from the collection.
|
||||
Removed(srcs ...*source.Source) error
|
||||
|
||||
// Moved is called when a source is moved from old to nu.
|
||||
Moved(coll *source.Collection, old, nu *source.Source) error
|
||||
|
||||
// Group prints the group.
|
||||
Group(group *source.Group) error
|
||||
|
||||
|
@ -81,6 +81,16 @@ func (w *sourceWriter) Source(_ *source.Collection, src *source.Source) error {
|
||||
return writeYAML(w.out, w.p, src)
|
||||
}
|
||||
|
||||
// Added implements output.SourceWriter.
|
||||
func (w *sourceWriter) Added(coll *source.Collection, src *source.Source) error {
|
||||
return w.Source(coll, src)
|
||||
}
|
||||
|
||||
// Moved implements output.SourceWriter.
|
||||
func (w *sourceWriter) Moved(coll *source.Collection, _, nu *source.Source) error {
|
||||
return w.Source(coll, nu)
|
||||
}
|
||||
|
||||
// Removed implements output.SourceWriter.
|
||||
func (w *sourceWriter) Removed(srcs ...*source.Source) error {
|
||||
if !w.pr.Verbose || len(srcs) == 0 {
|
||||
|
@ -2,6 +2,11 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
|
||||
"github.com/neilotoole/sq/cli/run"
|
||||
|
||||
@ -12,18 +17,15 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/core/options"
|
||||
"github.com/neilotoole/sq/libsq/driver"
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// determineSources figures out what the active source is
|
||||
// from any combination of stdin, flags or cfg. It will
|
||||
// mutate ru.Config.Collection as necessary. If no error
|
||||
// is returned, it is guaranteed that there's an active
|
||||
// source on the collection.
|
||||
func determineSources(ctx context.Context, ru *run.Run) error {
|
||||
// mutate ru.Config.Collection as necessary. If requireActive
|
||||
// is true, an error is returned if there's no active source.
|
||||
func determineSources(ctx context.Context, ru *run.Run, requireActive bool) error {
|
||||
cmd, coll := ru.Cmd, ru.Config.Collection
|
||||
activeSrc, err := activeSrcFromFlagsOrConfig(cmd, coll)
|
||||
activeSrc, err := activeSrcAndSchemaFromFlagsOrConfig(ru)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -59,20 +61,24 @@ func determineSources(ctx context.Context, ru *run.Run) error {
|
||||
}
|
||||
}
|
||||
|
||||
if activeSrc == nil {
|
||||
if activeSrc == nil && requireActive {
|
||||
return errz.New(msgNoActiveSrc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// activeSrcFromFlagsOrConfig gets the active source, either
|
||||
// activeSrcAndSchemaFromFlagsOrConfig gets the active source, either
|
||||
// from flagActiveSrc or from srcs.Active. An error is returned
|
||||
// if the flag src is not found: if the flag src is found,
|
||||
// it is set as the active src on coll. If the flag was not
|
||||
// set and there is no active src in coll, (nil, nil) is
|
||||
// returned.
|
||||
func activeSrcFromFlagsOrConfig(cmd *cobra.Command, coll *source.Collection) (*source.Source, error) {
|
||||
//
|
||||
// This source also checks flag.ActiveSchema, and changes the schema
|
||||
// of the source if the flag is set.
|
||||
func activeSrcAndSchemaFromFlagsOrConfig(ru *run.Run) (*source.Source, error) {
|
||||
cmd, coll := ru.Cmd, ru.Config.Collection
|
||||
var activeSrc *source.Source
|
||||
|
||||
if cmdFlagChanged(cmd, flag.ActiveSrc) {
|
||||
@ -92,9 +98,60 @@ func activeSrcFromFlagsOrConfig(cmd *cobra.Command, coll *source.Collection) (*s
|
||||
} else {
|
||||
activeSrc = coll.Active()
|
||||
}
|
||||
|
||||
if err := processFlagActiveSchema(cmd, activeSrc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return activeSrc, nil
|
||||
}
|
||||
|
||||
// processFlagActiveSchema processes the --src.schema flag, setting
|
||||
// appropriate Source.Catalog and Source.Schema values on activeSrc.
|
||||
// If flag.ActiveSchema is not set, this is no-op. If activeSrc is nil,
|
||||
// an error is returned.
|
||||
func processFlagActiveSchema(cmd *cobra.Command, activeSrc *source.Source) error {
|
||||
ru := run.FromContext(cmd.Context())
|
||||
if !cmdFlagChanged(cmd, flag.ActiveSchema) {
|
||||
// Nothing to do here
|
||||
return nil
|
||||
}
|
||||
if activeSrc == nil {
|
||||
return errz.Errorf("active catalog/schema specified via --%s, but active source is nil",
|
||||
flag.ActiveSchema)
|
||||
}
|
||||
|
||||
val, _ := cmd.Flags().GetString(flag.ActiveSchema)
|
||||
if val = strings.TrimSpace(val); val == "" {
|
||||
return errz.Errorf("active catalog/schema specified via --%s, but schema is empty",
|
||||
flag.ActiveSchema)
|
||||
}
|
||||
|
||||
catalog, schema, err := ast.ParseCatalogSchema(val)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "invalid active schema specified via --%s",
|
||||
flag.ActiveSchema)
|
||||
}
|
||||
|
||||
drvr, err := ru.DriverRegistry.SQLDriverFor(activeSrc.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if catalog != "" {
|
||||
if !drvr.Dialect().Catalog {
|
||||
return errz.Errorf("driver {%s} does not support catalog", activeSrc.Type)
|
||||
}
|
||||
activeSrc.Catalog = catalog
|
||||
}
|
||||
|
||||
if schema != "" {
|
||||
activeSrc.Schema = schema
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkStdinSource checks if there's stdin data (on pipe/redirect).
|
||||
// If there is, that pipe is inspected, and if it has recognizable
|
||||
// input, a new source instance with handle @stdin is constructed
|
||||
|
@ -32,11 +32,15 @@ import (
|
||||
type TestRun struct {
|
||||
T testing.TB
|
||||
Context context.Context
|
||||
mu sync.Mutex
|
||||
mu *sync.Mutex
|
||||
Run *run.Run
|
||||
Out *bytes.Buffer
|
||||
ErrOut *bytes.Buffer
|
||||
used bool
|
||||
|
||||
// Out contains the output written to stdout after TestRun.Exec is invoked.
|
||||
Out *bytes.Buffer
|
||||
|
||||
// ErrOut contains the output written to stderr after TestRun.Exec is invoked.
|
||||
ErrOut *bytes.Buffer
|
||||
used bool
|
||||
|
||||
// When true, out and errOut are not logged.
|
||||
hushOutput bool
|
||||
@ -45,6 +49,8 @@ type TestRun struct {
|
||||
// New returns a new run instance for testing sq commands.
|
||||
// If from is non-nil, its config is used. This allows sequential
|
||||
// commands to use the same config.
|
||||
//
|
||||
// You can also use TestRun.Reset to reuse a TestRun instance.
|
||||
func New(ctx context.Context, t testing.TB, from *TestRun) *TestRun {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
@ -54,7 +60,7 @@ func New(ctx context.Context, t testing.TB, from *TestRun) *TestRun {
|
||||
ctx = lg.NewContext(ctx, slogt.New(t))
|
||||
}
|
||||
|
||||
tr := &TestRun{T: t, Context: ctx}
|
||||
tr := &TestRun{T: t, Context: ctx, mu: &sync.Mutex{}}
|
||||
|
||||
var cfgStore config.Store
|
||||
if from != nil {
|
||||
@ -110,6 +116,17 @@ func newRun(ctx context.Context, t testing.TB, cfgStore config.Store) (ru *run.R
|
||||
return ru, out, errOut
|
||||
}
|
||||
|
||||
// Reset resets tr to a clean slate. Note that a new TestRun instance
|
||||
// is created behind the scenes, so any references to the previous
|
||||
// TestRun's fields are now invalid.
|
||||
//
|
||||
// See also: testrun.New.
|
||||
func (tr *TestRun) Reset() *TestRun {
|
||||
tr2 := New(tr.Context, tr.T, tr)
|
||||
*tr = *tr2
|
||||
return tr
|
||||
}
|
||||
|
||||
// Add adds srcs to tr.Run.Config.Collection. If the collection
|
||||
// does not already have an active source, the first element
|
||||
// of srcs is used as the active source.
|
||||
@ -144,7 +161,8 @@ func (tr *TestRun) Add(srcs ...source.Source) *TestRun {
|
||||
|
||||
// Exec executes the sq command specified by args. If the first
|
||||
// element of args is not "sq", that value is prepended to the
|
||||
// args for execution. This method may only be invoked once.
|
||||
// args for execution. This method may only be invoked once on
|
||||
// this TestRun instance, unless TestRun.Reset is called.
|
||||
// The backing Run will also be closed. If an error
|
||||
// occurs on the client side during execution, that error is returned.
|
||||
// Either tr.Out or tr.ErrOut will be filled, according to what the
|
||||
@ -225,6 +243,12 @@ func (tr *TestRun) BindCSV() [][]string {
|
||||
return recs
|
||||
}
|
||||
|
||||
// OutString returns the contents of tr.Out as a string,
|
||||
// with the final trailing newline removed.
|
||||
func (tr *TestRun) OutString() string {
|
||||
return strings.TrimSuffix(tr.Out.String(), "\n")
|
||||
}
|
||||
|
||||
// Hush suppresses the printing of output collected in out
|
||||
// and errOut to t.Log. Set to true for tests
|
||||
// that output excessive content, binary files, etc.
|
||||
|
@ -44,7 +44,7 @@ func TestSmoke(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.CSVActor)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM data")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM data")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(sakila.TblActorCols()), len(sink.RecMeta))
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
@ -142,11 +142,11 @@ func TestQuerySQL_Count(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(handle)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM data")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM data")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
|
||||
sink, err = th.QuerySQL(src, "SELECT COUNT(*) FROM data")
|
||||
sink, err = th.QuerySQL(src, nil, "SELECT COUNT(*) FROM data")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, int64(sakila.TblActorCount), sink.Result())
|
||||
})
|
||||
|
@ -95,7 +95,7 @@ func TestImportJSONL_Flat(t *testing.T) {
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM data")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM data")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.wantRows, len(sink.Recs))
|
||||
require.Equal(t, tc.wantCols, sink.RecMeta.Names())
|
||||
@ -116,7 +116,7 @@ func TestImportJSON_Flat(t *testing.T) {
|
||||
err := json.ImportJSON(th.Context, job)
|
||||
require.NoError(t, err)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM data")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM data")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/cli/output"
|
||||
@ -346,12 +348,11 @@ func TestDatabaseTypes(t *testing.T) { //nolint:tparallel
|
||||
t.Logf("using source %s: %s", src.Handle, src.Location)
|
||||
|
||||
actualTblName := createTypeTestTable(th, src, true)
|
||||
t.Cleanup(func() { th.DropTable(src, actualTblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(actualTblName)) })
|
||||
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), recw,
|
||||
fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), nil, recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
require.NoError(t, err)
|
||||
written, err := recw.Wait()
|
||||
require.NoError(t, err)
|
||||
@ -412,7 +413,7 @@ func TestDatabaseTypeJSON(t *testing.T) {
|
||||
|
||||
_, err := db.ExecContext(th.Context, createStmt)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { th.DropTable(src, actualTblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(actualTblName)) })
|
||||
|
||||
// Insert data
|
||||
insertStmt := fmt.Sprintf("INSERT INTO %s (col_id, col_json, col_json_n) VALUES (?,?,?)", actualTblName)
|
||||
@ -424,7 +425,7 @@ func TestDatabaseTypeJSON(t *testing.T) {
|
||||
// Query the inserted data
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err = libsq.QuerySQL(th.Context, th.Open(src), recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
err = libsq.QuerySQL(th.Context, th.Open(src), nil, recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
require.NoError(t, err)
|
||||
written, err := recw.Wait()
|
||||
require.NoError(t, err)
|
||||
|
@ -326,8 +326,9 @@ func setSourceSummaryMeta(ctx context.Context, db sqlz.DB, md *source.Metadata)
|
||||
FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()) AS size`
|
||||
|
||||
var version, versionComment, versionOS, versionArch, schema string
|
||||
var size sql.NullInt64
|
||||
err := db.QueryRowContext(ctx, summaryQuery).Scan(&version, &versionComment, &versionOS, &versionArch, &schema,
|
||||
&md.User, &md.Size)
|
||||
&md.User, &size)
|
||||
if err != nil {
|
||||
return errw(err)
|
||||
}
|
||||
@ -335,6 +336,9 @@ func setSourceSummaryMeta(ctx context.Context, db sqlz.DB, md *source.Metadata)
|
||||
md.Name = schema
|
||||
md.Schema = schema
|
||||
md.FQName = schema
|
||||
if size.Valid {
|
||||
md.Size = size.Int64
|
||||
}
|
||||
md.DBVersion = version
|
||||
md.DBProduct = fmt.Sprintf("%s %s / %s (%s)", versionComment, version, versionOS, versionArch)
|
||||
return nil
|
||||
|
@ -5,8 +5,13 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/loz"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/jointype"
|
||||
@ -34,9 +39,6 @@ import (
|
||||
const (
|
||||
// Type is the MySQL source driver type.
|
||||
Type = source.DriverType("mysql")
|
||||
|
||||
// dbDrvr is the backing MySQL SQL driver impl name.
|
||||
dbDrvr = "mysql"
|
||||
)
|
||||
|
||||
var _ driver.Provider = (*Provider)(nil)
|
||||
@ -121,6 +123,7 @@ func (d *driveri) Dialect() dialect.Dialect {
|
||||
MaxBatchValues: 250,
|
||||
Ops: dialect.DefaultOps(),
|
||||
Joins: lo.Without(jointype.All(), jointype.FullOuter),
|
||||
Catalog: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +137,10 @@ func placeholders(numCols, numRows int) string {
|
||||
|
||||
// Renderer implements driver.SQLDriver.
|
||||
func (d *driveri) Renderer() *render.Renderer {
|
||||
return render.NewDefaultRenderer()
|
||||
r := render.NewDefaultRenderer()
|
||||
r.FunctionNames[ast.FuncNameSchema] = "DATABASE"
|
||||
r.FunctionOverrides[ast.FuncNameCatalog] = doRenderFuncCatalog
|
||||
return r
|
||||
}
|
||||
|
||||
// RecordMeta implements driver.SQLDriver.
|
||||
@ -149,6 +155,20 @@ func (d *driveri) RecordMeta(ctx context.Context, colTypes []*sql.ColumnType) (
|
||||
return recMeta, mungeFn, nil
|
||||
}
|
||||
|
||||
// CreateSchema implements driver.SQLDriver.
|
||||
func (d *driveri) CreateSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
stmt := `CREATE SCHEMA ` + stringz.BacktickQuote(schemaName)
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
return errz.Wrapf(err, "failed to create schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
// DropSchema implements driver.SQLDriver.
|
||||
func (d *driveri) DropSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
stmt := `DROP SCHEMA ` + stringz.BacktickQuote(schemaName)
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
return errz.Wrapf(err, "failed to drop schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
// CreateTable implements driver.SQLDriver.
|
||||
func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.TableDef) error {
|
||||
createStmt := buildCreateTableStmt(tblDef)
|
||||
@ -179,6 +199,48 @@ func (d *driveri) CurrentSchema(ctx context.Context, db sqlz.DB) (string, error)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListSchemas implements driver.SQLDriver.
|
||||
func (d *driveri) ListSchemas(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
log := lg.FromContext(ctx)
|
||||
|
||||
const q = `SHOW DATABASES`
|
||||
var schemas []string
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
defer lg.WarnIfCloseError(log, lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var schema string
|
||||
if err = rows.Scan(&schema); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
slices.Sort(schemas)
|
||||
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
// CurrentCatalog implements driver.SQLDriver. MySQL does not support catalogs,
|
||||
// so this method returns an error.
|
||||
func (d *driveri) CurrentCatalog(_ context.Context, _ sqlz.DB) (string, error) {
|
||||
return "", errz.New("mysql: catalog mechanism not supported")
|
||||
}
|
||||
|
||||
// ListCatalogs implements driver.SQLDriver. MySQL does not support catalogs,
|
||||
// so this method returns an error.
|
||||
func (d *driveri) ListCatalogs(_ context.Context, _ sqlz.DB) ([]string, error) {
|
||||
return nil, errz.New("mysql: catalog mechanism not supported")
|
||||
}
|
||||
|
||||
// AlterTableRename implements driver.SQLDriver.
|
||||
func (d *driveri) AlterTableRename(ctx context.Context, db sqlz.DB, tbl, newName string) error {
|
||||
q := fmt.Sprintf("RENAME TABLE `%s` TO `%s`", tbl, newName)
|
||||
@ -246,8 +308,11 @@ func newStmtExecFunc(stmt *sql.Stmt) driver.StmtExecFunc {
|
||||
}
|
||||
|
||||
// CopyTable implements driver.SQLDriver.
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) {
|
||||
stmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` SELECT * FROM `%s`", toTable, fromTable)
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB,
|
||||
fromTable, toTable tablefq.T, copyData bool,
|
||||
) (int64, error) {
|
||||
stmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s SELECT * FROM %s",
|
||||
tblfmt(toTable), tblfmt(fromTable))
|
||||
|
||||
if !copyData {
|
||||
stmt += " WHERE 0"
|
||||
@ -275,13 +340,13 @@ func (d *driveri) TableExists(ctx context.Context, db sqlz.DB, tbl string) (bool
|
||||
}
|
||||
|
||||
// DropTable implements driver.SQLDriver.
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error {
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl tablefq.T, ifExists bool) error {
|
||||
var stmt string
|
||||
|
||||
if ifExists {
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS `%s` RESTRICT", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS %s RESTRICT", tblfmt(tbl))
|
||||
} else {
|
||||
stmt = fmt.Sprintf("DROP TABLE `%s` RESTRICT", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE %s RESTRICT", tblfmt(tbl))
|
||||
}
|
||||
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
@ -367,11 +432,25 @@ func (d *driveri) doOpen(ctx context.Context, src *source.Source) (*sql.DB, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := sql.Open(dbDrvr, dsn)
|
||||
cfg, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
if src.Schema != "" {
|
||||
lg.FromContext(ctx).Debug("Setting default schema for MysQL connection",
|
||||
lga.Src, src,
|
||||
lga.Schema, src.Schema,
|
||||
)
|
||||
cfg.DBName = src.Schema
|
||||
}
|
||||
|
||||
connector, err := mysql.NewConnector(cfg)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
db := sql.OpenDB(connector)
|
||||
driver.ConfigureDB(ctx, db, src.Options)
|
||||
return db, nil
|
||||
}
|
||||
@ -513,3 +592,20 @@ func doRetry(ctx context.Context, fn func() error) error {
|
||||
maxRetryInterval := driver.OptMaxRetryInterval.Get(options.FromContext(ctx))
|
||||
return retry.Do(ctx, maxRetryInterval, fn, isErrTooManyConnections)
|
||||
}
|
||||
|
||||
// tblfmt formats a table name for use in a query. The arg can be a string,
|
||||
// or a tablefq.T.
|
||||
func tblfmt[T string | tablefq.T](tbl T) string {
|
||||
tfq := tablefq.From(tbl)
|
||||
return tfq.Render(stringz.BacktickQuote)
|
||||
}
|
||||
|
||||
func doRenderFuncCatalog(_ *render.Context, fn *ast.FuncNode) (string, error) {
|
||||
if fn.FuncName() != ast.FuncNameCatalog {
|
||||
// Shouldn't happen
|
||||
return "", errz.Errorf("expected %s function, got %q", ast.FuncNameCatalog, fn.FuncName())
|
||||
}
|
||||
|
||||
const frag = `(SELECT CATALOG_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = DATABASE() LIMIT 1)`
|
||||
return frag, nil
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package mysql_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/sqlmodel"
|
||||
@ -21,7 +23,7 @@ func TestSmoke(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
th, src, _, _, _ := testh.NewWith(t, handle)
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM actor")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM actor")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(sakila.TblActorCols()), len(sink.RecMeta))
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
@ -51,7 +53,7 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) {
|
||||
|
||||
err := drvr.CreateTable(th.Context, db, tblDef)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { th.DropTable(src, tblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(tblName)) })
|
||||
|
||||
// MySQL doesn't support default values for TEXT or BLOB
|
||||
// See: https://bugs.mysql.com/bug.php?id=21532
|
||||
@ -61,7 +63,7 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) {
|
||||
affected := th.ExecSQL(src, insertDefaultStmt, "", []byte{})
|
||||
require.Equal(t, int64(1), affected)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tblName)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, len(colNames), len(sink.RecMeta))
|
||||
@ -84,7 +86,7 @@ func TestBug252_ShowCollation_uint64(t *testing.T) {
|
||||
t.Run(handle, func(t *testing.T) {
|
||||
th, src, _, _, _ := testh.NewWith(t, handle)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SHOW COLLATION")
|
||||
sink, err := th.QuerySQL(src, nil, "SHOW COLLATION")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sink)
|
||||
})
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/testh/fixt"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -449,12 +451,10 @@ func TestDatabaseTypes(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(handle)
|
||||
insertCount, actualTblName := createTypeTestTable(th, src, true)
|
||||
t.Cleanup(func() { th.DropTable(src, actualTblName) })
|
||||
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(actualTblName)) })
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), recw,
|
||||
fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), nil, recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
require.NoError(t, err)
|
||||
written, err := recw.Wait()
|
||||
require.NoError(t, err)
|
||||
|
@ -9,6 +9,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/xo/dburl"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/jointype"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/record"
|
||||
@ -41,13 +47,8 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
const (
|
||||
// Type is the postgres source driver type.
|
||||
Type = source.DriverType("postgres")
|
||||
|
||||
// dbDrvr is the backing postgres SQL driver impl name.
|
||||
dbDrvr = "pgx"
|
||||
)
|
||||
// Type is the postgres source driver type.
|
||||
const Type = source.DriverType("postgres")
|
||||
|
||||
// Provider is the postgres implementation of driver.Provider.
|
||||
type Provider struct {
|
||||
@ -108,6 +109,7 @@ func (d *driveri) Dialect() dialect.Dialect {
|
||||
MaxBatchValues: 1000,
|
||||
Ops: dialect.DefaultOps(),
|
||||
Joins: jointype.All(),
|
||||
Catalog: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +138,10 @@ func placeholders(numCols, numRows int) string {
|
||||
|
||||
// Renderer implements driver.SQLDriver.
|
||||
func (d *driveri) Renderer() *render.Renderer {
|
||||
return render.NewDefaultRenderer()
|
||||
r := render.NewDefaultRenderer()
|
||||
r.FunctionNames[ast.FuncNameSchema] = "current_schema"
|
||||
r.FunctionNames[ast.FuncNameCatalog] = "current_database"
|
||||
return r
|
||||
}
|
||||
|
||||
// Open implements driver.DatabaseOpener.
|
||||
@ -156,27 +161,68 @@ func (d *driveri) Open(ctx context.Context, src *source.Source) (driver.Database
|
||||
}
|
||||
|
||||
func (d *driveri) doOpen(ctx context.Context, src *source.Source) (*sql.DB, error) {
|
||||
log := lg.FromContext(ctx)
|
||||
ctx = options.NewContext(ctx, src.Options)
|
||||
dbCfg, err := pgxpool.ParseConfig(src.Location)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
connStr := stdlib.RegisterConnConfig(dbCfg.ConnConfig)
|
||||
|
||||
var db *sql.DB
|
||||
if err := doRetry(ctx, func() error {
|
||||
var err2 error
|
||||
db, err2 = sql.Open(dbDrvr, connStr)
|
||||
if err2 != nil {
|
||||
lg.FromContext(ctx).Error("postgres open, may retry", lga.Err, err2)
|
||||
if src.Catalog != "" && src.Catalog != dbCfg.ConnConfig.Database {
|
||||
// The catalog differs from the database in the connection string.
|
||||
// OOTB, Postgres doesn't support cross-database references. So,
|
||||
// we'll need to change the connection string to use the catalog
|
||||
// as the database. Note that we don't modify src.Location, but it's
|
||||
// not entirely clear if that's the correct approach. Are there any
|
||||
// downsides to modifying it (as long as the modified Location is not
|
||||
// persisted back to config)?
|
||||
var u *dburl.URL
|
||||
if u, err = dburl.Parse(src.Location); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
return err2
|
||||
}); err != nil {
|
||||
return nil, errz.Wrap(err, "failed to open postgres db")
|
||||
|
||||
u.Path = src.Catalog
|
||||
connStr := u.String()
|
||||
dbCfg, err = pgxpool.ParseConfig(connStr)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
log.Debug("Using catalog as database in connection string",
|
||||
lga.Src, src,
|
||||
lga.Catalog, src.Catalog,
|
||||
lga.Conn, source.RedactLocation(connStr),
|
||||
)
|
||||
}
|
||||
|
||||
var opts []stdlib.OptionOpenDB
|
||||
if src.Schema != "" {
|
||||
opts = append(opts, stdlib.OptionAfterConnect(func(ctx context.Context, conn *pgx.Conn) error {
|
||||
var oldSearchPath string
|
||||
if err = conn.QueryRow(ctx, "SHOW search_path").Scan(&oldSearchPath); err != nil {
|
||||
return errw(err)
|
||||
}
|
||||
|
||||
newSearchPath := stringz.DoubleQuote(src.Schema)
|
||||
if oldSearchPath != "" {
|
||||
newSearchPath += ", " + oldSearchPath
|
||||
}
|
||||
|
||||
log.Debug("Setting default schema (search_path) on Postgres DB connection",
|
||||
lga.Src, src,
|
||||
lga.Conn, source.RedactLocation(dbCfg.ConnString()),
|
||||
lga.Catalog, src.Catalog,
|
||||
lga.Schema, src.Schema,
|
||||
lga.Old, oldSearchPath,
|
||||
lga.New, newSearchPath)
|
||||
|
||||
_, err = conn.Exec(ctx, "SET search_path TO "+newSearchPath)
|
||||
return errw(err)
|
||||
}))
|
||||
}
|
||||
|
||||
db := stdlib.OpenDB(*dbCfg.ConnConfig, opts...)
|
||||
driver.ConfigureDB(ctx, db, src.Options)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@ -249,6 +295,20 @@ func idSanitize(s string) string {
|
||||
return pgx.Identifier([]string{s}).Sanitize()
|
||||
}
|
||||
|
||||
// CreateSchema implements driver.SQLDriver.
|
||||
func (d *driveri) CreateSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
stmt := `CREATE SCHEMA ` + idSanitize(schemaName)
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
return errz.Wrapf(err, "failed to create schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
// DropSchema implements driver.SQLDriver.
|
||||
func (d *driveri) DropSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
stmt := `DROP SCHEMA ` + idSanitize(schemaName) + ` CASCADE`
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
return errz.Wrapf(err, "failed to drop schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
// CreateTable implements driver.SQLDriver.
|
||||
func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.TableDef) error {
|
||||
stmt := buildCreateTableStmt(tblDef)
|
||||
@ -267,6 +327,77 @@ func (d *driveri) CurrentSchema(ctx context.Context, db sqlz.DB) (string, error)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListSchemas implements driver.SQLDriver.
|
||||
func (d *driveri) ListSchemas(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
log := lg.FromContext(ctx)
|
||||
|
||||
const q = `SELECT schema_name FROM information_schema.schemata ORDER BY schema_name`
|
||||
var schemas []string
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
defer lg.WarnIfCloseError(log, lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var schema string
|
||||
if err = rows.Scan(&schema); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
// CurrentCatalog implements driver.SQLDriver.
|
||||
func (d *driveri) CurrentCatalog(ctx context.Context, db sqlz.DB) (string, error) {
|
||||
var name string
|
||||
if err := db.QueryRowContext(ctx, `SELECT CURRENT_DATABASE()`).Scan(&name); err != nil {
|
||||
return "", errw(err)
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListCatalogs implements driver.SQLDriver.
|
||||
func (d *driveri) ListCatalogs(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
catalogs := make([]string, 1, 3)
|
||||
if err := db.QueryRowContext(ctx, `SELECT CURRENT_DATABASE()`).Scan(&catalogs[0]); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
const q = `SELECT datname FROM pg_catalog.pg_database
|
||||
WHERE datistemplate = FALSE AND datallowconn = TRUE AND datname != CURRENT_DATABASE()
|
||||
ORDER BY datname`
|
||||
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
defer lg.WarnIfCloseError(lg.FromContext(ctx), lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var catalog string
|
||||
if err = rows.Scan(&catalog); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
catalogs = append(catalogs, catalog)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
return catalogs, nil
|
||||
}
|
||||
|
||||
// AlterTableRename implements driver.SQLDriver.
|
||||
func (d *driveri) AlterTableRename(ctx context.Context, db sqlz.DB, tbl, newName string) error {
|
||||
q := fmt.Sprintf(`ALTER TABLE %q RENAME TO %q`, tbl, newName)
|
||||
@ -351,8 +482,14 @@ func newStmtExecFunc(stmt *sql.Stmt) driver.StmtExecFunc {
|
||||
}
|
||||
|
||||
// CopyTable implements driver.SQLDriver.
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) {
|
||||
stmt := fmt.Sprintf("CREATE TABLE %q AS TABLE %q", toTable, fromTable)
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB,
|
||||
fromTable, toTable tablefq.T, copyData bool,
|
||||
) (int64, error) {
|
||||
stmt := fmt.Sprintf(
|
||||
"CREATE TABLE %s AS TABLE %s",
|
||||
tblfmt(toTable),
|
||||
tblfmt(fromTable),
|
||||
)
|
||||
|
||||
if !copyData {
|
||||
stmt += " WITH NO DATA"
|
||||
@ -381,13 +518,13 @@ WHERE table_name = $1`
|
||||
}
|
||||
|
||||
// DropTable implements driver.SQLDriver.
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error {
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl tablefq.T, ifExists bool) error {
|
||||
var stmt string
|
||||
|
||||
if ifExists {
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS %q RESTRICT", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS %s RESTRICT", tblfmt(tbl))
|
||||
} else {
|
||||
stmt = fmt.Sprintf("DROP TABLE %q RESTRICT", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE %s RESTRICT", tblfmt(tbl))
|
||||
}
|
||||
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
@ -630,3 +767,10 @@ func doRetry(ctx context.Context, fn func() error) error {
|
||||
maxRetryInterval := driver.OptMaxRetryInterval.Get(options.FromContext(ctx))
|
||||
return retry.Do(ctx, maxRetryInterval, fn, isErrTooManyConnections)
|
||||
}
|
||||
|
||||
// tblfmt formats a table name for use in a query. The arg can be a string,
|
||||
// or a tablefq.T.
|
||||
func tblfmt[T string | tablefq.T](tbl T) string {
|
||||
tfq := tablefq.From(tbl)
|
||||
return tfq.Render(stringz.DoubleQuote)
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
@ -33,7 +35,7 @@ func TestSmoke(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
th, src, _, _, _ := testh.NewWith(t, handle)
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM actor")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM actor")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(sakila.TblActorCols()), len(sink.RecMeta))
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
@ -103,7 +105,7 @@ func Test_VerifyDriverDoesNotReportNullability(t *testing.T) {
|
||||
db := th.OpenDB(src)
|
||||
|
||||
_, actualTblName := createTypeTestTable(th, src, true)
|
||||
t.Cleanup(func() { th.DropTable(src, actualTblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(actualTblName)) })
|
||||
|
||||
rows, err := db.Query("SELECT * FROM " + actualTblName)
|
||||
require.NoError(t, err)
|
||||
@ -172,11 +174,11 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) {
|
||||
|
||||
err := drvr.CreateTable(th.Context, db, tblDef)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { th.DropTable(src, tblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(tblName)) })
|
||||
|
||||
th.InsertDefaultRow(src, tblName)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tblName)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, len(colNames), len(sink.RecMeta))
|
||||
@ -289,7 +291,7 @@ func BenchmarkDatabase_SourceMetadata(b *testing.B) {
|
||||
|
||||
func TestIsErrRelationDoesNotExist(t *testing.T) {
|
||||
th, src, _, _, _ := testh.NewWith(t, sakila.Pg)
|
||||
_, err := th.QuerySQL(src, "SELECT * FROM tbl_does_not_exist")
|
||||
_, err := th.QuerySQL(src, nil, "SELECT * FROM tbl_does_not_exist")
|
||||
require.Error(t, err)
|
||||
require.True(t, postgres.IsErrRelationNotExist(err))
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/cli/output"
|
||||
@ -169,12 +171,12 @@ func TestDatabaseTypes(t *testing.T) {
|
||||
src := th.Source(sakila.SL3)
|
||||
actualTblName := createTypeTestTbls(th, src, 1, true)[0]
|
||||
th.Cleanup.Add(func() {
|
||||
th.DropTable(src, actualTblName)
|
||||
th.DropTable(src, tablefq.From(actualTblName))
|
||||
})
|
||||
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), nil, recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
require.NoError(t, err)
|
||||
_, err = recw.Wait()
|
||||
require.NoError(t, err)
|
||||
|
65
drivers/sqlite3/extension_test.go
Normal file
65
drivers/sqlite3/extension_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
//go:build sqlite_vtable && sqlite_fts5
|
||||
|
||||
package sqlite3_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/sqlite3"
|
||||
"github.com/neilotoole/sq/libsq/core/kind"
|
||||
"github.com/neilotoole/sq/libsq/core/sqlz"
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
"github.com/neilotoole/sq/testh"
|
||||
"github.com/neilotoole/sq/testh/sakila"
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestExtension_fts5(t *testing.T) {
|
||||
const tblActorFts = "actor_fts"
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Add(&source.Source{
|
||||
Handle: "@fts",
|
||||
Type: sqlite3.Type,
|
||||
Location: "sqlite3://" + tutil.MustAbsFilepath("testdata", "sakila_fts5.db"),
|
||||
})
|
||||
|
||||
srcMeta, err := th.SourceMetadata(src)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, src.Handle, srcMeta.Handle)
|
||||
tblMeta1 := srcMeta.Table(tblActorFts)
|
||||
require.NotNil(t, tblMeta1)
|
||||
require.Equal(t, tblActorFts, tblMeta1.Name)
|
||||
require.Equal(t, sqlz.TableTypeVirtual, tblMeta1.TableType)
|
||||
|
||||
require.Equal(t, "actor_id", tblMeta1.Columns[0].Name)
|
||||
require.Equal(t, "integer", tblMeta1.Columns[0].ColumnType)
|
||||
require.Equal(t, "integer", tblMeta1.Columns[0].BaseType)
|
||||
require.Equal(t, kind.Int, tblMeta1.Columns[0].Kind)
|
||||
require.Equal(t, "first_name", tblMeta1.Columns[1].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[1].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[1].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[1].Kind)
|
||||
require.Equal(t, "last_name", tblMeta1.Columns[2].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[2].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[2].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[2].Kind)
|
||||
require.Equal(t, "last_update", tblMeta1.Columns[3].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[3].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[3].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[3].Kind)
|
||||
|
||||
tblMeta2, err := th.TableMetadata(src, tblActorFts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tblActorFts, tblMeta2.Name)
|
||||
require.Equal(t, sqlz.TableTypeVirtual, tblMeta2.TableType)
|
||||
require.EqualValues(t, *tblMeta1, *tblMeta2)
|
||||
|
||||
// Verify that the (non-virtual) "actor" table has its type set correctly.
|
||||
actorMeta1 := srcMeta.Table(sakila.TblActor)
|
||||
actorMeta2, err := th.TableMetadata(src, sakila.TblActor)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, actorMeta1.TableType, sqlz.TableTypeTable)
|
||||
require.Equal(t, *actorMeta1, *actorMeta2)
|
||||
}
|
243
drivers/sqlite3/internal/sqlparser/SQLiteLexer.g4
Normal file
243
drivers/sqlite3/internal/sqlparser/SQLiteLexer.g4
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 by Martin Mirchev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
* associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser
|
||||
* Developed by : Bart Kiers, bart@big-o.nl
|
||||
*/
|
||||
|
||||
// $antlr-format alignTrailingComments on, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments off, useTab off
|
||||
// $antlr-format allowShortRulesOnASingleLine on, alignSemicolons ownLine
|
||||
|
||||
lexer grammar SQLiteLexer;
|
||||
|
||||
options { caseInsensitive = true; }
|
||||
|
||||
SCOL: ';';
|
||||
DOT: '.';
|
||||
OPEN_PAR: '(';
|
||||
CLOSE_PAR: ')';
|
||||
COMMA: ',';
|
||||
ASSIGN: '=';
|
||||
STAR: '*';
|
||||
PLUS: '+';
|
||||
MINUS: '-';
|
||||
TILDE: '~';
|
||||
PIPE2: '||';
|
||||
DIV: '/';
|
||||
MOD: '%';
|
||||
LT2: '<<';
|
||||
GT2: '>>';
|
||||
AMP: '&';
|
||||
PIPE: '|';
|
||||
LT: '<';
|
||||
LT_EQ: '<=';
|
||||
GT: '>';
|
||||
GT_EQ: '>=';
|
||||
EQ: '==';
|
||||
NOT_EQ1: '!=';
|
||||
NOT_EQ2: '<>';
|
||||
|
||||
// http://www.sqlite.org/lang_keywords.html
|
||||
ABORT_: 'ABORT';
|
||||
ACTION_: 'ACTION';
|
||||
ADD_: 'ADD';
|
||||
AFTER_: 'AFTER';
|
||||
ALL_: 'ALL';
|
||||
ALTER_: 'ALTER';
|
||||
ANALYZE_: 'ANALYZE';
|
||||
AND_: 'AND';
|
||||
AS_: 'AS';
|
||||
ASC_: 'ASC';
|
||||
ATTACH_: 'ATTACH';
|
||||
AUTOINCREMENT_: 'AUTOINCREMENT';
|
||||
BEFORE_: 'BEFORE';
|
||||
BEGIN_: 'BEGIN';
|
||||
BETWEEN_: 'BETWEEN';
|
||||
BY_: 'BY';
|
||||
CASCADE_: 'CASCADE';
|
||||
CASE_: 'CASE';
|
||||
CAST_: 'CAST';
|
||||
CHECK_: 'CHECK';
|
||||
COLLATE_: 'COLLATE';
|
||||
COLUMN_: 'COLUMN';
|
||||
COMMIT_: 'COMMIT';
|
||||
CONFLICT_: 'CONFLICT';
|
||||
CONSTRAINT_: 'CONSTRAINT';
|
||||
CREATE_: 'CREATE';
|
||||
CROSS_: 'CROSS';
|
||||
CURRENT_DATE_: 'CURRENT_DATE';
|
||||
CURRENT_TIME_: 'CURRENT_TIME';
|
||||
CURRENT_TIMESTAMP_: 'CURRENT_TIMESTAMP';
|
||||
DATABASE_: 'DATABASE';
|
||||
DEFAULT_: 'DEFAULT';
|
||||
DEFERRABLE_: 'DEFERRABLE';
|
||||
DEFERRED_: 'DEFERRED';
|
||||
DELETE_: 'DELETE';
|
||||
DESC_: 'DESC';
|
||||
DETACH_: 'DETACH';
|
||||
DISTINCT_: 'DISTINCT';
|
||||
DROP_: 'DROP';
|
||||
EACH_: 'EACH';
|
||||
ELSE_: 'ELSE';
|
||||
END_: 'END';
|
||||
ESCAPE_: 'ESCAPE';
|
||||
EXCEPT_: 'EXCEPT';
|
||||
EXCLUSIVE_: 'EXCLUSIVE';
|
||||
EXISTS_: 'EXISTS';
|
||||
EXPLAIN_: 'EXPLAIN';
|
||||
FAIL_: 'FAIL';
|
||||
FOR_: 'FOR';
|
||||
FOREIGN_: 'FOREIGN';
|
||||
FROM_: 'FROM';
|
||||
FULL_: 'FULL';
|
||||
GLOB_: 'GLOB';
|
||||
GROUP_: 'GROUP';
|
||||
HAVING_: 'HAVING';
|
||||
IF_: 'IF';
|
||||
IGNORE_: 'IGNORE';
|
||||
IMMEDIATE_: 'IMMEDIATE';
|
||||
IN_: 'IN';
|
||||
INDEX_: 'INDEX';
|
||||
INDEXED_: 'INDEXED';
|
||||
INITIALLY_: 'INITIALLY';
|
||||
INNER_: 'INNER';
|
||||
INSERT_: 'INSERT';
|
||||
INSTEAD_: 'INSTEAD';
|
||||
INTERSECT_: 'INTERSECT';
|
||||
INTO_: 'INTO';
|
||||
IS_: 'IS';
|
||||
ISNULL_: 'ISNULL';
|
||||
JOIN_: 'JOIN';
|
||||
KEY_: 'KEY';
|
||||
LEFT_: 'LEFT';
|
||||
LIKE_: 'LIKE';
|
||||
LIMIT_: 'LIMIT';
|
||||
MATCH_: 'MATCH';
|
||||
NATURAL_: 'NATURAL';
|
||||
NO_: 'NO';
|
||||
NOT_: 'NOT';
|
||||
NOTNULL_: 'NOTNULL';
|
||||
NULL_: 'NULL';
|
||||
OF_: 'OF';
|
||||
OFFSET_: 'OFFSET';
|
||||
ON_: 'ON';
|
||||
OR_: 'OR';
|
||||
ORDER_: 'ORDER';
|
||||
OUTER_: 'OUTER';
|
||||
PLAN_: 'PLAN';
|
||||
PRAGMA_: 'PRAGMA';
|
||||
PRIMARY_: 'PRIMARY';
|
||||
QUERY_: 'QUERY';
|
||||
RAISE_: 'RAISE';
|
||||
RECURSIVE_: 'RECURSIVE';
|
||||
REFERENCES_: 'REFERENCES';
|
||||
REGEXP_: 'REGEXP';
|
||||
REINDEX_: 'REINDEX';
|
||||
RELEASE_: 'RELEASE';
|
||||
RENAME_: 'RENAME';
|
||||
REPLACE_: 'REPLACE';
|
||||
RESTRICT_: 'RESTRICT';
|
||||
RETURNING_: 'RETURNING';
|
||||
RIGHT_: 'RIGHT';
|
||||
ROLLBACK_: 'ROLLBACK';
|
||||
ROW_: 'ROW';
|
||||
ROWS_: 'ROWS';
|
||||
SAVEPOINT_: 'SAVEPOINT';
|
||||
SELECT_: 'SELECT';
|
||||
SET_: 'SET';
|
||||
TABLE_: 'TABLE';
|
||||
TEMP_: 'TEMP';
|
||||
TEMPORARY_: 'TEMPORARY';
|
||||
THEN_: 'THEN';
|
||||
TO_: 'TO';
|
||||
TRANSACTION_: 'TRANSACTION';
|
||||
TRIGGER_: 'TRIGGER';
|
||||
UNION_: 'UNION';
|
||||
UNIQUE_: 'UNIQUE';
|
||||
UPDATE_: 'UPDATE';
|
||||
USING_: 'USING';
|
||||
VACUUM_: 'VACUUM';
|
||||
VALUES_: 'VALUES';
|
||||
VIEW_: 'VIEW';
|
||||
VIRTUAL_: 'VIRTUAL';
|
||||
WHEN_: 'WHEN';
|
||||
WHERE_: 'WHERE';
|
||||
WITH_: 'WITH';
|
||||
WITHOUT_: 'WITHOUT';
|
||||
FIRST_VALUE_: 'FIRST_VALUE';
|
||||
OVER_: 'OVER';
|
||||
PARTITION_: 'PARTITION';
|
||||
RANGE_: 'RANGE';
|
||||
PRECEDING_: 'PRECEDING';
|
||||
UNBOUNDED_: 'UNBOUNDED';
|
||||
CURRENT_: 'CURRENT';
|
||||
FOLLOWING_: 'FOLLOWING';
|
||||
CUME_DIST_: 'CUME_DIST';
|
||||
DENSE_RANK_: 'DENSE_RANK';
|
||||
LAG_: 'LAG';
|
||||
LAST_VALUE_: 'LAST_VALUE';
|
||||
LEAD_: 'LEAD';
|
||||
NTH_VALUE_: 'NTH_VALUE';
|
||||
NTILE_: 'NTILE';
|
||||
PERCENT_RANK_: 'PERCENT_RANK';
|
||||
RANK_: 'RANK';
|
||||
ROW_NUMBER_: 'ROW_NUMBER';
|
||||
GENERATED_: 'GENERATED';
|
||||
ALWAYS_: 'ALWAYS';
|
||||
STORED_: 'STORED';
|
||||
TRUE_: 'TRUE';
|
||||
FALSE_: 'FALSE';
|
||||
WINDOW_: 'WINDOW';
|
||||
NULLS_: 'NULLS';
|
||||
FIRST_: 'FIRST';
|
||||
LAST_: 'LAST';
|
||||
FILTER_: 'FILTER';
|
||||
GROUPS_: 'GROUPS';
|
||||
EXCLUDE_: 'EXCLUDE';
|
||||
TIES_: 'TIES';
|
||||
OTHERS_: 'OTHERS';
|
||||
DO_: 'DO';
|
||||
NOTHING_: 'NOTHING';
|
||||
|
||||
IDENTIFIER:
|
||||
'"' (~'"' | '""')* '"'
|
||||
| '`' (~'`' | '``')* '`'
|
||||
| '[' ~']'* ']'
|
||||
| [A-Z_] [A-Z_0-9]*
|
||||
; // TODO check: needs more chars in set
|
||||
|
||||
NUMERIC_LITERAL: ((DIGIT+ ('.' DIGIT*)?) | ('.' DIGIT+)) ('E' [-+]? DIGIT+)? | '0x' HEX_DIGIT+;
|
||||
|
||||
BIND_PARAMETER: '?' DIGIT* | [:@$] IDENTIFIER;
|
||||
|
||||
STRING_LITERAL: '\'' ( ~'\'' | '\'\'')* '\'';
|
||||
|
||||
BLOB_LITERAL: 'X' STRING_LITERAL;
|
||||
|
||||
SINGLE_LINE_COMMENT: '--' ~[\r\n]* (('\r'? '\n') | EOF) -> channel(HIDDEN);
|
||||
|
||||
MULTILINE_COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
|
||||
|
||||
SPACES: [ \u000B\t\r\n] -> channel(HIDDEN);
|
||||
|
||||
UNEXPECTED_CHAR: .;
|
||||
|
||||
fragment HEX_DIGIT: [0-9A-F];
|
||||
fragment DIGIT: [0-9];
|
915
drivers/sqlite3/internal/sqlparser/SQLiteParser.g4
Normal file
915
drivers/sqlite3/internal/sqlparser/SQLiteParser.g4
Normal file
@ -0,0 +1,915 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 by Bart Kiers
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
* associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser
|
||||
* Developed by:
|
||||
* Bart Kiers, bart@big-o.nl
|
||||
* Martin Mirchev, marti_2203@abv.bg
|
||||
* Mike Lische, mike@lischke-online.de
|
||||
*/
|
||||
|
||||
// $antlr-format alignTrailingComments on, columnLimit 130, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments off
|
||||
// $antlr-format useTab off, allowShortRulesOnASingleLine off, allowShortBlocksOnASingleLine on, alignSemicolons ownLine
|
||||
|
||||
parser grammar SQLiteParser;
|
||||
|
||||
options {
|
||||
tokenVocab = SQLiteLexer;
|
||||
}
|
||||
|
||||
parse: (sql_stmt_list)* EOF
|
||||
;
|
||||
|
||||
sql_stmt_list:
|
||||
SCOL* sql_stmt (SCOL+ sql_stmt)* SCOL*
|
||||
;
|
||||
|
||||
sql_stmt: (EXPLAIN_ (QUERY_ PLAN_)?)? (
|
||||
alter_table_stmt
|
||||
| analyze_stmt
|
||||
| attach_stmt
|
||||
| begin_stmt
|
||||
| commit_stmt
|
||||
| create_index_stmt
|
||||
| create_table_stmt
|
||||
| create_trigger_stmt
|
||||
| create_view_stmt
|
||||
| create_virtual_table_stmt
|
||||
| delete_stmt
|
||||
| delete_stmt_limited
|
||||
| detach_stmt
|
||||
| drop_stmt
|
||||
| insert_stmt
|
||||
| pragma_stmt
|
||||
| reindex_stmt
|
||||
| release_stmt
|
||||
| rollback_stmt
|
||||
| savepoint_stmt
|
||||
| select_stmt
|
||||
| update_stmt
|
||||
| update_stmt_limited
|
||||
| vacuum_stmt
|
||||
)
|
||||
;
|
||||
|
||||
alter_table_stmt:
|
||||
ALTER_ TABLE_ (schema_name DOT)? table_name (
|
||||
RENAME_ (
|
||||
TO_ new_table_name = table_name
|
||||
| COLUMN_? old_column_name = column_name TO_ new_column_name = column_name
|
||||
)
|
||||
| ADD_ COLUMN_? column_def
|
||||
| DROP_ COLUMN_? column_name
|
||||
)
|
||||
;
|
||||
|
||||
analyze_stmt:
|
||||
ANALYZE_ (schema_name | (schema_name DOT)? table_or_index_name)?
|
||||
;
|
||||
|
||||
attach_stmt:
|
||||
ATTACH_ DATABASE_? expr AS_ schema_name
|
||||
;
|
||||
|
||||
begin_stmt:
|
||||
BEGIN_ (DEFERRED_ | IMMEDIATE_ | EXCLUSIVE_)? (
|
||||
TRANSACTION_ transaction_name?
|
||||
)?
|
||||
;
|
||||
|
||||
commit_stmt: (COMMIT_ | END_) TRANSACTION_?
|
||||
;
|
||||
|
||||
rollback_stmt:
|
||||
ROLLBACK_ TRANSACTION_? (TO_ SAVEPOINT_? savepoint_name)?
|
||||
;
|
||||
|
||||
savepoint_stmt:
|
||||
SAVEPOINT_ savepoint_name
|
||||
;
|
||||
|
||||
release_stmt:
|
||||
RELEASE_ SAVEPOINT_? savepoint_name
|
||||
;
|
||||
|
||||
create_index_stmt:
|
||||
CREATE_ UNIQUE_? INDEX_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? index_name ON_ table_name OPEN_PAR
|
||||
indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?
|
||||
;
|
||||
|
||||
indexed_column: (column_name | expr) (COLLATE_ collation_name)? asc_desc?
|
||||
;
|
||||
|
||||
create_table_stmt:
|
||||
CREATE_ (TEMP_ | TEMPORARY_)? TABLE_ (IF_ NOT_ EXISTS_)? (
|
||||
schema_name DOT
|
||||
)? table_name (
|
||||
OPEN_PAR column_def (COMMA column_def)*? (COMMA table_constraint)* CLOSE_PAR (
|
||||
WITHOUT_ row_ROW_ID = IDENTIFIER
|
||||
)?
|
||||
| AS_ select_stmt
|
||||
)
|
||||
;
|
||||
|
||||
column_def:
|
||||
column_name type_name? column_constraint*
|
||||
;
|
||||
|
||||
type_name:
|
||||
name+? (
|
||||
OPEN_PAR signed_number CLOSE_PAR
|
||||
| OPEN_PAR signed_number COMMA signed_number CLOSE_PAR
|
||||
)?
|
||||
;
|
||||
|
||||
column_constraint: (CONSTRAINT_ name)? (
|
||||
(PRIMARY_ KEY_ asc_desc? conflict_clause? AUTOINCREMENT_?)
|
||||
| (NOT_? NULL_ | UNIQUE_) conflict_clause?
|
||||
| CHECK_ OPEN_PAR expr CLOSE_PAR
|
||||
| DEFAULT_ (signed_number | literal_value | OPEN_PAR expr CLOSE_PAR)
|
||||
| COLLATE_ collation_name
|
||||
| foreign_key_clause
|
||||
| (GENERATED_ ALWAYS_)? AS_ OPEN_PAR expr CLOSE_PAR (
|
||||
STORED_
|
||||
| VIRTUAL_
|
||||
)?
|
||||
)
|
||||
;
|
||||
|
||||
signed_number: (PLUS | MINUS)? NUMERIC_LITERAL
|
||||
;
|
||||
|
||||
table_constraint: (CONSTRAINT_ name)? (
|
||||
(PRIMARY_ KEY_ | UNIQUE_) OPEN_PAR indexed_column (
|
||||
COMMA indexed_column
|
||||
)* CLOSE_PAR conflict_clause?
|
||||
| CHECK_ OPEN_PAR expr CLOSE_PAR
|
||||
| FOREIGN_ KEY_ OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR foreign_key_clause
|
||||
)
|
||||
;
|
||||
|
||||
foreign_key_clause:
|
||||
REFERENCES_ foreign_table (
|
||||
OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR
|
||||
)? (
|
||||
ON_ (DELETE_ | UPDATE_) (
|
||||
SET_ (NULL_ | DEFAULT_)
|
||||
| CASCADE_
|
||||
| RESTRICT_
|
||||
| NO_ ACTION_
|
||||
)
|
||||
| MATCH_ name
|
||||
)* (NOT_? DEFERRABLE_ (INITIALLY_ (DEFERRED_ | IMMEDIATE_))?)?
|
||||
;
|
||||
|
||||
conflict_clause:
|
||||
ON_ CONFLICT_ (
|
||||
ROLLBACK_
|
||||
| ABORT_
|
||||
| FAIL_
|
||||
| IGNORE_
|
||||
| REPLACE_
|
||||
)
|
||||
;
|
||||
|
||||
create_trigger_stmt:
|
||||
CREATE_ (TEMP_ | TEMPORARY_)? TRIGGER_ (IF_ NOT_ EXISTS_)? (
|
||||
schema_name DOT
|
||||
)? trigger_name (BEFORE_ | AFTER_ | INSTEAD_ OF_)? (
|
||||
DELETE_
|
||||
| INSERT_
|
||||
| UPDATE_ (OF_ column_name ( COMMA column_name)*)?
|
||||
) ON_ table_name (FOR_ EACH_ ROW_)? (WHEN_ expr)? BEGIN_ (
|
||||
(update_stmt | insert_stmt | delete_stmt | select_stmt) SCOL
|
||||
)+ END_
|
||||
;
|
||||
|
||||
create_view_stmt:
|
||||
CREATE_ (TEMP_ | TEMPORARY_)? VIEW_ (IF_ NOT_ EXISTS_)? (
|
||||
schema_name DOT
|
||||
)? view_name (OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR)? AS_ select_stmt
|
||||
;
|
||||
|
||||
create_virtual_table_stmt:
|
||||
CREATE_ VIRTUAL_ TABLE_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? table_name USING_ module_name (
|
||||
OPEN_PAR module_argument (COMMA module_argument)* CLOSE_PAR
|
||||
)?
|
||||
;
|
||||
|
||||
with_clause:
|
||||
WITH_ RECURSIVE_? cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR (
|
||||
COMMA cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR
|
||||
)*
|
||||
;
|
||||
|
||||
cte_table_name:
|
||||
table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)?
|
||||
;
|
||||
|
||||
recursive_cte:
|
||||
cte_table_name AS_ OPEN_PAR initial_select UNION_ ALL_? recursive_select CLOSE_PAR
|
||||
;
|
||||
|
||||
common_table_expression:
|
||||
table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)? AS_ OPEN_PAR select_stmt CLOSE_PAR
|
||||
;
|
||||
|
||||
delete_stmt:
|
||||
with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause?
|
||||
;
|
||||
|
||||
delete_stmt_limited:
|
||||
with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause? (
|
||||
order_by_stmt? limit_stmt
|
||||
)?
|
||||
;
|
||||
|
||||
detach_stmt:
|
||||
DETACH_ DATABASE_? schema_name
|
||||
;
|
||||
|
||||
drop_stmt:
|
||||
DROP_ object = (INDEX_ | TABLE_ | TRIGGER_ | VIEW_) (
|
||||
IF_ EXISTS_
|
||||
)? (schema_name DOT)? any_name
|
||||
;
|
||||
|
||||
/*
|
||||
SQLite understands the following binary operators, in order from highest to lowest precedence:
|
||||
||
|
||||
* / %
|
||||
+ -
|
||||
<< >> & |
|
||||
< <= > >=
|
||||
= == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP
|
||||
AND
|
||||
OR
|
||||
*/
|
||||
expr:
|
||||
literal_value
|
||||
| BIND_PARAMETER
|
||||
| ((schema_name DOT)? table_name DOT)? column_name
|
||||
| unary_operator expr
|
||||
| expr PIPE2 expr
|
||||
| expr ( STAR | DIV | MOD) expr
|
||||
| expr ( PLUS | MINUS) expr
|
||||
| expr ( LT2 | GT2 | AMP | PIPE) expr
|
||||
| expr ( LT | LT_EQ | GT | GT_EQ) expr
|
||||
| expr (
|
||||
ASSIGN
|
||||
| EQ
|
||||
| NOT_EQ1
|
||||
| NOT_EQ2
|
||||
| IS_
|
||||
| IS_ NOT_
|
||||
| IN_
|
||||
| LIKE_
|
||||
| GLOB_
|
||||
| MATCH_
|
||||
| REGEXP_
|
||||
) expr
|
||||
| expr AND_ expr
|
||||
| expr OR_ expr
|
||||
| function_name OPEN_PAR ((DISTINCT_? expr ( COMMA expr)*) | STAR)? CLOSE_PAR filter_clause? over_clause?
|
||||
| OPEN_PAR expr (COMMA expr)* CLOSE_PAR
|
||||
| CAST_ OPEN_PAR expr AS_ type_name CLOSE_PAR
|
||||
| expr COLLATE_ collation_name
|
||||
| expr NOT_? (LIKE_ | GLOB_ | REGEXP_ | MATCH_) expr (
|
||||
ESCAPE_ expr
|
||||
)?
|
||||
| expr ( ISNULL_ | NOTNULL_ | NOT_ NULL_)
|
||||
| expr IS_ NOT_? expr
|
||||
| expr NOT_? BETWEEN_ expr AND_ expr
|
||||
| expr NOT_? IN_ (
|
||||
OPEN_PAR (select_stmt | expr ( COMMA expr)*)? CLOSE_PAR
|
||||
| ( schema_name DOT)? table_name
|
||||
| (schema_name DOT)? table_function_name OPEN_PAR (expr (COMMA expr)*)? CLOSE_PAR
|
||||
)
|
||||
| ((NOT_)? EXISTS_)? OPEN_PAR select_stmt CLOSE_PAR
|
||||
| CASE_ expr? (WHEN_ expr THEN_ expr)+ (ELSE_ expr)? END_
|
||||
| raise_function
|
||||
;
|
||||
|
||||
raise_function:
|
||||
RAISE_ OPEN_PAR (
|
||||
IGNORE_
|
||||
| (ROLLBACK_ | ABORT_ | FAIL_) COMMA error_message
|
||||
) CLOSE_PAR
|
||||
;
|
||||
|
||||
literal_value:
|
||||
NUMERIC_LITERAL
|
||||
| STRING_LITERAL
|
||||
| BLOB_LITERAL
|
||||
| NULL_
|
||||
| TRUE_
|
||||
| FALSE_
|
||||
| CURRENT_TIME_
|
||||
| CURRENT_DATE_
|
||||
| CURRENT_TIMESTAMP_
|
||||
;
|
||||
|
||||
value_row:
|
||||
OPEN_PAR expr (COMMA expr)* CLOSE_PAR
|
||||
;
|
||||
|
||||
values_clause:
|
||||
VALUES_ value_row (COMMA value_row)*
|
||||
;
|
||||
|
||||
insert_stmt:
|
||||
with_clause? (
|
||||
INSERT_
|
||||
| REPLACE_
|
||||
| INSERT_ OR_ (
|
||||
REPLACE_
|
||||
| ROLLBACK_
|
||||
| ABORT_
|
||||
| FAIL_
|
||||
| IGNORE_
|
||||
)
|
||||
) INTO_ (schema_name DOT)? table_name (AS_ table_alias)? (
|
||||
OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR
|
||||
)? (
|
||||
(
|
||||
( values_clause | select_stmt ) upsert_clause?
|
||||
)
|
||||
| DEFAULT_ VALUES_
|
||||
) returning_clause?
|
||||
;
|
||||
|
||||
returning_clause:
|
||||
RETURNING_ result_column (COMMA result_column)*
|
||||
;
|
||||
|
||||
upsert_clause:
|
||||
ON_ CONFLICT_ (
|
||||
OPEN_PAR indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?
|
||||
)? DO_ (
|
||||
NOTHING_
|
||||
| UPDATE_ SET_ (
|
||||
(column_name | column_name_list) ASSIGN expr (
|
||||
COMMA (column_name | column_name_list) ASSIGN expr
|
||||
)* (WHERE_ expr)?
|
||||
)
|
||||
)
|
||||
;
|
||||
|
||||
pragma_stmt:
|
||||
PRAGMA_ (schema_name DOT)? pragma_name (
|
||||
ASSIGN pragma_value
|
||||
| OPEN_PAR pragma_value CLOSE_PAR
|
||||
)?
|
||||
;
|
||||
|
||||
pragma_value:
|
||||
signed_number
|
||||
| name
|
||||
| STRING_LITERAL
|
||||
;
|
||||
|
||||
reindex_stmt:
|
||||
REINDEX_ (collation_name | (schema_name DOT)? (table_name | index_name))?
|
||||
;
|
||||
|
||||
select_stmt:
|
||||
common_table_stmt? select_core (compound_operator select_core)* order_by_stmt? limit_stmt?
|
||||
;
|
||||
|
||||
join_clause:
|
||||
table_or_subquery (join_operator table_or_subquery join_constraint?)*
|
||||
;
|
||||
|
||||
select_core:
|
||||
(
|
||||
SELECT_ (DISTINCT_ | ALL_)? result_column (COMMA result_column)* (
|
||||
FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)
|
||||
)? (WHERE_ whereExpr=expr)? (
|
||||
GROUP_ BY_ groupByExpr+=expr (COMMA groupByExpr+=expr)* (
|
||||
HAVING_ havingExpr=expr
|
||||
)?)? (
|
||||
WINDOW_ window_name AS_ window_defn (
|
||||
COMMA window_name AS_ window_defn
|
||||
)*
|
||||
)?
|
||||
)
|
||||
| values_clause
|
||||
;
|
||||
|
||||
factored_select_stmt:
|
||||
select_stmt
|
||||
;
|
||||
|
||||
simple_select_stmt:
|
||||
common_table_stmt? select_core order_by_stmt? limit_stmt?
|
||||
;
|
||||
|
||||
compound_select_stmt:
|
||||
common_table_stmt? select_core (
|
||||
(UNION_ ALL_? | INTERSECT_ | EXCEPT_) select_core
|
||||
)+ order_by_stmt? limit_stmt?
|
||||
;
|
||||
|
||||
table_or_subquery: (
|
||||
(schema_name DOT)? table_name (AS_? table_alias)? (
|
||||
INDEXED_ BY_ index_name
|
||||
| NOT_ INDEXED_
|
||||
)?
|
||||
)
|
||||
| (schema_name DOT)? table_function_name OPEN_PAR expr (COMMA expr)* CLOSE_PAR (
|
||||
AS_? table_alias
|
||||
)?
|
||||
| OPEN_PAR (table_or_subquery (COMMA table_or_subquery)* | join_clause) CLOSE_PAR
|
||||
| OPEN_PAR select_stmt CLOSE_PAR (AS_? table_alias)?
|
||||
;
|
||||
|
||||
result_column:
|
||||
STAR
|
||||
| table_name DOT STAR
|
||||
| expr ( AS_? column_alias)?
|
||||
;
|
||||
|
||||
join_operator:
|
||||
COMMA
|
||||
| NATURAL_? (LEFT_ OUTER_? | INNER_ | CROSS_)? JOIN_
|
||||
;
|
||||
|
||||
join_constraint:
|
||||
ON_ expr
|
||||
| USING_ OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR
|
||||
;
|
||||
|
||||
compound_operator:
|
||||
UNION_ ALL_?
|
||||
| INTERSECT_
|
||||
| EXCEPT_
|
||||
;
|
||||
|
||||
update_stmt:
|
||||
with_clause? UPDATE_ (
|
||||
OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)
|
||||
)? qualified_table_name SET_ (column_name | column_name_list) ASSIGN expr (
|
||||
COMMA (column_name | column_name_list) ASSIGN expr
|
||||
)* (
|
||||
FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)
|
||||
)? (WHERE_ expr)? returning_clause?
|
||||
;
|
||||
|
||||
column_name_list:
|
||||
OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR
|
||||
;
|
||||
|
||||
update_stmt_limited:
|
||||
with_clause? UPDATE_ (
|
||||
OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)
|
||||
)? qualified_table_name SET_ (column_name | column_name_list) ASSIGN expr (
|
||||
COMMA (column_name | column_name_list) ASSIGN expr
|
||||
)* (WHERE_ expr)? returning_clause? (order_by_stmt? limit_stmt)?
|
||||
;
|
||||
|
||||
qualified_table_name: (schema_name DOT)? table_name (AS_ alias)? (
|
||||
INDEXED_ BY_ index_name
|
||||
| NOT_ INDEXED_
|
||||
)?
|
||||
;
|
||||
|
||||
vacuum_stmt:
|
||||
VACUUM_ schema_name? (INTO_ filename)?
|
||||
;
|
||||
|
||||
filter_clause:
|
||||
FILTER_ OPEN_PAR WHERE_ expr CLOSE_PAR
|
||||
;
|
||||
|
||||
window_defn:
|
||||
OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (
|
||||
ORDER_ BY_ ordering_term (COMMA ordering_term)*
|
||||
) frame_spec? CLOSE_PAR
|
||||
;
|
||||
|
||||
over_clause:
|
||||
OVER_ (
|
||||
window_name
|
||||
| OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (
|
||||
ORDER_ BY_ ordering_term (COMMA ordering_term)*
|
||||
)? frame_spec? CLOSE_PAR
|
||||
)
|
||||
;
|
||||
|
||||
frame_spec:
|
||||
frame_clause (
|
||||
EXCLUDE_ (
|
||||
NO_ OTHERS_
|
||||
| CURRENT_ ROW_
|
||||
| GROUP_
|
||||
| TIES_
|
||||
)
|
||||
)?
|
||||
;
|
||||
|
||||
frame_clause: (RANGE_ | ROWS_ | GROUPS_) (
|
||||
frame_single
|
||||
| BETWEEN_ frame_left AND_ frame_right
|
||||
)
|
||||
;
|
||||
|
||||
simple_function_invocation:
|
||||
simple_func OPEN_PAR (expr (COMMA expr)* | STAR) CLOSE_PAR
|
||||
;
|
||||
|
||||
aggregate_function_invocation:
|
||||
aggregate_func OPEN_PAR (DISTINCT_? expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause?
|
||||
;
|
||||
|
||||
window_function_invocation:
|
||||
window_function OPEN_PAR (expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause? OVER_ (
|
||||
window_defn
|
||||
| window_name
|
||||
)
|
||||
;
|
||||
|
||||
common_table_stmt: //additional structures
|
||||
WITH_ RECURSIVE_? common_table_expression (COMMA common_table_expression)*
|
||||
;
|
||||
|
||||
order_by_stmt:
|
||||
ORDER_ BY_ ordering_term (COMMA ordering_term)*
|
||||
;
|
||||
|
||||
limit_stmt:
|
||||
LIMIT_ expr ((OFFSET_ | COMMA) expr)?
|
||||
;
|
||||
|
||||
ordering_term:
|
||||
expr (COLLATE_ collation_name)? asc_desc? (NULLS_ (FIRST_ | LAST_))?
|
||||
;
|
||||
|
||||
asc_desc:
|
||||
ASC_
|
||||
| DESC_
|
||||
;
|
||||
|
||||
frame_left:
|
||||
expr PRECEDING_
|
||||
| expr FOLLOWING_
|
||||
| CURRENT_ ROW_
|
||||
| UNBOUNDED_ PRECEDING_
|
||||
;
|
||||
|
||||
frame_right:
|
||||
expr PRECEDING_
|
||||
| expr FOLLOWING_
|
||||
| CURRENT_ ROW_
|
||||
| UNBOUNDED_ FOLLOWING_
|
||||
;
|
||||
|
||||
frame_single:
|
||||
expr PRECEDING_
|
||||
| UNBOUNDED_ PRECEDING_
|
||||
| CURRENT_ ROW_
|
||||
;
|
||||
|
||||
// unknown
|
||||
|
||||
window_function:
|
||||
(FIRST_VALUE_ | LAST_VALUE_) OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc frame_clause
|
||||
? CLOSE_PAR
|
||||
| (CUME_DIST_ | PERCENT_RANK_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr? CLOSE_PAR
|
||||
| (DENSE_RANK_ | RANK_ | ROW_NUMBER_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc
|
||||
CLOSE_PAR
|
||||
| (LAG_ | LEAD_) OPEN_PAR expr offset? default_value? CLOSE_PAR OVER_ OPEN_PAR partition_by?
|
||||
order_by_expr_asc_desc CLOSE_PAR
|
||||
| NTH_VALUE_ OPEN_PAR expr COMMA signed_number CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc
|
||||
frame_clause? CLOSE_PAR
|
||||
| NTILE_ OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc CLOSE_PAR
|
||||
;
|
||||
|
||||
offset:
|
||||
COMMA signed_number
|
||||
;
|
||||
|
||||
default_value:
|
||||
COMMA signed_number
|
||||
;
|
||||
|
||||
partition_by:
|
||||
PARTITION_ BY_ expr+
|
||||
;
|
||||
|
||||
order_by_expr:
|
||||
ORDER_ BY_ expr+
|
||||
;
|
||||
|
||||
order_by_expr_asc_desc:
|
||||
ORDER_ BY_ expr_asc_desc
|
||||
;
|
||||
|
||||
expr_asc_desc:
|
||||
expr asc_desc? (COMMA expr asc_desc?)*
|
||||
;
|
||||
|
||||
//TODO BOTH OF THESE HAVE TO BE REWORKED TO FOLLOW THE SPEC
|
||||
initial_select:
|
||||
select_stmt
|
||||
;
|
||||
|
||||
recursive_select:
|
||||
select_stmt
|
||||
;
|
||||
|
||||
unary_operator:
|
||||
MINUS
|
||||
| PLUS
|
||||
| TILDE
|
||||
| NOT_
|
||||
;
|
||||
|
||||
error_message:
|
||||
STRING_LITERAL
|
||||
;
|
||||
|
||||
module_argument: // TODO check what exactly is permitted here
|
||||
expr
|
||||
| column_def
|
||||
;
|
||||
|
||||
column_alias:
|
||||
IDENTIFIER
|
||||
| STRING_LITERAL
|
||||
;
|
||||
|
||||
keyword:
|
||||
ABORT_
|
||||
| ACTION_
|
||||
| ADD_
|
||||
| AFTER_
|
||||
| ALL_
|
||||
| ALTER_
|
||||
| ANALYZE_
|
||||
| AND_
|
||||
| AS_
|
||||
| ASC_
|
||||
| ATTACH_
|
||||
| AUTOINCREMENT_
|
||||
| BEFORE_
|
||||
| BEGIN_
|
||||
| BETWEEN_
|
||||
| BY_
|
||||
| CASCADE_
|
||||
| CASE_
|
||||
| CAST_
|
||||
| CHECK_
|
||||
| COLLATE_
|
||||
| COLUMN_
|
||||
| COMMIT_
|
||||
| CONFLICT_
|
||||
| CONSTRAINT_
|
||||
| CREATE_
|
||||
| CROSS_
|
||||
| CURRENT_DATE_
|
||||
| CURRENT_TIME_
|
||||
| CURRENT_TIMESTAMP_
|
||||
| DATABASE_
|
||||
| DEFAULT_
|
||||
| DEFERRABLE_
|
||||
| DEFERRED_
|
||||
| DELETE_
|
||||
| DESC_
|
||||
| DETACH_
|
||||
| DISTINCT_
|
||||
| DROP_
|
||||
| EACH_
|
||||
| ELSE_
|
||||
| END_
|
||||
| ESCAPE_
|
||||
| EXCEPT_
|
||||
| EXCLUSIVE_
|
||||
| EXISTS_
|
||||
| EXPLAIN_
|
||||
| FAIL_
|
||||
| FOR_
|
||||
| FOREIGN_
|
||||
| FROM_
|
||||
| FULL_
|
||||
| GLOB_
|
||||
| GROUP_
|
||||
| HAVING_
|
||||
| IF_
|
||||
| IGNORE_
|
||||
| IMMEDIATE_
|
||||
| IN_
|
||||
| INDEX_
|
||||
| INDEXED_
|
||||
| INITIALLY_
|
||||
| INNER_
|
||||
| INSERT_
|
||||
| INSTEAD_
|
||||
| INTERSECT_
|
||||
| INTO_
|
||||
| IS_
|
||||
| ISNULL_
|
||||
| JOIN_
|
||||
| KEY_
|
||||
| LEFT_
|
||||
| LIKE_
|
||||
| LIMIT_
|
||||
| MATCH_
|
||||
| NATURAL_
|
||||
| NO_
|
||||
| NOT_
|
||||
| NOTNULL_
|
||||
| NULL_
|
||||
| OF_
|
||||
| OFFSET_
|
||||
| ON_
|
||||
| OR_
|
||||
| ORDER_
|
||||
| OUTER_
|
||||
| PLAN_
|
||||
| PRAGMA_
|
||||
| PRIMARY_
|
||||
| QUERY_
|
||||
| RAISE_
|
||||
| RECURSIVE_
|
||||
| REFERENCES_
|
||||
| REGEXP_
|
||||
| REINDEX_
|
||||
| RELEASE_
|
||||
| RENAME_
|
||||
| REPLACE_
|
||||
| RESTRICT_
|
||||
| RIGHT_
|
||||
| ROLLBACK_
|
||||
| ROW_
|
||||
| ROWS_
|
||||
| SAVEPOINT_
|
||||
| SELECT_
|
||||
| SET_
|
||||
| TABLE_
|
||||
| TEMP_
|
||||
| TEMPORARY_
|
||||
| THEN_
|
||||
| TO_
|
||||
| TRANSACTION_
|
||||
| TRIGGER_
|
||||
| UNION_
|
||||
| UNIQUE_
|
||||
| UPDATE_
|
||||
| USING_
|
||||
| VACUUM_
|
||||
| VALUES_
|
||||
| VIEW_
|
||||
| VIRTUAL_
|
||||
| WHEN_
|
||||
| WHERE_
|
||||
| WITH_
|
||||
| WITHOUT_
|
||||
| FIRST_VALUE_
|
||||
| OVER_
|
||||
| PARTITION_
|
||||
| RANGE_
|
||||
| PRECEDING_
|
||||
| UNBOUNDED_
|
||||
| CURRENT_
|
||||
| FOLLOWING_
|
||||
| CUME_DIST_
|
||||
| DENSE_RANK_
|
||||
| LAG_
|
||||
| LAST_VALUE_
|
||||
| LEAD_
|
||||
| NTH_VALUE_
|
||||
| NTILE_
|
||||
| PERCENT_RANK_
|
||||
| RANK_
|
||||
| ROW_NUMBER_
|
||||
| GENERATED_
|
||||
| ALWAYS_
|
||||
| STORED_
|
||||
| TRUE_
|
||||
| FALSE_
|
||||
| WINDOW_
|
||||
| NULLS_
|
||||
| FIRST_
|
||||
| LAST_
|
||||
| FILTER_
|
||||
| GROUPS_
|
||||
| EXCLUDE_
|
||||
;
|
||||
|
||||
// TODO: check all names below
|
||||
|
||||
name:
|
||||
any_name
|
||||
;
|
||||
|
||||
function_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
schema_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
table_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
table_or_index_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
column_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
collation_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
foreign_table:
|
||||
any_name
|
||||
;
|
||||
|
||||
index_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
trigger_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
view_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
module_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
pragma_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
savepoint_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
table_alias:
|
||||
any_name
|
||||
;
|
||||
|
||||
transaction_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
window_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
alias:
|
||||
any_name
|
||||
;
|
||||
|
||||
filename:
|
||||
any_name
|
||||
;
|
||||
|
||||
base_window_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
simple_func:
|
||||
any_name
|
||||
;
|
||||
|
||||
aggregate_func:
|
||||
any_name
|
||||
;
|
||||
|
||||
table_function_name:
|
||||
any_name
|
||||
;
|
||||
|
||||
any_name:
|
||||
IDENTIFIER
|
||||
| keyword
|
||||
| STRING_LITERAL
|
||||
| OPEN_PAR any_name CLOSE_PAR
|
||||
;
|
14
drivers/sqlite3/internal/sqlparser/generate.sh
Executable file
14
drivers/sqlite3/internal/sqlparser/generate.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
dest_dir="./sqlite"
|
||||
mkdir -p $dest_dir
|
||||
|
||||
echo "Generating parser code from grammar..."
|
||||
alias antlr4='java -Xmx500M -cp "../../../../tools/antlr-4.13.0-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
|
||||
antlr4 -Dlanguage=Go -listener -visitor -o $dest_dir -package sqlite SQLiteLexer.g4 SQLiteParser.g4
|
||||
|
||||
echo "Verifying that generated files can build..."
|
||||
go build -v $dest_dir
|
||||
echo "Generated files are OK."
|
598
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteLexer.interp
Normal file
598
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteLexer.interp
Normal file
File diff suppressed because one or more lines are too long
377
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteLexer.tokens
Normal file
377
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteLexer.tokens
Normal file
@ -0,0 +1,377 @@
|
||||
SCOL=1
|
||||
DOT=2
|
||||
OPEN_PAR=3
|
||||
CLOSE_PAR=4
|
||||
COMMA=5
|
||||
ASSIGN=6
|
||||
STAR=7
|
||||
PLUS=8
|
||||
MINUS=9
|
||||
TILDE=10
|
||||
PIPE2=11
|
||||
DIV=12
|
||||
MOD=13
|
||||
LT2=14
|
||||
GT2=15
|
||||
AMP=16
|
||||
PIPE=17
|
||||
LT=18
|
||||
LT_EQ=19
|
||||
GT=20
|
||||
GT_EQ=21
|
||||
EQ=22
|
||||
NOT_EQ1=23
|
||||
NOT_EQ2=24
|
||||
ABORT_=25
|
||||
ACTION_=26
|
||||
ADD_=27
|
||||
AFTER_=28
|
||||
ALL_=29
|
||||
ALTER_=30
|
||||
ANALYZE_=31
|
||||
AND_=32
|
||||
AS_=33
|
||||
ASC_=34
|
||||
ATTACH_=35
|
||||
AUTOINCREMENT_=36
|
||||
BEFORE_=37
|
||||
BEGIN_=38
|
||||
BETWEEN_=39
|
||||
BY_=40
|
||||
CASCADE_=41
|
||||
CASE_=42
|
||||
CAST_=43
|
||||
CHECK_=44
|
||||
COLLATE_=45
|
||||
COLUMN_=46
|
||||
COMMIT_=47
|
||||
CONFLICT_=48
|
||||
CONSTRAINT_=49
|
||||
CREATE_=50
|
||||
CROSS_=51
|
||||
CURRENT_DATE_=52
|
||||
CURRENT_TIME_=53
|
||||
CURRENT_TIMESTAMP_=54
|
||||
DATABASE_=55
|
||||
DEFAULT_=56
|
||||
DEFERRABLE_=57
|
||||
DEFERRED_=58
|
||||
DELETE_=59
|
||||
DESC_=60
|
||||
DETACH_=61
|
||||
DISTINCT_=62
|
||||
DROP_=63
|
||||
EACH_=64
|
||||
ELSE_=65
|
||||
END_=66
|
||||
ESCAPE_=67
|
||||
EXCEPT_=68
|
||||
EXCLUSIVE_=69
|
||||
EXISTS_=70
|
||||
EXPLAIN_=71
|
||||
FAIL_=72
|
||||
FOR_=73
|
||||
FOREIGN_=74
|
||||
FROM_=75
|
||||
FULL_=76
|
||||
GLOB_=77
|
||||
GROUP_=78
|
||||
HAVING_=79
|
||||
IF_=80
|
||||
IGNORE_=81
|
||||
IMMEDIATE_=82
|
||||
IN_=83
|
||||
INDEX_=84
|
||||
INDEXED_=85
|
||||
INITIALLY_=86
|
||||
INNER_=87
|
||||
INSERT_=88
|
||||
INSTEAD_=89
|
||||
INTERSECT_=90
|
||||
INTO_=91
|
||||
IS_=92
|
||||
ISNULL_=93
|
||||
JOIN_=94
|
||||
KEY_=95
|
||||
LEFT_=96
|
||||
LIKE_=97
|
||||
LIMIT_=98
|
||||
MATCH_=99
|
||||
NATURAL_=100
|
||||
NO_=101
|
||||
NOT_=102
|
||||
NOTNULL_=103
|
||||
NULL_=104
|
||||
OF_=105
|
||||
OFFSET_=106
|
||||
ON_=107
|
||||
OR_=108
|
||||
ORDER_=109
|
||||
OUTER_=110
|
||||
PLAN_=111
|
||||
PRAGMA_=112
|
||||
PRIMARY_=113
|
||||
QUERY_=114
|
||||
RAISE_=115
|
||||
RECURSIVE_=116
|
||||
REFERENCES_=117
|
||||
REGEXP_=118
|
||||
REINDEX_=119
|
||||
RELEASE_=120
|
||||
RENAME_=121
|
||||
REPLACE_=122
|
||||
RESTRICT_=123
|
||||
RETURNING_=124
|
||||
RIGHT_=125
|
||||
ROLLBACK_=126
|
||||
ROW_=127
|
||||
ROWS_=128
|
||||
SAVEPOINT_=129
|
||||
SELECT_=130
|
||||
SET_=131
|
||||
TABLE_=132
|
||||
TEMP_=133
|
||||
TEMPORARY_=134
|
||||
THEN_=135
|
||||
TO_=136
|
||||
TRANSACTION_=137
|
||||
TRIGGER_=138
|
||||
UNION_=139
|
||||
UNIQUE_=140
|
||||
UPDATE_=141
|
||||
USING_=142
|
||||
VACUUM_=143
|
||||
VALUES_=144
|
||||
VIEW_=145
|
||||
VIRTUAL_=146
|
||||
WHEN_=147
|
||||
WHERE_=148
|
||||
WITH_=149
|
||||
WITHOUT_=150
|
||||
FIRST_VALUE_=151
|
||||
OVER_=152
|
||||
PARTITION_=153
|
||||
RANGE_=154
|
||||
PRECEDING_=155
|
||||
UNBOUNDED_=156
|
||||
CURRENT_=157
|
||||
FOLLOWING_=158
|
||||
CUME_DIST_=159
|
||||
DENSE_RANK_=160
|
||||
LAG_=161
|
||||
LAST_VALUE_=162
|
||||
LEAD_=163
|
||||
NTH_VALUE_=164
|
||||
NTILE_=165
|
||||
PERCENT_RANK_=166
|
||||
RANK_=167
|
||||
ROW_NUMBER_=168
|
||||
GENERATED_=169
|
||||
ALWAYS_=170
|
||||
STORED_=171
|
||||
TRUE_=172
|
||||
FALSE_=173
|
||||
WINDOW_=174
|
||||
NULLS_=175
|
||||
FIRST_=176
|
||||
LAST_=177
|
||||
FILTER_=178
|
||||
GROUPS_=179
|
||||
EXCLUDE_=180
|
||||
TIES_=181
|
||||
OTHERS_=182
|
||||
DO_=183
|
||||
NOTHING_=184
|
||||
IDENTIFIER=185
|
||||
NUMERIC_LITERAL=186
|
||||
BIND_PARAMETER=187
|
||||
STRING_LITERAL=188
|
||||
BLOB_LITERAL=189
|
||||
SINGLE_LINE_COMMENT=190
|
||||
MULTILINE_COMMENT=191
|
||||
SPACES=192
|
||||
UNEXPECTED_CHAR=193
|
||||
';'=1
|
||||
'.'=2
|
||||
'('=3
|
||||
')'=4
|
||||
','=5
|
||||
'='=6
|
||||
'*'=7
|
||||
'+'=8
|
||||
'-'=9
|
||||
'~'=10
|
||||
'||'=11
|
||||
'/'=12
|
||||
'%'=13
|
||||
'<<'=14
|
||||
'>>'=15
|
||||
'&'=16
|
||||
'|'=17
|
||||
'<'=18
|
||||
'<='=19
|
||||
'>'=20
|
||||
'>='=21
|
||||
'=='=22
|
||||
'!='=23
|
||||
'<>'=24
|
||||
'ABORT'=25
|
||||
'ACTION'=26
|
||||
'ADD'=27
|
||||
'AFTER'=28
|
||||
'ALL'=29
|
||||
'ALTER'=30
|
||||
'ANALYZE'=31
|
||||
'AND'=32
|
||||
'AS'=33
|
||||
'ASC'=34
|
||||
'ATTACH'=35
|
||||
'AUTOINCREMENT'=36
|
||||
'BEFORE'=37
|
||||
'BEGIN'=38
|
||||
'BETWEEN'=39
|
||||
'BY'=40
|
||||
'CASCADE'=41
|
||||
'CASE'=42
|
||||
'CAST'=43
|
||||
'CHECK'=44
|
||||
'COLLATE'=45
|
||||
'COLUMN'=46
|
||||
'COMMIT'=47
|
||||
'CONFLICT'=48
|
||||
'CONSTRAINT'=49
|
||||
'CREATE'=50
|
||||
'CROSS'=51
|
||||
'CURRENT_DATE'=52
|
||||
'CURRENT_TIME'=53
|
||||
'CURRENT_TIMESTAMP'=54
|
||||
'DATABASE'=55
|
||||
'DEFAULT'=56
|
||||
'DEFERRABLE'=57
|
||||
'DEFERRED'=58
|
||||
'DELETE'=59
|
||||
'DESC'=60
|
||||
'DETACH'=61
|
||||
'DISTINCT'=62
|
||||
'DROP'=63
|
||||
'EACH'=64
|
||||
'ELSE'=65
|
||||
'END'=66
|
||||
'ESCAPE'=67
|
||||
'EXCEPT'=68
|
||||
'EXCLUSIVE'=69
|
||||
'EXISTS'=70
|
||||
'EXPLAIN'=71
|
||||
'FAIL'=72
|
||||
'FOR'=73
|
||||
'FOREIGN'=74
|
||||
'FROM'=75
|
||||
'FULL'=76
|
||||
'GLOB'=77
|
||||
'GROUP'=78
|
||||
'HAVING'=79
|
||||
'IF'=80
|
||||
'IGNORE'=81
|
||||
'IMMEDIATE'=82
|
||||
'IN'=83
|
||||
'INDEX'=84
|
||||
'INDEXED'=85
|
||||
'INITIALLY'=86
|
||||
'INNER'=87
|
||||
'INSERT'=88
|
||||
'INSTEAD'=89
|
||||
'INTERSECT'=90
|
||||
'INTO'=91
|
||||
'IS'=92
|
||||
'ISNULL'=93
|
||||
'JOIN'=94
|
||||
'KEY'=95
|
||||
'LEFT'=96
|
||||
'LIKE'=97
|
||||
'LIMIT'=98
|
||||
'MATCH'=99
|
||||
'NATURAL'=100
|
||||
'NO'=101
|
||||
'NOT'=102
|
||||
'NOTNULL'=103
|
||||
'NULL'=104
|
||||
'OF'=105
|
||||
'OFFSET'=106
|
||||
'ON'=107
|
||||
'OR'=108
|
||||
'ORDER'=109
|
||||
'OUTER'=110
|
||||
'PLAN'=111
|
||||
'PRAGMA'=112
|
||||
'PRIMARY'=113
|
||||
'QUERY'=114
|
||||
'RAISE'=115
|
||||
'RECURSIVE'=116
|
||||
'REFERENCES'=117
|
||||
'REGEXP'=118
|
||||
'REINDEX'=119
|
||||
'RELEASE'=120
|
||||
'RENAME'=121
|
||||
'REPLACE'=122
|
||||
'RESTRICT'=123
|
||||
'RETURNING'=124
|
||||
'RIGHT'=125
|
||||
'ROLLBACK'=126
|
||||
'ROW'=127
|
||||
'ROWS'=128
|
||||
'SAVEPOINT'=129
|
||||
'SELECT'=130
|
||||
'SET'=131
|
||||
'TABLE'=132
|
||||
'TEMP'=133
|
||||
'TEMPORARY'=134
|
||||
'THEN'=135
|
||||
'TO'=136
|
||||
'TRANSACTION'=137
|
||||
'TRIGGER'=138
|
||||
'UNION'=139
|
||||
'UNIQUE'=140
|
||||
'UPDATE'=141
|
||||
'USING'=142
|
||||
'VACUUM'=143
|
||||
'VALUES'=144
|
||||
'VIEW'=145
|
||||
'VIRTUAL'=146
|
||||
'WHEN'=147
|
||||
'WHERE'=148
|
||||
'WITH'=149
|
||||
'WITHOUT'=150
|
||||
'FIRST_VALUE'=151
|
||||
'OVER'=152
|
||||
'PARTITION'=153
|
||||
'RANGE'=154
|
||||
'PRECEDING'=155
|
||||
'UNBOUNDED'=156
|
||||
'CURRENT'=157
|
||||
'FOLLOWING'=158
|
||||
'CUME_DIST'=159
|
||||
'DENSE_RANK'=160
|
||||
'LAG'=161
|
||||
'LAST_VALUE'=162
|
||||
'LEAD'=163
|
||||
'NTH_VALUE'=164
|
||||
'NTILE'=165
|
||||
'PERCENT_RANK'=166
|
||||
'RANK'=167
|
||||
'ROW_NUMBER'=168
|
||||
'GENERATED'=169
|
||||
'ALWAYS'=170
|
||||
'STORED'=171
|
||||
'TRUE'=172
|
||||
'FALSE'=173
|
||||
'WINDOW'=174
|
||||
'NULLS'=175
|
||||
'FIRST'=176
|
||||
'LAST'=177
|
||||
'FILTER'=178
|
||||
'GROUPS'=179
|
||||
'EXCLUDE'=180
|
||||
'TIES'=181
|
||||
'OTHERS'=182
|
||||
'DO'=183
|
||||
'NOTHING'=184
|
510
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteParser.interp
Normal file
510
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteParser.interp
Normal file
File diff suppressed because one or more lines are too long
377
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteParser.tokens
Normal file
377
drivers/sqlite3/internal/sqlparser/sqlite/SQLiteParser.tokens
Normal file
@ -0,0 +1,377 @@
|
||||
SCOL=1
|
||||
DOT=2
|
||||
OPEN_PAR=3
|
||||
CLOSE_PAR=4
|
||||
COMMA=5
|
||||
ASSIGN=6
|
||||
STAR=7
|
||||
PLUS=8
|
||||
MINUS=9
|
||||
TILDE=10
|
||||
PIPE2=11
|
||||
DIV=12
|
||||
MOD=13
|
||||
LT2=14
|
||||
GT2=15
|
||||
AMP=16
|
||||
PIPE=17
|
||||
LT=18
|
||||
LT_EQ=19
|
||||
GT=20
|
||||
GT_EQ=21
|
||||
EQ=22
|
||||
NOT_EQ1=23
|
||||
NOT_EQ2=24
|
||||
ABORT_=25
|
||||
ACTION_=26
|
||||
ADD_=27
|
||||
AFTER_=28
|
||||
ALL_=29
|
||||
ALTER_=30
|
||||
ANALYZE_=31
|
||||
AND_=32
|
||||
AS_=33
|
||||
ASC_=34
|
||||
ATTACH_=35
|
||||
AUTOINCREMENT_=36
|
||||
BEFORE_=37
|
||||
BEGIN_=38
|
||||
BETWEEN_=39
|
||||
BY_=40
|
||||
CASCADE_=41
|
||||
CASE_=42
|
||||
CAST_=43
|
||||
CHECK_=44
|
||||
COLLATE_=45
|
||||
COLUMN_=46
|
||||
COMMIT_=47
|
||||
CONFLICT_=48
|
||||
CONSTRAINT_=49
|
||||
CREATE_=50
|
||||
CROSS_=51
|
||||
CURRENT_DATE_=52
|
||||
CURRENT_TIME_=53
|
||||
CURRENT_TIMESTAMP_=54
|
||||
DATABASE_=55
|
||||
DEFAULT_=56
|
||||
DEFERRABLE_=57
|
||||
DEFERRED_=58
|
||||
DELETE_=59
|
||||
DESC_=60
|
||||
DETACH_=61
|
||||
DISTINCT_=62
|
||||
DROP_=63
|
||||
EACH_=64
|
||||
ELSE_=65
|
||||
END_=66
|
||||
ESCAPE_=67
|
||||
EXCEPT_=68
|
||||
EXCLUSIVE_=69
|
||||
EXISTS_=70
|
||||
EXPLAIN_=71
|
||||
FAIL_=72
|
||||
FOR_=73
|
||||
FOREIGN_=74
|
||||
FROM_=75
|
||||
FULL_=76
|
||||
GLOB_=77
|
||||
GROUP_=78
|
||||
HAVING_=79
|
||||
IF_=80
|
||||
IGNORE_=81
|
||||
IMMEDIATE_=82
|
||||
IN_=83
|
||||
INDEX_=84
|
||||
INDEXED_=85
|
||||
INITIALLY_=86
|
||||
INNER_=87
|
||||
INSERT_=88
|
||||
INSTEAD_=89
|
||||
INTERSECT_=90
|
||||
INTO_=91
|
||||
IS_=92
|
||||
ISNULL_=93
|
||||
JOIN_=94
|
||||
KEY_=95
|
||||
LEFT_=96
|
||||
LIKE_=97
|
||||
LIMIT_=98
|
||||
MATCH_=99
|
||||
NATURAL_=100
|
||||
NO_=101
|
||||
NOT_=102
|
||||
NOTNULL_=103
|
||||
NULL_=104
|
||||
OF_=105
|
||||
OFFSET_=106
|
||||
ON_=107
|
||||
OR_=108
|
||||
ORDER_=109
|
||||
OUTER_=110
|
||||
PLAN_=111
|
||||
PRAGMA_=112
|
||||
PRIMARY_=113
|
||||
QUERY_=114
|
||||
RAISE_=115
|
||||
RECURSIVE_=116
|
||||
REFERENCES_=117
|
||||
REGEXP_=118
|
||||
REINDEX_=119
|
||||
RELEASE_=120
|
||||
RENAME_=121
|
||||
REPLACE_=122
|
||||
RESTRICT_=123
|
||||
RETURNING_=124
|
||||
RIGHT_=125
|
||||
ROLLBACK_=126
|
||||
ROW_=127
|
||||
ROWS_=128
|
||||
SAVEPOINT_=129
|
||||
SELECT_=130
|
||||
SET_=131
|
||||
TABLE_=132
|
||||
TEMP_=133
|
||||
TEMPORARY_=134
|
||||
THEN_=135
|
||||
TO_=136
|
||||
TRANSACTION_=137
|
||||
TRIGGER_=138
|
||||
UNION_=139
|
||||
UNIQUE_=140
|
||||
UPDATE_=141
|
||||
USING_=142
|
||||
VACUUM_=143
|
||||
VALUES_=144
|
||||
VIEW_=145
|
||||
VIRTUAL_=146
|
||||
WHEN_=147
|
||||
WHERE_=148
|
||||
WITH_=149
|
||||
WITHOUT_=150
|
||||
FIRST_VALUE_=151
|
||||
OVER_=152
|
||||
PARTITION_=153
|
||||
RANGE_=154
|
||||
PRECEDING_=155
|
||||
UNBOUNDED_=156
|
||||
CURRENT_=157
|
||||
FOLLOWING_=158
|
||||
CUME_DIST_=159
|
||||
DENSE_RANK_=160
|
||||
LAG_=161
|
||||
LAST_VALUE_=162
|
||||
LEAD_=163
|
||||
NTH_VALUE_=164
|
||||
NTILE_=165
|
||||
PERCENT_RANK_=166
|
||||
RANK_=167
|
||||
ROW_NUMBER_=168
|
||||
GENERATED_=169
|
||||
ALWAYS_=170
|
||||
STORED_=171
|
||||
TRUE_=172
|
||||
FALSE_=173
|
||||
WINDOW_=174
|
||||
NULLS_=175
|
||||
FIRST_=176
|
||||
LAST_=177
|
||||
FILTER_=178
|
||||
GROUPS_=179
|
||||
EXCLUDE_=180
|
||||
TIES_=181
|
||||
OTHERS_=182
|
||||
DO_=183
|
||||
NOTHING_=184
|
||||
IDENTIFIER=185
|
||||
NUMERIC_LITERAL=186
|
||||
BIND_PARAMETER=187
|
||||
STRING_LITERAL=188
|
||||
BLOB_LITERAL=189
|
||||
SINGLE_LINE_COMMENT=190
|
||||
MULTILINE_COMMENT=191
|
||||
SPACES=192
|
||||
UNEXPECTED_CHAR=193
|
||||
';'=1
|
||||
'.'=2
|
||||
'('=3
|
||||
')'=4
|
||||
','=5
|
||||
'='=6
|
||||
'*'=7
|
||||
'+'=8
|
||||
'-'=9
|
||||
'~'=10
|
||||
'||'=11
|
||||
'/'=12
|
||||
'%'=13
|
||||
'<<'=14
|
||||
'>>'=15
|
||||
'&'=16
|
||||
'|'=17
|
||||
'<'=18
|
||||
'<='=19
|
||||
'>'=20
|
||||
'>='=21
|
||||
'=='=22
|
||||
'!='=23
|
||||
'<>'=24
|
||||
'ABORT'=25
|
||||
'ACTION'=26
|
||||
'ADD'=27
|
||||
'AFTER'=28
|
||||
'ALL'=29
|
||||
'ALTER'=30
|
||||
'ANALYZE'=31
|
||||
'AND'=32
|
||||
'AS'=33
|
||||
'ASC'=34
|
||||
'ATTACH'=35
|
||||
'AUTOINCREMENT'=36
|
||||
'BEFORE'=37
|
||||
'BEGIN'=38
|
||||
'BETWEEN'=39
|
||||
'BY'=40
|
||||
'CASCADE'=41
|
||||
'CASE'=42
|
||||
'CAST'=43
|
||||
'CHECK'=44
|
||||
'COLLATE'=45
|
||||
'COLUMN'=46
|
||||
'COMMIT'=47
|
||||
'CONFLICT'=48
|
||||
'CONSTRAINT'=49
|
||||
'CREATE'=50
|
||||
'CROSS'=51
|
||||
'CURRENT_DATE'=52
|
||||
'CURRENT_TIME'=53
|
||||
'CURRENT_TIMESTAMP'=54
|
||||
'DATABASE'=55
|
||||
'DEFAULT'=56
|
||||
'DEFERRABLE'=57
|
||||
'DEFERRED'=58
|
||||
'DELETE'=59
|
||||
'DESC'=60
|
||||
'DETACH'=61
|
||||
'DISTINCT'=62
|
||||
'DROP'=63
|
||||
'EACH'=64
|
||||
'ELSE'=65
|
||||
'END'=66
|
||||
'ESCAPE'=67
|
||||
'EXCEPT'=68
|
||||
'EXCLUSIVE'=69
|
||||
'EXISTS'=70
|
||||
'EXPLAIN'=71
|
||||
'FAIL'=72
|
||||
'FOR'=73
|
||||
'FOREIGN'=74
|
||||
'FROM'=75
|
||||
'FULL'=76
|
||||
'GLOB'=77
|
||||
'GROUP'=78
|
||||
'HAVING'=79
|
||||
'IF'=80
|
||||
'IGNORE'=81
|
||||
'IMMEDIATE'=82
|
||||
'IN'=83
|
||||
'INDEX'=84
|
||||
'INDEXED'=85
|
||||
'INITIALLY'=86
|
||||
'INNER'=87
|
||||
'INSERT'=88
|
||||
'INSTEAD'=89
|
||||
'INTERSECT'=90
|
||||
'INTO'=91
|
||||
'IS'=92
|
||||
'ISNULL'=93
|
||||
'JOIN'=94
|
||||
'KEY'=95
|
||||
'LEFT'=96
|
||||
'LIKE'=97
|
||||
'LIMIT'=98
|
||||
'MATCH'=99
|
||||
'NATURAL'=100
|
||||
'NO'=101
|
||||
'NOT'=102
|
||||
'NOTNULL'=103
|
||||
'NULL'=104
|
||||
'OF'=105
|
||||
'OFFSET'=106
|
||||
'ON'=107
|
||||
'OR'=108
|
||||
'ORDER'=109
|
||||
'OUTER'=110
|
||||
'PLAN'=111
|
||||
'PRAGMA'=112
|
||||
'PRIMARY'=113
|
||||
'QUERY'=114
|
||||
'RAISE'=115
|
||||
'RECURSIVE'=116
|
||||
'REFERENCES'=117
|
||||
'REGEXP'=118
|
||||
'REINDEX'=119
|
||||
'RELEASE'=120
|
||||
'RENAME'=121
|
||||
'REPLACE'=122
|
||||
'RESTRICT'=123
|
||||
'RETURNING'=124
|
||||
'RIGHT'=125
|
||||
'ROLLBACK'=126
|
||||
'ROW'=127
|
||||
'ROWS'=128
|
||||
'SAVEPOINT'=129
|
||||
'SELECT'=130
|
||||
'SET'=131
|
||||
'TABLE'=132
|
||||
'TEMP'=133
|
||||
'TEMPORARY'=134
|
||||
'THEN'=135
|
||||
'TO'=136
|
||||
'TRANSACTION'=137
|
||||
'TRIGGER'=138
|
||||
'UNION'=139
|
||||
'UNIQUE'=140
|
||||
'UPDATE'=141
|
||||
'USING'=142
|
||||
'VACUUM'=143
|
||||
'VALUES'=144
|
||||
'VIEW'=145
|
||||
'VIRTUAL'=146
|
||||
'WHEN'=147
|
||||
'WHERE'=148
|
||||
'WITH'=149
|
||||
'WITHOUT'=150
|
||||
'FIRST_VALUE'=151
|
||||
'OVER'=152
|
||||
'PARTITION'=153
|
||||
'RANGE'=154
|
||||
'PRECEDING'=155
|
||||
'UNBOUNDED'=156
|
||||
'CURRENT'=157
|
||||
'FOLLOWING'=158
|
||||
'CUME_DIST'=159
|
||||
'DENSE_RANK'=160
|
||||
'LAG'=161
|
||||
'LAST_VALUE'=162
|
||||
'LEAD'=163
|
||||
'NTH_VALUE'=164
|
||||
'NTILE'=165
|
||||
'PERCENT_RANK'=166
|
||||
'RANK'=167
|
||||
'ROW_NUMBER'=168
|
||||
'GENERATED'=169
|
||||
'ALWAYS'=170
|
||||
'STORED'=171
|
||||
'TRUE'=172
|
||||
'FALSE'=173
|
||||
'WINDOW'=174
|
||||
'NULLS'=175
|
||||
'FIRST'=176
|
||||
'LAST'=177
|
||||
'FILTER'=178
|
||||
'GROUPS'=179
|
||||
'EXCLUDE'=180
|
||||
'TIES'=181
|
||||
'OTHERS'=182
|
||||
'DO'=183
|
||||
'NOTHING'=184
|
1137
drivers/sqlite3/internal/sqlparser/sqlite/sqlite_lexer.go
Normal file
1137
drivers/sqlite3/internal/sqlparser/sqlite/sqlite_lexer.go
Normal file
File diff suppressed because it is too large
Load Diff
32524
drivers/sqlite3/internal/sqlparser/sqlite/sqlite_parser.go
Normal file
32524
drivers/sqlite3/internal/sqlparser/sqlite/sqlite_parser.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,708 @@
|
||||
// Code generated from SQLiteParser.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package sqlite // SQLiteParser
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
// BaseSQLiteParserListener is a complete listener for a parse tree produced by SQLiteParser.
|
||||
type BaseSQLiteParserListener struct{}
|
||||
|
||||
var _ SQLiteParserListener = &BaseSQLiteParserListener{}
|
||||
|
||||
// VisitTerminal is called when a terminal node is visited.
|
||||
func (s *BaseSQLiteParserListener) VisitTerminal(node antlr.TerminalNode) {}
|
||||
|
||||
// VisitErrorNode is called when an error node is visited.
|
||||
func (s *BaseSQLiteParserListener) VisitErrorNode(node antlr.ErrorNode) {}
|
||||
|
||||
// EnterEveryRule is called when any rule is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
|
||||
|
||||
// ExitEveryRule is called when any rule is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
|
||||
|
||||
// EnterParse is called when production parse is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterParse(ctx *ParseContext) {}
|
||||
|
||||
// ExitParse is called when production parse is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitParse(ctx *ParseContext) {}
|
||||
|
||||
// EnterSql_stmt_list is called when production sql_stmt_list is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSql_stmt_list(ctx *Sql_stmt_listContext) {}
|
||||
|
||||
// ExitSql_stmt_list is called when production sql_stmt_list is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSql_stmt_list(ctx *Sql_stmt_listContext) {}
|
||||
|
||||
// EnterSql_stmt is called when production sql_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSql_stmt(ctx *Sql_stmtContext) {}
|
||||
|
||||
// ExitSql_stmt is called when production sql_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSql_stmt(ctx *Sql_stmtContext) {}
|
||||
|
||||
// EnterAlter_table_stmt is called when production alter_table_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAlter_table_stmt(ctx *Alter_table_stmtContext) {}
|
||||
|
||||
// ExitAlter_table_stmt is called when production alter_table_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAlter_table_stmt(ctx *Alter_table_stmtContext) {}
|
||||
|
||||
// EnterAnalyze_stmt is called when production analyze_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAnalyze_stmt(ctx *Analyze_stmtContext) {}
|
||||
|
||||
// ExitAnalyze_stmt is called when production analyze_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAnalyze_stmt(ctx *Analyze_stmtContext) {}
|
||||
|
||||
// EnterAttach_stmt is called when production attach_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAttach_stmt(ctx *Attach_stmtContext) {}
|
||||
|
||||
// ExitAttach_stmt is called when production attach_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAttach_stmt(ctx *Attach_stmtContext) {}
|
||||
|
||||
// EnterBegin_stmt is called when production begin_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterBegin_stmt(ctx *Begin_stmtContext) {}
|
||||
|
||||
// ExitBegin_stmt is called when production begin_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitBegin_stmt(ctx *Begin_stmtContext) {}
|
||||
|
||||
// EnterCommit_stmt is called when production commit_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCommit_stmt(ctx *Commit_stmtContext) {}
|
||||
|
||||
// ExitCommit_stmt is called when production commit_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCommit_stmt(ctx *Commit_stmtContext) {}
|
||||
|
||||
// EnterRollback_stmt is called when production rollback_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterRollback_stmt(ctx *Rollback_stmtContext) {}
|
||||
|
||||
// ExitRollback_stmt is called when production rollback_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitRollback_stmt(ctx *Rollback_stmtContext) {}
|
||||
|
||||
// EnterSavepoint_stmt is called when production savepoint_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSavepoint_stmt(ctx *Savepoint_stmtContext) {}
|
||||
|
||||
// ExitSavepoint_stmt is called when production savepoint_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSavepoint_stmt(ctx *Savepoint_stmtContext) {}
|
||||
|
||||
// EnterRelease_stmt is called when production release_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterRelease_stmt(ctx *Release_stmtContext) {}
|
||||
|
||||
// ExitRelease_stmt is called when production release_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitRelease_stmt(ctx *Release_stmtContext) {}
|
||||
|
||||
// EnterCreate_index_stmt is called when production create_index_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCreate_index_stmt(ctx *Create_index_stmtContext) {}
|
||||
|
||||
// ExitCreate_index_stmt is called when production create_index_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCreate_index_stmt(ctx *Create_index_stmtContext) {}
|
||||
|
||||
// EnterIndexed_column is called when production indexed_column is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterIndexed_column(ctx *Indexed_columnContext) {}
|
||||
|
||||
// ExitIndexed_column is called when production indexed_column is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitIndexed_column(ctx *Indexed_columnContext) {}
|
||||
|
||||
// EnterCreate_table_stmt is called when production create_table_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCreate_table_stmt(ctx *Create_table_stmtContext) {}
|
||||
|
||||
// ExitCreate_table_stmt is called when production create_table_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCreate_table_stmt(ctx *Create_table_stmtContext) {}
|
||||
|
||||
// EnterColumn_def is called when production column_def is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterColumn_def(ctx *Column_defContext) {}
|
||||
|
||||
// ExitColumn_def is called when production column_def is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitColumn_def(ctx *Column_defContext) {}
|
||||
|
||||
// EnterType_name is called when production type_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterType_name(ctx *Type_nameContext) {}
|
||||
|
||||
// ExitType_name is called when production type_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitType_name(ctx *Type_nameContext) {}
|
||||
|
||||
// EnterColumn_constraint is called when production column_constraint is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterColumn_constraint(ctx *Column_constraintContext) {}
|
||||
|
||||
// ExitColumn_constraint is called when production column_constraint is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitColumn_constraint(ctx *Column_constraintContext) {}
|
||||
|
||||
// EnterSigned_number is called when production signed_number is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSigned_number(ctx *Signed_numberContext) {}
|
||||
|
||||
// ExitSigned_number is called when production signed_number is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSigned_number(ctx *Signed_numberContext) {}
|
||||
|
||||
// EnterTable_constraint is called when production table_constraint is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_constraint(ctx *Table_constraintContext) {}
|
||||
|
||||
// ExitTable_constraint is called when production table_constraint is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_constraint(ctx *Table_constraintContext) {}
|
||||
|
||||
// EnterForeign_key_clause is called when production foreign_key_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterForeign_key_clause(ctx *Foreign_key_clauseContext) {}
|
||||
|
||||
// ExitForeign_key_clause is called when production foreign_key_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitForeign_key_clause(ctx *Foreign_key_clauseContext) {}
|
||||
|
||||
// EnterConflict_clause is called when production conflict_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterConflict_clause(ctx *Conflict_clauseContext) {}
|
||||
|
||||
// ExitConflict_clause is called when production conflict_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitConflict_clause(ctx *Conflict_clauseContext) {}
|
||||
|
||||
// EnterCreate_trigger_stmt is called when production create_trigger_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}
|
||||
|
||||
// ExitCreate_trigger_stmt is called when production create_trigger_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}
|
||||
|
||||
// EnterCreate_view_stmt is called when production create_view_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCreate_view_stmt(ctx *Create_view_stmtContext) {}
|
||||
|
||||
// ExitCreate_view_stmt is called when production create_view_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCreate_view_stmt(ctx *Create_view_stmtContext) {}
|
||||
|
||||
// EnterCreate_virtual_table_stmt is called when production create_virtual_table_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {
|
||||
}
|
||||
|
||||
// ExitCreate_virtual_table_stmt is called when production create_virtual_table_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {
|
||||
}
|
||||
|
||||
// EnterWith_clause is called when production with_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterWith_clause(ctx *With_clauseContext) {}
|
||||
|
||||
// ExitWith_clause is called when production with_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitWith_clause(ctx *With_clauseContext) {}
|
||||
|
||||
// EnterCte_table_name is called when production cte_table_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCte_table_name(ctx *Cte_table_nameContext) {}
|
||||
|
||||
// ExitCte_table_name is called when production cte_table_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCte_table_name(ctx *Cte_table_nameContext) {}
|
||||
|
||||
// EnterRecursive_cte is called when production recursive_cte is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterRecursive_cte(ctx *Recursive_cteContext) {}
|
||||
|
||||
// ExitRecursive_cte is called when production recursive_cte is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitRecursive_cte(ctx *Recursive_cteContext) {}
|
||||
|
||||
// EnterCommon_table_expression is called when production common_table_expression is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCommon_table_expression(ctx *Common_table_expressionContext) {
|
||||
}
|
||||
|
||||
// ExitCommon_table_expression is called when production common_table_expression is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCommon_table_expression(ctx *Common_table_expressionContext) {}
|
||||
|
||||
// EnterDelete_stmt is called when production delete_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterDelete_stmt(ctx *Delete_stmtContext) {}
|
||||
|
||||
// ExitDelete_stmt is called when production delete_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitDelete_stmt(ctx *Delete_stmtContext) {}
|
||||
|
||||
// EnterDelete_stmt_limited is called when production delete_stmt_limited is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}
|
||||
|
||||
// ExitDelete_stmt_limited is called when production delete_stmt_limited is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}
|
||||
|
||||
// EnterDetach_stmt is called when production detach_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterDetach_stmt(ctx *Detach_stmtContext) {}
|
||||
|
||||
// ExitDetach_stmt is called when production detach_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitDetach_stmt(ctx *Detach_stmtContext) {}
|
||||
|
||||
// EnterDrop_stmt is called when production drop_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterDrop_stmt(ctx *Drop_stmtContext) {}
|
||||
|
||||
// ExitDrop_stmt is called when production drop_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitDrop_stmt(ctx *Drop_stmtContext) {}
|
||||
|
||||
// EnterExpr is called when production expr is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterExpr(ctx *ExprContext) {}
|
||||
|
||||
// ExitExpr is called when production expr is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitExpr(ctx *ExprContext) {}
|
||||
|
||||
// EnterRaise_function is called when production raise_function is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterRaise_function(ctx *Raise_functionContext) {}
|
||||
|
||||
// ExitRaise_function is called when production raise_function is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitRaise_function(ctx *Raise_functionContext) {}
|
||||
|
||||
// EnterLiteral_value is called when production literal_value is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterLiteral_value(ctx *Literal_valueContext) {}
|
||||
|
||||
// ExitLiteral_value is called when production literal_value is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitLiteral_value(ctx *Literal_valueContext) {}
|
||||
|
||||
// EnterValue_row is called when production value_row is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterValue_row(ctx *Value_rowContext) {}
|
||||
|
||||
// ExitValue_row is called when production value_row is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitValue_row(ctx *Value_rowContext) {}
|
||||
|
||||
// EnterValues_clause is called when production values_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterValues_clause(ctx *Values_clauseContext) {}
|
||||
|
||||
// ExitValues_clause is called when production values_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitValues_clause(ctx *Values_clauseContext) {}
|
||||
|
||||
// EnterInsert_stmt is called when production insert_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterInsert_stmt(ctx *Insert_stmtContext) {}
|
||||
|
||||
// ExitInsert_stmt is called when production insert_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitInsert_stmt(ctx *Insert_stmtContext) {}
|
||||
|
||||
// EnterReturning_clause is called when production returning_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterReturning_clause(ctx *Returning_clauseContext) {}
|
||||
|
||||
// ExitReturning_clause is called when production returning_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitReturning_clause(ctx *Returning_clauseContext) {}
|
||||
|
||||
// EnterUpsert_clause is called when production upsert_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterUpsert_clause(ctx *Upsert_clauseContext) {}
|
||||
|
||||
// ExitUpsert_clause is called when production upsert_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitUpsert_clause(ctx *Upsert_clauseContext) {}
|
||||
|
||||
// EnterPragma_stmt is called when production pragma_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterPragma_stmt(ctx *Pragma_stmtContext) {}
|
||||
|
||||
// ExitPragma_stmt is called when production pragma_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitPragma_stmt(ctx *Pragma_stmtContext) {}
|
||||
|
||||
// EnterPragma_value is called when production pragma_value is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterPragma_value(ctx *Pragma_valueContext) {}
|
||||
|
||||
// ExitPragma_value is called when production pragma_value is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitPragma_value(ctx *Pragma_valueContext) {}
|
||||
|
||||
// EnterReindex_stmt is called when production reindex_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterReindex_stmt(ctx *Reindex_stmtContext) {}
|
||||
|
||||
// ExitReindex_stmt is called when production reindex_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitReindex_stmt(ctx *Reindex_stmtContext) {}
|
||||
|
||||
// EnterSelect_stmt is called when production select_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSelect_stmt(ctx *Select_stmtContext) {}
|
||||
|
||||
// ExitSelect_stmt is called when production select_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSelect_stmt(ctx *Select_stmtContext) {}
|
||||
|
||||
// EnterJoin_clause is called when production join_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterJoin_clause(ctx *Join_clauseContext) {}
|
||||
|
||||
// ExitJoin_clause is called when production join_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitJoin_clause(ctx *Join_clauseContext) {}
|
||||
|
||||
// EnterSelect_core is called when production select_core is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSelect_core(ctx *Select_coreContext) {}
|
||||
|
||||
// ExitSelect_core is called when production select_core is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSelect_core(ctx *Select_coreContext) {}
|
||||
|
||||
// EnterFactored_select_stmt is called when production factored_select_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFactored_select_stmt(ctx *Factored_select_stmtContext) {}
|
||||
|
||||
// ExitFactored_select_stmt is called when production factored_select_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFactored_select_stmt(ctx *Factored_select_stmtContext) {}
|
||||
|
||||
// EnterSimple_select_stmt is called when production simple_select_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSimple_select_stmt(ctx *Simple_select_stmtContext) {}
|
||||
|
||||
// ExitSimple_select_stmt is called when production simple_select_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSimple_select_stmt(ctx *Simple_select_stmtContext) {}
|
||||
|
||||
// EnterCompound_select_stmt is called when production compound_select_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCompound_select_stmt(ctx *Compound_select_stmtContext) {}
|
||||
|
||||
// ExitCompound_select_stmt is called when production compound_select_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCompound_select_stmt(ctx *Compound_select_stmtContext) {}
|
||||
|
||||
// EnterTable_or_subquery is called when production table_or_subquery is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_or_subquery(ctx *Table_or_subqueryContext) {}
|
||||
|
||||
// ExitTable_or_subquery is called when production table_or_subquery is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_or_subquery(ctx *Table_or_subqueryContext) {}
|
||||
|
||||
// EnterResult_column is called when production result_column is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterResult_column(ctx *Result_columnContext) {}
|
||||
|
||||
// ExitResult_column is called when production result_column is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitResult_column(ctx *Result_columnContext) {}
|
||||
|
||||
// EnterJoin_operator is called when production join_operator is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterJoin_operator(ctx *Join_operatorContext) {}
|
||||
|
||||
// ExitJoin_operator is called when production join_operator is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitJoin_operator(ctx *Join_operatorContext) {}
|
||||
|
||||
// EnterJoin_constraint is called when production join_constraint is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterJoin_constraint(ctx *Join_constraintContext) {}
|
||||
|
||||
// ExitJoin_constraint is called when production join_constraint is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitJoin_constraint(ctx *Join_constraintContext) {}
|
||||
|
||||
// EnterCompound_operator is called when production compound_operator is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCompound_operator(ctx *Compound_operatorContext) {}
|
||||
|
||||
// ExitCompound_operator is called when production compound_operator is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCompound_operator(ctx *Compound_operatorContext) {}
|
||||
|
||||
// EnterUpdate_stmt is called when production update_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterUpdate_stmt(ctx *Update_stmtContext) {}
|
||||
|
||||
// ExitUpdate_stmt is called when production update_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitUpdate_stmt(ctx *Update_stmtContext) {}
|
||||
|
||||
// EnterColumn_name_list is called when production column_name_list is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterColumn_name_list(ctx *Column_name_listContext) {}
|
||||
|
||||
// ExitColumn_name_list is called when production column_name_list is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitColumn_name_list(ctx *Column_name_listContext) {}
|
||||
|
||||
// EnterUpdate_stmt_limited is called when production update_stmt_limited is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}
|
||||
|
||||
// ExitUpdate_stmt_limited is called when production update_stmt_limited is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}
|
||||
|
||||
// EnterQualified_table_name is called when production qualified_table_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterQualified_table_name(ctx *Qualified_table_nameContext) {}
|
||||
|
||||
// ExitQualified_table_name is called when production qualified_table_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitQualified_table_name(ctx *Qualified_table_nameContext) {}
|
||||
|
||||
// EnterVacuum_stmt is called when production vacuum_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterVacuum_stmt(ctx *Vacuum_stmtContext) {}
|
||||
|
||||
// ExitVacuum_stmt is called when production vacuum_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitVacuum_stmt(ctx *Vacuum_stmtContext) {}
|
||||
|
||||
// EnterFilter_clause is called when production filter_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFilter_clause(ctx *Filter_clauseContext) {}
|
||||
|
||||
// ExitFilter_clause is called when production filter_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFilter_clause(ctx *Filter_clauseContext) {}
|
||||
|
||||
// EnterWindow_defn is called when production window_defn is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterWindow_defn(ctx *Window_defnContext) {}
|
||||
|
||||
// ExitWindow_defn is called when production window_defn is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitWindow_defn(ctx *Window_defnContext) {}
|
||||
|
||||
// EnterOver_clause is called when production over_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOver_clause(ctx *Over_clauseContext) {}
|
||||
|
||||
// ExitOver_clause is called when production over_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOver_clause(ctx *Over_clauseContext) {}
|
||||
|
||||
// EnterFrame_spec is called when production frame_spec is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFrame_spec(ctx *Frame_specContext) {}
|
||||
|
||||
// ExitFrame_spec is called when production frame_spec is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFrame_spec(ctx *Frame_specContext) {}
|
||||
|
||||
// EnterFrame_clause is called when production frame_clause is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFrame_clause(ctx *Frame_clauseContext) {}
|
||||
|
||||
// ExitFrame_clause is called when production frame_clause is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFrame_clause(ctx *Frame_clauseContext) {}
|
||||
|
||||
// EnterSimple_function_invocation is called when production simple_function_invocation is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSimple_function_invocation(ctx *Simple_function_invocationContext) {
|
||||
}
|
||||
|
||||
// ExitSimple_function_invocation is called when production simple_function_invocation is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSimple_function_invocation(ctx *Simple_function_invocationContext) {
|
||||
}
|
||||
|
||||
// EnterAggregate_function_invocation is called when production aggregate_function_invocation is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {
|
||||
}
|
||||
|
||||
// ExitAggregate_function_invocation is called when production aggregate_function_invocation is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {
|
||||
}
|
||||
|
||||
// EnterWindow_function_invocation is called when production window_function_invocation is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterWindow_function_invocation(ctx *Window_function_invocationContext) {
|
||||
}
|
||||
|
||||
// ExitWindow_function_invocation is called when production window_function_invocation is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitWindow_function_invocation(ctx *Window_function_invocationContext) {
|
||||
}
|
||||
|
||||
// EnterCommon_table_stmt is called when production common_table_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCommon_table_stmt(ctx *Common_table_stmtContext) {}
|
||||
|
||||
// ExitCommon_table_stmt is called when production common_table_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCommon_table_stmt(ctx *Common_table_stmtContext) {}
|
||||
|
||||
// EnterOrder_by_stmt is called when production order_by_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOrder_by_stmt(ctx *Order_by_stmtContext) {}
|
||||
|
||||
// ExitOrder_by_stmt is called when production order_by_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOrder_by_stmt(ctx *Order_by_stmtContext) {}
|
||||
|
||||
// EnterLimit_stmt is called when production limit_stmt is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterLimit_stmt(ctx *Limit_stmtContext) {}
|
||||
|
||||
// ExitLimit_stmt is called when production limit_stmt is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitLimit_stmt(ctx *Limit_stmtContext) {}
|
||||
|
||||
// EnterOrdering_term is called when production ordering_term is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOrdering_term(ctx *Ordering_termContext) {}
|
||||
|
||||
// ExitOrdering_term is called when production ordering_term is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOrdering_term(ctx *Ordering_termContext) {}
|
||||
|
||||
// EnterAsc_desc is called when production asc_desc is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAsc_desc(ctx *Asc_descContext) {}
|
||||
|
||||
// ExitAsc_desc is called when production asc_desc is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAsc_desc(ctx *Asc_descContext) {}
|
||||
|
||||
// EnterFrame_left is called when production frame_left is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFrame_left(ctx *Frame_leftContext) {}
|
||||
|
||||
// ExitFrame_left is called when production frame_left is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFrame_left(ctx *Frame_leftContext) {}
|
||||
|
||||
// EnterFrame_right is called when production frame_right is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFrame_right(ctx *Frame_rightContext) {}
|
||||
|
||||
// ExitFrame_right is called when production frame_right is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFrame_right(ctx *Frame_rightContext) {}
|
||||
|
||||
// EnterFrame_single is called when production frame_single is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFrame_single(ctx *Frame_singleContext) {}
|
||||
|
||||
// ExitFrame_single is called when production frame_single is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFrame_single(ctx *Frame_singleContext) {}
|
||||
|
||||
// EnterWindow_function is called when production window_function is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterWindow_function(ctx *Window_functionContext) {}
|
||||
|
||||
// ExitWindow_function is called when production window_function is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitWindow_function(ctx *Window_functionContext) {}
|
||||
|
||||
// EnterOffset is called when production offset is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOffset(ctx *OffsetContext) {}
|
||||
|
||||
// ExitOffset is called when production offset is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOffset(ctx *OffsetContext) {}
|
||||
|
||||
// EnterDefault_value is called when production default_value is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterDefault_value(ctx *Default_valueContext) {}
|
||||
|
||||
// ExitDefault_value is called when production default_value is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitDefault_value(ctx *Default_valueContext) {}
|
||||
|
||||
// EnterPartition_by is called when production partition_by is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterPartition_by(ctx *Partition_byContext) {}
|
||||
|
||||
// ExitPartition_by is called when production partition_by is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitPartition_by(ctx *Partition_byContext) {}
|
||||
|
||||
// EnterOrder_by_expr is called when production order_by_expr is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOrder_by_expr(ctx *Order_by_exprContext) {}
|
||||
|
||||
// ExitOrder_by_expr is called when production order_by_expr is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOrder_by_expr(ctx *Order_by_exprContext) {}
|
||||
|
||||
// EnterOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}
|
||||
|
||||
// ExitOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}
|
||||
|
||||
// EnterExpr_asc_desc is called when production expr_asc_desc is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterExpr_asc_desc(ctx *Expr_asc_descContext) {}
|
||||
|
||||
// ExitExpr_asc_desc is called when production expr_asc_desc is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitExpr_asc_desc(ctx *Expr_asc_descContext) {}
|
||||
|
||||
// EnterInitial_select is called when production initial_select is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterInitial_select(ctx *Initial_selectContext) {}
|
||||
|
||||
// ExitInitial_select is called when production initial_select is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitInitial_select(ctx *Initial_selectContext) {}
|
||||
|
||||
// EnterRecursive_select is called when production recursive_select is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterRecursive_select(ctx *Recursive_selectContext) {}
|
||||
|
||||
// ExitRecursive_select is called when production recursive_select is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitRecursive_select(ctx *Recursive_selectContext) {}
|
||||
|
||||
// EnterUnary_operator is called when production unary_operator is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterUnary_operator(ctx *Unary_operatorContext) {}
|
||||
|
||||
// ExitUnary_operator is called when production unary_operator is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitUnary_operator(ctx *Unary_operatorContext) {}
|
||||
|
||||
// EnterError_message is called when production error_message is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterError_message(ctx *Error_messageContext) {}
|
||||
|
||||
// ExitError_message is called when production error_message is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitError_message(ctx *Error_messageContext) {}
|
||||
|
||||
// EnterModule_argument is called when production module_argument is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterModule_argument(ctx *Module_argumentContext) {}
|
||||
|
||||
// ExitModule_argument is called when production module_argument is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitModule_argument(ctx *Module_argumentContext) {}
|
||||
|
||||
// EnterColumn_alias is called when production column_alias is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterColumn_alias(ctx *Column_aliasContext) {}
|
||||
|
||||
// ExitColumn_alias is called when production column_alias is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitColumn_alias(ctx *Column_aliasContext) {}
|
||||
|
||||
// EnterKeyword is called when production keyword is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterKeyword(ctx *KeywordContext) {}
|
||||
|
||||
// ExitKeyword is called when production keyword is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitKeyword(ctx *KeywordContext) {}
|
||||
|
||||
// EnterName is called when production name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterName(ctx *NameContext) {}
|
||||
|
||||
// ExitName is called when production name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitName(ctx *NameContext) {}
|
||||
|
||||
// EnterFunction_name is called when production function_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFunction_name(ctx *Function_nameContext) {}
|
||||
|
||||
// ExitFunction_name is called when production function_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFunction_name(ctx *Function_nameContext) {}
|
||||
|
||||
// EnterSchema_name is called when production schema_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSchema_name(ctx *Schema_nameContext) {}
|
||||
|
||||
// ExitSchema_name is called when production schema_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSchema_name(ctx *Schema_nameContext) {}
|
||||
|
||||
// EnterTable_name is called when production table_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_name(ctx *Table_nameContext) {}
|
||||
|
||||
// ExitTable_name is called when production table_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_name(ctx *Table_nameContext) {}
|
||||
|
||||
// EnterTable_or_index_name is called when production table_or_index_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_or_index_name(ctx *Table_or_index_nameContext) {}
|
||||
|
||||
// ExitTable_or_index_name is called when production table_or_index_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_or_index_name(ctx *Table_or_index_nameContext) {}
|
||||
|
||||
// EnterColumn_name is called when production column_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterColumn_name(ctx *Column_nameContext) {}
|
||||
|
||||
// ExitColumn_name is called when production column_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitColumn_name(ctx *Column_nameContext) {}
|
||||
|
||||
// EnterCollation_name is called when production collation_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterCollation_name(ctx *Collation_nameContext) {}
|
||||
|
||||
// ExitCollation_name is called when production collation_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitCollation_name(ctx *Collation_nameContext) {}
|
||||
|
||||
// EnterForeign_table is called when production foreign_table is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterForeign_table(ctx *Foreign_tableContext) {}
|
||||
|
||||
// ExitForeign_table is called when production foreign_table is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitForeign_table(ctx *Foreign_tableContext) {}
|
||||
|
||||
// EnterIndex_name is called when production index_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterIndex_name(ctx *Index_nameContext) {}
|
||||
|
||||
// ExitIndex_name is called when production index_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitIndex_name(ctx *Index_nameContext) {}
|
||||
|
||||
// EnterTrigger_name is called when production trigger_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTrigger_name(ctx *Trigger_nameContext) {}
|
||||
|
||||
// ExitTrigger_name is called when production trigger_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTrigger_name(ctx *Trigger_nameContext) {}
|
||||
|
||||
// EnterView_name is called when production view_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterView_name(ctx *View_nameContext) {}
|
||||
|
||||
// ExitView_name is called when production view_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitView_name(ctx *View_nameContext) {}
|
||||
|
||||
// EnterModule_name is called when production module_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterModule_name(ctx *Module_nameContext) {}
|
||||
|
||||
// ExitModule_name is called when production module_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitModule_name(ctx *Module_nameContext) {}
|
||||
|
||||
// EnterPragma_name is called when production pragma_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterPragma_name(ctx *Pragma_nameContext) {}
|
||||
|
||||
// ExitPragma_name is called when production pragma_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitPragma_name(ctx *Pragma_nameContext) {}
|
||||
|
||||
// EnterSavepoint_name is called when production savepoint_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSavepoint_name(ctx *Savepoint_nameContext) {}
|
||||
|
||||
// ExitSavepoint_name is called when production savepoint_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSavepoint_name(ctx *Savepoint_nameContext) {}
|
||||
|
||||
// EnterTable_alias is called when production table_alias is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_alias(ctx *Table_aliasContext) {}
|
||||
|
||||
// ExitTable_alias is called when production table_alias is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_alias(ctx *Table_aliasContext) {}
|
||||
|
||||
// EnterTransaction_name is called when production transaction_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTransaction_name(ctx *Transaction_nameContext) {}
|
||||
|
||||
// ExitTransaction_name is called when production transaction_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTransaction_name(ctx *Transaction_nameContext) {}
|
||||
|
||||
// EnterWindow_name is called when production window_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterWindow_name(ctx *Window_nameContext) {}
|
||||
|
||||
// ExitWindow_name is called when production window_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitWindow_name(ctx *Window_nameContext) {}
|
||||
|
||||
// EnterAlias is called when production alias is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAlias(ctx *AliasContext) {}
|
||||
|
||||
// ExitAlias is called when production alias is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAlias(ctx *AliasContext) {}
|
||||
|
||||
// EnterFilename is called when production filename is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterFilename(ctx *FilenameContext) {}
|
||||
|
||||
// ExitFilename is called when production filename is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitFilename(ctx *FilenameContext) {}
|
||||
|
||||
// EnterBase_window_name is called when production base_window_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterBase_window_name(ctx *Base_window_nameContext) {}
|
||||
|
||||
// ExitBase_window_name is called when production base_window_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitBase_window_name(ctx *Base_window_nameContext) {}
|
||||
|
||||
// EnterSimple_func is called when production simple_func is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterSimple_func(ctx *Simple_funcContext) {}
|
||||
|
||||
// ExitSimple_func is called when production simple_func is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitSimple_func(ctx *Simple_funcContext) {}
|
||||
|
||||
// EnterAggregate_func is called when production aggregate_func is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAggregate_func(ctx *Aggregate_funcContext) {}
|
||||
|
||||
// ExitAggregate_func is called when production aggregate_func is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAggregate_func(ctx *Aggregate_funcContext) {}
|
||||
|
||||
// EnterTable_function_name is called when production table_function_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterTable_function_name(ctx *Table_function_nameContext) {}
|
||||
|
||||
// ExitTable_function_name is called when production table_function_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitTable_function_name(ctx *Table_function_nameContext) {}
|
||||
|
||||
// EnterAny_name is called when production any_name is entered.
|
||||
func (s *BaseSQLiteParserListener) EnterAny_name(ctx *Any_nameContext) {}
|
||||
|
||||
// ExitAny_name is called when production any_name is exited.
|
||||
func (s *BaseSQLiteParserListener) ExitAny_name(ctx *Any_nameContext) {}
|
@ -0,0 +1,460 @@
|
||||
// Code generated from SQLiteParser.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package sqlite // SQLiteParser
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
type BaseSQLiteParserVisitor struct {
|
||||
*antlr.BaseParseTreeVisitor
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitParse(ctx *ParseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSql_stmt(ctx *Sql_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAttach_stmt(ctx *Attach_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitBegin_stmt(ctx *Begin_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCommit_stmt(ctx *Commit_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitRollback_stmt(ctx *Rollback_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitRelease_stmt(ctx *Release_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitIndexed_column(ctx *Indexed_columnContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitColumn_def(ctx *Column_defContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitType_name(ctx *Type_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitColumn_constraint(ctx *Column_constraintContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSigned_number(ctx *Signed_numberContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_constraint(ctx *Table_constraintContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitConflict_clause(ctx *Conflict_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitWith_clause(ctx *With_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCte_table_name(ctx *Cte_table_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitRecursive_cte(ctx *Recursive_cteContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCommon_table_expression(ctx *Common_table_expressionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitDelete_stmt(ctx *Delete_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitDetach_stmt(ctx *Detach_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitDrop_stmt(ctx *Drop_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitExpr(ctx *ExprContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitRaise_function(ctx *Raise_functionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitLiteral_value(ctx *Literal_valueContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitValue_row(ctx *Value_rowContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitValues_clause(ctx *Values_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitInsert_stmt(ctx *Insert_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitReturning_clause(ctx *Returning_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitUpsert_clause(ctx *Upsert_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitPragma_stmt(ctx *Pragma_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitPragma_value(ctx *Pragma_valueContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitReindex_stmt(ctx *Reindex_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSelect_stmt(ctx *Select_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitJoin_clause(ctx *Join_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSelect_core(ctx *Select_coreContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitResult_column(ctx *Result_columnContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitJoin_operator(ctx *Join_operatorContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitJoin_constraint(ctx *Join_constraintContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCompound_operator(ctx *Compound_operatorContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitUpdate_stmt(ctx *Update_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitColumn_name_list(ctx *Column_name_listContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitQualified_table_name(ctx *Qualified_table_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFilter_clause(ctx *Filter_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitWindow_defn(ctx *Window_defnContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOver_clause(ctx *Over_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFrame_spec(ctx *Frame_specContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFrame_clause(ctx *Frame_clauseContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitLimit_stmt(ctx *Limit_stmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOrdering_term(ctx *Ordering_termContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAsc_desc(ctx *Asc_descContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFrame_left(ctx *Frame_leftContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFrame_right(ctx *Frame_rightContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFrame_single(ctx *Frame_singleContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitWindow_function(ctx *Window_functionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOffset(ctx *OffsetContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitDefault_value(ctx *Default_valueContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitPartition_by(ctx *Partition_byContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOrder_by_expr(ctx *Order_by_exprContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitInitial_select(ctx *Initial_selectContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitRecursive_select(ctx *Recursive_selectContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitUnary_operator(ctx *Unary_operatorContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitError_message(ctx *Error_messageContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitModule_argument(ctx *Module_argumentContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitColumn_alias(ctx *Column_aliasContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitKeyword(ctx *KeywordContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitName(ctx *NameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFunction_name(ctx *Function_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSchema_name(ctx *Schema_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_name(ctx *Table_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitColumn_name(ctx *Column_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitCollation_name(ctx *Collation_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitForeign_table(ctx *Foreign_tableContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitIndex_name(ctx *Index_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTrigger_name(ctx *Trigger_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitView_name(ctx *View_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitModule_name(ctx *Module_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitPragma_name(ctx *Pragma_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSavepoint_name(ctx *Savepoint_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_alias(ctx *Table_aliasContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTransaction_name(ctx *Transaction_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitWindow_name(ctx *Window_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAlias(ctx *AliasContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitFilename(ctx *FilenameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitBase_window_name(ctx *Base_window_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitSimple_func(ctx *Simple_funcContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAggregate_func(ctx *Aggregate_funcContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitTable_function_name(ctx *Table_function_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseSQLiteParserVisitor) VisitAny_name(ctx *Any_nameContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
@ -0,0 +1,687 @@
|
||||
// Code generated from SQLiteParser.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package sqlite // SQLiteParser
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
// SQLiteParserListener is a complete listener for a parse tree produced by SQLiteParser.
|
||||
type SQLiteParserListener interface {
|
||||
antlr.ParseTreeListener
|
||||
|
||||
// EnterParse is called when entering the parse production.
|
||||
EnterParse(c *ParseContext)
|
||||
|
||||
// EnterSql_stmt_list is called when entering the sql_stmt_list production.
|
||||
EnterSql_stmt_list(c *Sql_stmt_listContext)
|
||||
|
||||
// EnterSql_stmt is called when entering the sql_stmt production.
|
||||
EnterSql_stmt(c *Sql_stmtContext)
|
||||
|
||||
// EnterAlter_table_stmt is called when entering the alter_table_stmt production.
|
||||
EnterAlter_table_stmt(c *Alter_table_stmtContext)
|
||||
|
||||
// EnterAnalyze_stmt is called when entering the analyze_stmt production.
|
||||
EnterAnalyze_stmt(c *Analyze_stmtContext)
|
||||
|
||||
// EnterAttach_stmt is called when entering the attach_stmt production.
|
||||
EnterAttach_stmt(c *Attach_stmtContext)
|
||||
|
||||
// EnterBegin_stmt is called when entering the begin_stmt production.
|
||||
EnterBegin_stmt(c *Begin_stmtContext)
|
||||
|
||||
// EnterCommit_stmt is called when entering the commit_stmt production.
|
||||
EnterCommit_stmt(c *Commit_stmtContext)
|
||||
|
||||
// EnterRollback_stmt is called when entering the rollback_stmt production.
|
||||
EnterRollback_stmt(c *Rollback_stmtContext)
|
||||
|
||||
// EnterSavepoint_stmt is called when entering the savepoint_stmt production.
|
||||
EnterSavepoint_stmt(c *Savepoint_stmtContext)
|
||||
|
||||
// EnterRelease_stmt is called when entering the release_stmt production.
|
||||
EnterRelease_stmt(c *Release_stmtContext)
|
||||
|
||||
// EnterCreate_index_stmt is called when entering the create_index_stmt production.
|
||||
EnterCreate_index_stmt(c *Create_index_stmtContext)
|
||||
|
||||
// EnterIndexed_column is called when entering the indexed_column production.
|
||||
EnterIndexed_column(c *Indexed_columnContext)
|
||||
|
||||
// EnterCreate_table_stmt is called when entering the create_table_stmt production.
|
||||
EnterCreate_table_stmt(c *Create_table_stmtContext)
|
||||
|
||||
// EnterColumn_def is called when entering the column_def production.
|
||||
EnterColumn_def(c *Column_defContext)
|
||||
|
||||
// EnterType_name is called when entering the type_name production.
|
||||
EnterType_name(c *Type_nameContext)
|
||||
|
||||
// EnterColumn_constraint is called when entering the column_constraint production.
|
||||
EnterColumn_constraint(c *Column_constraintContext)
|
||||
|
||||
// EnterSigned_number is called when entering the signed_number production.
|
||||
EnterSigned_number(c *Signed_numberContext)
|
||||
|
||||
// EnterTable_constraint is called when entering the table_constraint production.
|
||||
EnterTable_constraint(c *Table_constraintContext)
|
||||
|
||||
// EnterForeign_key_clause is called when entering the foreign_key_clause production.
|
||||
EnterForeign_key_clause(c *Foreign_key_clauseContext)
|
||||
|
||||
// EnterConflict_clause is called when entering the conflict_clause production.
|
||||
EnterConflict_clause(c *Conflict_clauseContext)
|
||||
|
||||
// EnterCreate_trigger_stmt is called when entering the create_trigger_stmt production.
|
||||
EnterCreate_trigger_stmt(c *Create_trigger_stmtContext)
|
||||
|
||||
// EnterCreate_view_stmt is called when entering the create_view_stmt production.
|
||||
EnterCreate_view_stmt(c *Create_view_stmtContext)
|
||||
|
||||
// EnterCreate_virtual_table_stmt is called when entering the create_virtual_table_stmt production.
|
||||
EnterCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)
|
||||
|
||||
// EnterWith_clause is called when entering the with_clause production.
|
||||
EnterWith_clause(c *With_clauseContext)
|
||||
|
||||
// EnterCte_table_name is called when entering the cte_table_name production.
|
||||
EnterCte_table_name(c *Cte_table_nameContext)
|
||||
|
||||
// EnterRecursive_cte is called when entering the recursive_cte production.
|
||||
EnterRecursive_cte(c *Recursive_cteContext)
|
||||
|
||||
// EnterCommon_table_expression is called when entering the common_table_expression production.
|
||||
EnterCommon_table_expression(c *Common_table_expressionContext)
|
||||
|
||||
// EnterDelete_stmt is called when entering the delete_stmt production.
|
||||
EnterDelete_stmt(c *Delete_stmtContext)
|
||||
|
||||
// EnterDelete_stmt_limited is called when entering the delete_stmt_limited production.
|
||||
EnterDelete_stmt_limited(c *Delete_stmt_limitedContext)
|
||||
|
||||
// EnterDetach_stmt is called when entering the detach_stmt production.
|
||||
EnterDetach_stmt(c *Detach_stmtContext)
|
||||
|
||||
// EnterDrop_stmt is called when entering the drop_stmt production.
|
||||
EnterDrop_stmt(c *Drop_stmtContext)
|
||||
|
||||
// EnterExpr is called when entering the expr production.
|
||||
EnterExpr(c *ExprContext)
|
||||
|
||||
// EnterRaise_function is called when entering the raise_function production.
|
||||
EnterRaise_function(c *Raise_functionContext)
|
||||
|
||||
// EnterLiteral_value is called when entering the literal_value production.
|
||||
EnterLiteral_value(c *Literal_valueContext)
|
||||
|
||||
// EnterValue_row is called when entering the value_row production.
|
||||
EnterValue_row(c *Value_rowContext)
|
||||
|
||||
// EnterValues_clause is called when entering the values_clause production.
|
||||
EnterValues_clause(c *Values_clauseContext)
|
||||
|
||||
// EnterInsert_stmt is called when entering the insert_stmt production.
|
||||
EnterInsert_stmt(c *Insert_stmtContext)
|
||||
|
||||
// EnterReturning_clause is called when entering the returning_clause production.
|
||||
EnterReturning_clause(c *Returning_clauseContext)
|
||||
|
||||
// EnterUpsert_clause is called when entering the upsert_clause production.
|
||||
EnterUpsert_clause(c *Upsert_clauseContext)
|
||||
|
||||
// EnterPragma_stmt is called when entering the pragma_stmt production.
|
||||
EnterPragma_stmt(c *Pragma_stmtContext)
|
||||
|
||||
// EnterPragma_value is called when entering the pragma_value production.
|
||||
EnterPragma_value(c *Pragma_valueContext)
|
||||
|
||||
// EnterReindex_stmt is called when entering the reindex_stmt production.
|
||||
EnterReindex_stmt(c *Reindex_stmtContext)
|
||||
|
||||
// EnterSelect_stmt is called when entering the select_stmt production.
|
||||
EnterSelect_stmt(c *Select_stmtContext)
|
||||
|
||||
// EnterJoin_clause is called when entering the join_clause production.
|
||||
EnterJoin_clause(c *Join_clauseContext)
|
||||
|
||||
// EnterSelect_core is called when entering the select_core production.
|
||||
EnterSelect_core(c *Select_coreContext)
|
||||
|
||||
// EnterFactored_select_stmt is called when entering the factored_select_stmt production.
|
||||
EnterFactored_select_stmt(c *Factored_select_stmtContext)
|
||||
|
||||
// EnterSimple_select_stmt is called when entering the simple_select_stmt production.
|
||||
EnterSimple_select_stmt(c *Simple_select_stmtContext)
|
||||
|
||||
// EnterCompound_select_stmt is called when entering the compound_select_stmt production.
|
||||
EnterCompound_select_stmt(c *Compound_select_stmtContext)
|
||||
|
||||
// EnterTable_or_subquery is called when entering the table_or_subquery production.
|
||||
EnterTable_or_subquery(c *Table_or_subqueryContext)
|
||||
|
||||
// EnterResult_column is called when entering the result_column production.
|
||||
EnterResult_column(c *Result_columnContext)
|
||||
|
||||
// EnterJoin_operator is called when entering the join_operator production.
|
||||
EnterJoin_operator(c *Join_operatorContext)
|
||||
|
||||
// EnterJoin_constraint is called when entering the join_constraint production.
|
||||
EnterJoin_constraint(c *Join_constraintContext)
|
||||
|
||||
// EnterCompound_operator is called when entering the compound_operator production.
|
||||
EnterCompound_operator(c *Compound_operatorContext)
|
||||
|
||||
// EnterUpdate_stmt is called when entering the update_stmt production.
|
||||
EnterUpdate_stmt(c *Update_stmtContext)
|
||||
|
||||
// EnterColumn_name_list is called when entering the column_name_list production.
|
||||
EnterColumn_name_list(c *Column_name_listContext)
|
||||
|
||||
// EnterUpdate_stmt_limited is called when entering the update_stmt_limited production.
|
||||
EnterUpdate_stmt_limited(c *Update_stmt_limitedContext)
|
||||
|
||||
// EnterQualified_table_name is called when entering the qualified_table_name production.
|
||||
EnterQualified_table_name(c *Qualified_table_nameContext)
|
||||
|
||||
// EnterVacuum_stmt is called when entering the vacuum_stmt production.
|
||||
EnterVacuum_stmt(c *Vacuum_stmtContext)
|
||||
|
||||
// EnterFilter_clause is called when entering the filter_clause production.
|
||||
EnterFilter_clause(c *Filter_clauseContext)
|
||||
|
||||
// EnterWindow_defn is called when entering the window_defn production.
|
||||
EnterWindow_defn(c *Window_defnContext)
|
||||
|
||||
// EnterOver_clause is called when entering the over_clause production.
|
||||
EnterOver_clause(c *Over_clauseContext)
|
||||
|
||||
// EnterFrame_spec is called when entering the frame_spec production.
|
||||
EnterFrame_spec(c *Frame_specContext)
|
||||
|
||||
// EnterFrame_clause is called when entering the frame_clause production.
|
||||
EnterFrame_clause(c *Frame_clauseContext)
|
||||
|
||||
// EnterSimple_function_invocation is called when entering the simple_function_invocation production.
|
||||
EnterSimple_function_invocation(c *Simple_function_invocationContext)
|
||||
|
||||
// EnterAggregate_function_invocation is called when entering the aggregate_function_invocation production.
|
||||
EnterAggregate_function_invocation(c *Aggregate_function_invocationContext)
|
||||
|
||||
// EnterWindow_function_invocation is called when entering the window_function_invocation production.
|
||||
EnterWindow_function_invocation(c *Window_function_invocationContext)
|
||||
|
||||
// EnterCommon_table_stmt is called when entering the common_table_stmt production.
|
||||
EnterCommon_table_stmt(c *Common_table_stmtContext)
|
||||
|
||||
// EnterOrder_by_stmt is called when entering the order_by_stmt production.
|
||||
EnterOrder_by_stmt(c *Order_by_stmtContext)
|
||||
|
||||
// EnterLimit_stmt is called when entering the limit_stmt production.
|
||||
EnterLimit_stmt(c *Limit_stmtContext)
|
||||
|
||||
// EnterOrdering_term is called when entering the ordering_term production.
|
||||
EnterOrdering_term(c *Ordering_termContext)
|
||||
|
||||
// EnterAsc_desc is called when entering the asc_desc production.
|
||||
EnterAsc_desc(c *Asc_descContext)
|
||||
|
||||
// EnterFrame_left is called when entering the frame_left production.
|
||||
EnterFrame_left(c *Frame_leftContext)
|
||||
|
||||
// EnterFrame_right is called when entering the frame_right production.
|
||||
EnterFrame_right(c *Frame_rightContext)
|
||||
|
||||
// EnterFrame_single is called when entering the frame_single production.
|
||||
EnterFrame_single(c *Frame_singleContext)
|
||||
|
||||
// EnterWindow_function is called when entering the window_function production.
|
||||
EnterWindow_function(c *Window_functionContext)
|
||||
|
||||
// EnterOffset is called when entering the offset production.
|
||||
EnterOffset(c *OffsetContext)
|
||||
|
||||
// EnterDefault_value is called when entering the default_value production.
|
||||
EnterDefault_value(c *Default_valueContext)
|
||||
|
||||
// EnterPartition_by is called when entering the partition_by production.
|
||||
EnterPartition_by(c *Partition_byContext)
|
||||
|
||||
// EnterOrder_by_expr is called when entering the order_by_expr production.
|
||||
EnterOrder_by_expr(c *Order_by_exprContext)
|
||||
|
||||
// EnterOrder_by_expr_asc_desc is called when entering the order_by_expr_asc_desc production.
|
||||
EnterOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)
|
||||
|
||||
// EnterExpr_asc_desc is called when entering the expr_asc_desc production.
|
||||
EnterExpr_asc_desc(c *Expr_asc_descContext)
|
||||
|
||||
// EnterInitial_select is called when entering the initial_select production.
|
||||
EnterInitial_select(c *Initial_selectContext)
|
||||
|
||||
// EnterRecursive_select is called when entering the recursive_select production.
|
||||
EnterRecursive_select(c *Recursive_selectContext)
|
||||
|
||||
// EnterUnary_operator is called when entering the unary_operator production.
|
||||
EnterUnary_operator(c *Unary_operatorContext)
|
||||
|
||||
// EnterError_message is called when entering the error_message production.
|
||||
EnterError_message(c *Error_messageContext)
|
||||
|
||||
// EnterModule_argument is called when entering the module_argument production.
|
||||
EnterModule_argument(c *Module_argumentContext)
|
||||
|
||||
// EnterColumn_alias is called when entering the column_alias production.
|
||||
EnterColumn_alias(c *Column_aliasContext)
|
||||
|
||||
// EnterKeyword is called when entering the keyword production.
|
||||
EnterKeyword(c *KeywordContext)
|
||||
|
||||
// EnterName is called when entering the name production.
|
||||
EnterName(c *NameContext)
|
||||
|
||||
// EnterFunction_name is called when entering the function_name production.
|
||||
EnterFunction_name(c *Function_nameContext)
|
||||
|
||||
// EnterSchema_name is called when entering the schema_name production.
|
||||
EnterSchema_name(c *Schema_nameContext)
|
||||
|
||||
// EnterTable_name is called when entering the table_name production.
|
||||
EnterTable_name(c *Table_nameContext)
|
||||
|
||||
// EnterTable_or_index_name is called when entering the table_or_index_name production.
|
||||
EnterTable_or_index_name(c *Table_or_index_nameContext)
|
||||
|
||||
// EnterColumn_name is called when entering the column_name production.
|
||||
EnterColumn_name(c *Column_nameContext)
|
||||
|
||||
// EnterCollation_name is called when entering the collation_name production.
|
||||
EnterCollation_name(c *Collation_nameContext)
|
||||
|
||||
// EnterForeign_table is called when entering the foreign_table production.
|
||||
EnterForeign_table(c *Foreign_tableContext)
|
||||
|
||||
// EnterIndex_name is called when entering the index_name production.
|
||||
EnterIndex_name(c *Index_nameContext)
|
||||
|
||||
// EnterTrigger_name is called when entering the trigger_name production.
|
||||
EnterTrigger_name(c *Trigger_nameContext)
|
||||
|
||||
// EnterView_name is called when entering the view_name production.
|
||||
EnterView_name(c *View_nameContext)
|
||||
|
||||
// EnterModule_name is called when entering the module_name production.
|
||||
EnterModule_name(c *Module_nameContext)
|
||||
|
||||
// EnterPragma_name is called when entering the pragma_name production.
|
||||
EnterPragma_name(c *Pragma_nameContext)
|
||||
|
||||
// EnterSavepoint_name is called when entering the savepoint_name production.
|
||||
EnterSavepoint_name(c *Savepoint_nameContext)
|
||||
|
||||
// EnterTable_alias is called when entering the table_alias production.
|
||||
EnterTable_alias(c *Table_aliasContext)
|
||||
|
||||
// EnterTransaction_name is called when entering the transaction_name production.
|
||||
EnterTransaction_name(c *Transaction_nameContext)
|
||||
|
||||
// EnterWindow_name is called when entering the window_name production.
|
||||
EnterWindow_name(c *Window_nameContext)
|
||||
|
||||
// EnterAlias is called when entering the alias production.
|
||||
EnterAlias(c *AliasContext)
|
||||
|
||||
// EnterFilename is called when entering the filename production.
|
||||
EnterFilename(c *FilenameContext)
|
||||
|
||||
// EnterBase_window_name is called when entering the base_window_name production.
|
||||
EnterBase_window_name(c *Base_window_nameContext)
|
||||
|
||||
// EnterSimple_func is called when entering the simple_func production.
|
||||
EnterSimple_func(c *Simple_funcContext)
|
||||
|
||||
// EnterAggregate_func is called when entering the aggregate_func production.
|
||||
EnterAggregate_func(c *Aggregate_funcContext)
|
||||
|
||||
// EnterTable_function_name is called when entering the table_function_name production.
|
||||
EnterTable_function_name(c *Table_function_nameContext)
|
||||
|
||||
// EnterAny_name is called when entering the any_name production.
|
||||
EnterAny_name(c *Any_nameContext)
|
||||
|
||||
// ExitParse is called when exiting the parse production.
|
||||
ExitParse(c *ParseContext)
|
||||
|
||||
// ExitSql_stmt_list is called when exiting the sql_stmt_list production.
|
||||
ExitSql_stmt_list(c *Sql_stmt_listContext)
|
||||
|
||||
// ExitSql_stmt is called when exiting the sql_stmt production.
|
||||
ExitSql_stmt(c *Sql_stmtContext)
|
||||
|
||||
// ExitAlter_table_stmt is called when exiting the alter_table_stmt production.
|
||||
ExitAlter_table_stmt(c *Alter_table_stmtContext)
|
||||
|
||||
// ExitAnalyze_stmt is called when exiting the analyze_stmt production.
|
||||
ExitAnalyze_stmt(c *Analyze_stmtContext)
|
||||
|
||||
// ExitAttach_stmt is called when exiting the attach_stmt production.
|
||||
ExitAttach_stmt(c *Attach_stmtContext)
|
||||
|
||||
// ExitBegin_stmt is called when exiting the begin_stmt production.
|
||||
ExitBegin_stmt(c *Begin_stmtContext)
|
||||
|
||||
// ExitCommit_stmt is called when exiting the commit_stmt production.
|
||||
ExitCommit_stmt(c *Commit_stmtContext)
|
||||
|
||||
// ExitRollback_stmt is called when exiting the rollback_stmt production.
|
||||
ExitRollback_stmt(c *Rollback_stmtContext)
|
||||
|
||||
// ExitSavepoint_stmt is called when exiting the savepoint_stmt production.
|
||||
ExitSavepoint_stmt(c *Savepoint_stmtContext)
|
||||
|
||||
// ExitRelease_stmt is called when exiting the release_stmt production.
|
||||
ExitRelease_stmt(c *Release_stmtContext)
|
||||
|
||||
// ExitCreate_index_stmt is called when exiting the create_index_stmt production.
|
||||
ExitCreate_index_stmt(c *Create_index_stmtContext)
|
||||
|
||||
// ExitIndexed_column is called when exiting the indexed_column production.
|
||||
ExitIndexed_column(c *Indexed_columnContext)
|
||||
|
||||
// ExitCreate_table_stmt is called when exiting the create_table_stmt production.
|
||||
ExitCreate_table_stmt(c *Create_table_stmtContext)
|
||||
|
||||
// ExitColumn_def is called when exiting the column_def production.
|
||||
ExitColumn_def(c *Column_defContext)
|
||||
|
||||
// ExitType_name is called when exiting the type_name production.
|
||||
ExitType_name(c *Type_nameContext)
|
||||
|
||||
// ExitColumn_constraint is called when exiting the column_constraint production.
|
||||
ExitColumn_constraint(c *Column_constraintContext)
|
||||
|
||||
// ExitSigned_number is called when exiting the signed_number production.
|
||||
ExitSigned_number(c *Signed_numberContext)
|
||||
|
||||
// ExitTable_constraint is called when exiting the table_constraint production.
|
||||
ExitTable_constraint(c *Table_constraintContext)
|
||||
|
||||
// ExitForeign_key_clause is called when exiting the foreign_key_clause production.
|
||||
ExitForeign_key_clause(c *Foreign_key_clauseContext)
|
||||
|
||||
// ExitConflict_clause is called when exiting the conflict_clause production.
|
||||
ExitConflict_clause(c *Conflict_clauseContext)
|
||||
|
||||
// ExitCreate_trigger_stmt is called when exiting the create_trigger_stmt production.
|
||||
ExitCreate_trigger_stmt(c *Create_trigger_stmtContext)
|
||||
|
||||
// ExitCreate_view_stmt is called when exiting the create_view_stmt production.
|
||||
ExitCreate_view_stmt(c *Create_view_stmtContext)
|
||||
|
||||
// ExitCreate_virtual_table_stmt is called when exiting the create_virtual_table_stmt production.
|
||||
ExitCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)
|
||||
|
||||
// ExitWith_clause is called when exiting the with_clause production.
|
||||
ExitWith_clause(c *With_clauseContext)
|
||||
|
||||
// ExitCte_table_name is called when exiting the cte_table_name production.
|
||||
ExitCte_table_name(c *Cte_table_nameContext)
|
||||
|
||||
// ExitRecursive_cte is called when exiting the recursive_cte production.
|
||||
ExitRecursive_cte(c *Recursive_cteContext)
|
||||
|
||||
// ExitCommon_table_expression is called when exiting the common_table_expression production.
|
||||
ExitCommon_table_expression(c *Common_table_expressionContext)
|
||||
|
||||
// ExitDelete_stmt is called when exiting the delete_stmt production.
|
||||
ExitDelete_stmt(c *Delete_stmtContext)
|
||||
|
||||
// ExitDelete_stmt_limited is called when exiting the delete_stmt_limited production.
|
||||
ExitDelete_stmt_limited(c *Delete_stmt_limitedContext)
|
||||
|
||||
// ExitDetach_stmt is called when exiting the detach_stmt production.
|
||||
ExitDetach_stmt(c *Detach_stmtContext)
|
||||
|
||||
// ExitDrop_stmt is called when exiting the drop_stmt production.
|
||||
ExitDrop_stmt(c *Drop_stmtContext)
|
||||
|
||||
// ExitExpr is called when exiting the expr production.
|
||||
ExitExpr(c *ExprContext)
|
||||
|
||||
// ExitRaise_function is called when exiting the raise_function production.
|
||||
ExitRaise_function(c *Raise_functionContext)
|
||||
|
||||
// ExitLiteral_value is called when exiting the literal_value production.
|
||||
ExitLiteral_value(c *Literal_valueContext)
|
||||
|
||||
// ExitValue_row is called when exiting the value_row production.
|
||||
ExitValue_row(c *Value_rowContext)
|
||||
|
||||
// ExitValues_clause is called when exiting the values_clause production.
|
||||
ExitValues_clause(c *Values_clauseContext)
|
||||
|
||||
// ExitInsert_stmt is called when exiting the insert_stmt production.
|
||||
ExitInsert_stmt(c *Insert_stmtContext)
|
||||
|
||||
// ExitReturning_clause is called when exiting the returning_clause production.
|
||||
ExitReturning_clause(c *Returning_clauseContext)
|
||||
|
||||
// ExitUpsert_clause is called when exiting the upsert_clause production.
|
||||
ExitUpsert_clause(c *Upsert_clauseContext)
|
||||
|
||||
// ExitPragma_stmt is called when exiting the pragma_stmt production.
|
||||
ExitPragma_stmt(c *Pragma_stmtContext)
|
||||
|
||||
// ExitPragma_value is called when exiting the pragma_value production.
|
||||
ExitPragma_value(c *Pragma_valueContext)
|
||||
|
||||
// ExitReindex_stmt is called when exiting the reindex_stmt production.
|
||||
ExitReindex_stmt(c *Reindex_stmtContext)
|
||||
|
||||
// ExitSelect_stmt is called when exiting the select_stmt production.
|
||||
ExitSelect_stmt(c *Select_stmtContext)
|
||||
|
||||
// ExitJoin_clause is called when exiting the join_clause production.
|
||||
ExitJoin_clause(c *Join_clauseContext)
|
||||
|
||||
// ExitSelect_core is called when exiting the select_core production.
|
||||
ExitSelect_core(c *Select_coreContext)
|
||||
|
||||
// ExitFactored_select_stmt is called when exiting the factored_select_stmt production.
|
||||
ExitFactored_select_stmt(c *Factored_select_stmtContext)
|
||||
|
||||
// ExitSimple_select_stmt is called when exiting the simple_select_stmt production.
|
||||
ExitSimple_select_stmt(c *Simple_select_stmtContext)
|
||||
|
||||
// ExitCompound_select_stmt is called when exiting the compound_select_stmt production.
|
||||
ExitCompound_select_stmt(c *Compound_select_stmtContext)
|
||||
|
||||
// ExitTable_or_subquery is called when exiting the table_or_subquery production.
|
||||
ExitTable_or_subquery(c *Table_or_subqueryContext)
|
||||
|
||||
// ExitResult_column is called when exiting the result_column production.
|
||||
ExitResult_column(c *Result_columnContext)
|
||||
|
||||
// ExitJoin_operator is called when exiting the join_operator production.
|
||||
ExitJoin_operator(c *Join_operatorContext)
|
||||
|
||||
// ExitJoin_constraint is called when exiting the join_constraint production.
|
||||
ExitJoin_constraint(c *Join_constraintContext)
|
||||
|
||||
// ExitCompound_operator is called when exiting the compound_operator production.
|
||||
ExitCompound_operator(c *Compound_operatorContext)
|
||||
|
||||
// ExitUpdate_stmt is called when exiting the update_stmt production.
|
||||
ExitUpdate_stmt(c *Update_stmtContext)
|
||||
|
||||
// ExitColumn_name_list is called when exiting the column_name_list production.
|
||||
ExitColumn_name_list(c *Column_name_listContext)
|
||||
|
||||
// ExitUpdate_stmt_limited is called when exiting the update_stmt_limited production.
|
||||
ExitUpdate_stmt_limited(c *Update_stmt_limitedContext)
|
||||
|
||||
// ExitQualified_table_name is called when exiting the qualified_table_name production.
|
||||
ExitQualified_table_name(c *Qualified_table_nameContext)
|
||||
|
||||
// ExitVacuum_stmt is called when exiting the vacuum_stmt production.
|
||||
ExitVacuum_stmt(c *Vacuum_stmtContext)
|
||||
|
||||
// ExitFilter_clause is called when exiting the filter_clause production.
|
||||
ExitFilter_clause(c *Filter_clauseContext)
|
||||
|
||||
// ExitWindow_defn is called when exiting the window_defn production.
|
||||
ExitWindow_defn(c *Window_defnContext)
|
||||
|
||||
// ExitOver_clause is called when exiting the over_clause production.
|
||||
ExitOver_clause(c *Over_clauseContext)
|
||||
|
||||
// ExitFrame_spec is called when exiting the frame_spec production.
|
||||
ExitFrame_spec(c *Frame_specContext)
|
||||
|
||||
// ExitFrame_clause is called when exiting the frame_clause production.
|
||||
ExitFrame_clause(c *Frame_clauseContext)
|
||||
|
||||
// ExitSimple_function_invocation is called when exiting the simple_function_invocation production.
|
||||
ExitSimple_function_invocation(c *Simple_function_invocationContext)
|
||||
|
||||
// ExitAggregate_function_invocation is called when exiting the aggregate_function_invocation production.
|
||||
ExitAggregate_function_invocation(c *Aggregate_function_invocationContext)
|
||||
|
||||
// ExitWindow_function_invocation is called when exiting the window_function_invocation production.
|
||||
ExitWindow_function_invocation(c *Window_function_invocationContext)
|
||||
|
||||
// ExitCommon_table_stmt is called when exiting the common_table_stmt production.
|
||||
ExitCommon_table_stmt(c *Common_table_stmtContext)
|
||||
|
||||
// ExitOrder_by_stmt is called when exiting the order_by_stmt production.
|
||||
ExitOrder_by_stmt(c *Order_by_stmtContext)
|
||||
|
||||
// ExitLimit_stmt is called when exiting the limit_stmt production.
|
||||
ExitLimit_stmt(c *Limit_stmtContext)
|
||||
|
||||
// ExitOrdering_term is called when exiting the ordering_term production.
|
||||
ExitOrdering_term(c *Ordering_termContext)
|
||||
|
||||
// ExitAsc_desc is called when exiting the asc_desc production.
|
||||
ExitAsc_desc(c *Asc_descContext)
|
||||
|
||||
// ExitFrame_left is called when exiting the frame_left production.
|
||||
ExitFrame_left(c *Frame_leftContext)
|
||||
|
||||
// ExitFrame_right is called when exiting the frame_right production.
|
||||
ExitFrame_right(c *Frame_rightContext)
|
||||
|
||||
// ExitFrame_single is called when exiting the frame_single production.
|
||||
ExitFrame_single(c *Frame_singleContext)
|
||||
|
||||
// ExitWindow_function is called when exiting the window_function production.
|
||||
ExitWindow_function(c *Window_functionContext)
|
||||
|
||||
// ExitOffset is called when exiting the offset production.
|
||||
ExitOffset(c *OffsetContext)
|
||||
|
||||
// ExitDefault_value is called when exiting the default_value production.
|
||||
ExitDefault_value(c *Default_valueContext)
|
||||
|
||||
// ExitPartition_by is called when exiting the partition_by production.
|
||||
ExitPartition_by(c *Partition_byContext)
|
||||
|
||||
// ExitOrder_by_expr is called when exiting the order_by_expr production.
|
||||
ExitOrder_by_expr(c *Order_by_exprContext)
|
||||
|
||||
// ExitOrder_by_expr_asc_desc is called when exiting the order_by_expr_asc_desc production.
|
||||
ExitOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)
|
||||
|
||||
// ExitExpr_asc_desc is called when exiting the expr_asc_desc production.
|
||||
ExitExpr_asc_desc(c *Expr_asc_descContext)
|
||||
|
||||
// ExitInitial_select is called when exiting the initial_select production.
|
||||
ExitInitial_select(c *Initial_selectContext)
|
||||
|
||||
// ExitRecursive_select is called when exiting the recursive_select production.
|
||||
ExitRecursive_select(c *Recursive_selectContext)
|
||||
|
||||
// ExitUnary_operator is called when exiting the unary_operator production.
|
||||
ExitUnary_operator(c *Unary_operatorContext)
|
||||
|
||||
// ExitError_message is called when exiting the error_message production.
|
||||
ExitError_message(c *Error_messageContext)
|
||||
|
||||
// ExitModule_argument is called when exiting the module_argument production.
|
||||
ExitModule_argument(c *Module_argumentContext)
|
||||
|
||||
// ExitColumn_alias is called when exiting the column_alias production.
|
||||
ExitColumn_alias(c *Column_aliasContext)
|
||||
|
||||
// ExitKeyword is called when exiting the keyword production.
|
||||
ExitKeyword(c *KeywordContext)
|
||||
|
||||
// ExitName is called when exiting the name production.
|
||||
ExitName(c *NameContext)
|
||||
|
||||
// ExitFunction_name is called when exiting the function_name production.
|
||||
ExitFunction_name(c *Function_nameContext)
|
||||
|
||||
// ExitSchema_name is called when exiting the schema_name production.
|
||||
ExitSchema_name(c *Schema_nameContext)
|
||||
|
||||
// ExitTable_name is called when exiting the table_name production.
|
||||
ExitTable_name(c *Table_nameContext)
|
||||
|
||||
// ExitTable_or_index_name is called when exiting the table_or_index_name production.
|
||||
ExitTable_or_index_name(c *Table_or_index_nameContext)
|
||||
|
||||
// ExitColumn_name is called when exiting the column_name production.
|
||||
ExitColumn_name(c *Column_nameContext)
|
||||
|
||||
// ExitCollation_name is called when exiting the collation_name production.
|
||||
ExitCollation_name(c *Collation_nameContext)
|
||||
|
||||
// ExitForeign_table is called when exiting the foreign_table production.
|
||||
ExitForeign_table(c *Foreign_tableContext)
|
||||
|
||||
// ExitIndex_name is called when exiting the index_name production.
|
||||
ExitIndex_name(c *Index_nameContext)
|
||||
|
||||
// ExitTrigger_name is called when exiting the trigger_name production.
|
||||
ExitTrigger_name(c *Trigger_nameContext)
|
||||
|
||||
// ExitView_name is called when exiting the view_name production.
|
||||
ExitView_name(c *View_nameContext)
|
||||
|
||||
// ExitModule_name is called when exiting the module_name production.
|
||||
ExitModule_name(c *Module_nameContext)
|
||||
|
||||
// ExitPragma_name is called when exiting the pragma_name production.
|
||||
ExitPragma_name(c *Pragma_nameContext)
|
||||
|
||||
// ExitSavepoint_name is called when exiting the savepoint_name production.
|
||||
ExitSavepoint_name(c *Savepoint_nameContext)
|
||||
|
||||
// ExitTable_alias is called when exiting the table_alias production.
|
||||
ExitTable_alias(c *Table_aliasContext)
|
||||
|
||||
// ExitTransaction_name is called when exiting the transaction_name production.
|
||||
ExitTransaction_name(c *Transaction_nameContext)
|
||||
|
||||
// ExitWindow_name is called when exiting the window_name production.
|
||||
ExitWindow_name(c *Window_nameContext)
|
||||
|
||||
// ExitAlias is called when exiting the alias production.
|
||||
ExitAlias(c *AliasContext)
|
||||
|
||||
// ExitFilename is called when exiting the filename production.
|
||||
ExitFilename(c *FilenameContext)
|
||||
|
||||
// ExitBase_window_name is called when exiting the base_window_name production.
|
||||
ExitBase_window_name(c *Base_window_nameContext)
|
||||
|
||||
// ExitSimple_func is called when exiting the simple_func production.
|
||||
ExitSimple_func(c *Simple_funcContext)
|
||||
|
||||
// ExitAggregate_func is called when exiting the aggregate_func production.
|
||||
ExitAggregate_func(c *Aggregate_funcContext)
|
||||
|
||||
// ExitTable_function_name is called when exiting the table_function_name production.
|
||||
ExitTable_function_name(c *Table_function_nameContext)
|
||||
|
||||
// ExitAny_name is called when exiting the any_name production.
|
||||
ExitAny_name(c *Any_nameContext)
|
||||
}
|
@ -0,0 +1,348 @@
|
||||
// Code generated from SQLiteParser.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package sqlite // SQLiteParser
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
// A complete Visitor for a parse tree produced by SQLiteParser.
|
||||
type SQLiteParserVisitor interface {
|
||||
antlr.ParseTreeVisitor
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#parse.
|
||||
VisitParse(ctx *ParseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#sql_stmt_list.
|
||||
VisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#sql_stmt.
|
||||
VisitSql_stmt(ctx *Sql_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#alter_table_stmt.
|
||||
VisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#analyze_stmt.
|
||||
VisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#attach_stmt.
|
||||
VisitAttach_stmt(ctx *Attach_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#begin_stmt.
|
||||
VisitBegin_stmt(ctx *Begin_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#commit_stmt.
|
||||
VisitCommit_stmt(ctx *Commit_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#rollback_stmt.
|
||||
VisitRollback_stmt(ctx *Rollback_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#savepoint_stmt.
|
||||
VisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#release_stmt.
|
||||
VisitRelease_stmt(ctx *Release_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#create_index_stmt.
|
||||
VisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#indexed_column.
|
||||
VisitIndexed_column(ctx *Indexed_columnContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#create_table_stmt.
|
||||
VisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#column_def.
|
||||
VisitColumn_def(ctx *Column_defContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#type_name.
|
||||
VisitType_name(ctx *Type_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#column_constraint.
|
||||
VisitColumn_constraint(ctx *Column_constraintContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#signed_number.
|
||||
VisitSigned_number(ctx *Signed_numberContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_constraint.
|
||||
VisitTable_constraint(ctx *Table_constraintContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#foreign_key_clause.
|
||||
VisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#conflict_clause.
|
||||
VisitConflict_clause(ctx *Conflict_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#create_trigger_stmt.
|
||||
VisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#create_view_stmt.
|
||||
VisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#create_virtual_table_stmt.
|
||||
VisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#with_clause.
|
||||
VisitWith_clause(ctx *With_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#cte_table_name.
|
||||
VisitCte_table_name(ctx *Cte_table_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#recursive_cte.
|
||||
VisitRecursive_cte(ctx *Recursive_cteContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#common_table_expression.
|
||||
VisitCommon_table_expression(ctx *Common_table_expressionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#delete_stmt.
|
||||
VisitDelete_stmt(ctx *Delete_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#delete_stmt_limited.
|
||||
VisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#detach_stmt.
|
||||
VisitDetach_stmt(ctx *Detach_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#drop_stmt.
|
||||
VisitDrop_stmt(ctx *Drop_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#expr.
|
||||
VisitExpr(ctx *ExprContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#raise_function.
|
||||
VisitRaise_function(ctx *Raise_functionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#literal_value.
|
||||
VisitLiteral_value(ctx *Literal_valueContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#value_row.
|
||||
VisitValue_row(ctx *Value_rowContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#values_clause.
|
||||
VisitValues_clause(ctx *Values_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#insert_stmt.
|
||||
VisitInsert_stmt(ctx *Insert_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#returning_clause.
|
||||
VisitReturning_clause(ctx *Returning_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#upsert_clause.
|
||||
VisitUpsert_clause(ctx *Upsert_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#pragma_stmt.
|
||||
VisitPragma_stmt(ctx *Pragma_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#pragma_value.
|
||||
VisitPragma_value(ctx *Pragma_valueContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#reindex_stmt.
|
||||
VisitReindex_stmt(ctx *Reindex_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#select_stmt.
|
||||
VisitSelect_stmt(ctx *Select_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#join_clause.
|
||||
VisitJoin_clause(ctx *Join_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#select_core.
|
||||
VisitSelect_core(ctx *Select_coreContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#factored_select_stmt.
|
||||
VisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#simple_select_stmt.
|
||||
VisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#compound_select_stmt.
|
||||
VisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_or_subquery.
|
||||
VisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#result_column.
|
||||
VisitResult_column(ctx *Result_columnContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#join_operator.
|
||||
VisitJoin_operator(ctx *Join_operatorContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#join_constraint.
|
||||
VisitJoin_constraint(ctx *Join_constraintContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#compound_operator.
|
||||
VisitCompound_operator(ctx *Compound_operatorContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#update_stmt.
|
||||
VisitUpdate_stmt(ctx *Update_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#column_name_list.
|
||||
VisitColumn_name_list(ctx *Column_name_listContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#update_stmt_limited.
|
||||
VisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#qualified_table_name.
|
||||
VisitQualified_table_name(ctx *Qualified_table_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#vacuum_stmt.
|
||||
VisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#filter_clause.
|
||||
VisitFilter_clause(ctx *Filter_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#window_defn.
|
||||
VisitWindow_defn(ctx *Window_defnContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#over_clause.
|
||||
VisitOver_clause(ctx *Over_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#frame_spec.
|
||||
VisitFrame_spec(ctx *Frame_specContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#frame_clause.
|
||||
VisitFrame_clause(ctx *Frame_clauseContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#simple_function_invocation.
|
||||
VisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#aggregate_function_invocation.
|
||||
VisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#window_function_invocation.
|
||||
VisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#common_table_stmt.
|
||||
VisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#order_by_stmt.
|
||||
VisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#limit_stmt.
|
||||
VisitLimit_stmt(ctx *Limit_stmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#ordering_term.
|
||||
VisitOrdering_term(ctx *Ordering_termContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#asc_desc.
|
||||
VisitAsc_desc(ctx *Asc_descContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#frame_left.
|
||||
VisitFrame_left(ctx *Frame_leftContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#frame_right.
|
||||
VisitFrame_right(ctx *Frame_rightContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#frame_single.
|
||||
VisitFrame_single(ctx *Frame_singleContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#window_function.
|
||||
VisitWindow_function(ctx *Window_functionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#offset.
|
||||
VisitOffset(ctx *OffsetContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#default_value.
|
||||
VisitDefault_value(ctx *Default_valueContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#partition_by.
|
||||
VisitPartition_by(ctx *Partition_byContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#order_by_expr.
|
||||
VisitOrder_by_expr(ctx *Order_by_exprContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#order_by_expr_asc_desc.
|
||||
VisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#expr_asc_desc.
|
||||
VisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#initial_select.
|
||||
VisitInitial_select(ctx *Initial_selectContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#recursive_select.
|
||||
VisitRecursive_select(ctx *Recursive_selectContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#unary_operator.
|
||||
VisitUnary_operator(ctx *Unary_operatorContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#error_message.
|
||||
VisitError_message(ctx *Error_messageContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#module_argument.
|
||||
VisitModule_argument(ctx *Module_argumentContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#column_alias.
|
||||
VisitColumn_alias(ctx *Column_aliasContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#keyword.
|
||||
VisitKeyword(ctx *KeywordContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#name.
|
||||
VisitName(ctx *NameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#function_name.
|
||||
VisitFunction_name(ctx *Function_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#schema_name.
|
||||
VisitSchema_name(ctx *Schema_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_name.
|
||||
VisitTable_name(ctx *Table_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_or_index_name.
|
||||
VisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#column_name.
|
||||
VisitColumn_name(ctx *Column_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#collation_name.
|
||||
VisitCollation_name(ctx *Collation_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#foreign_table.
|
||||
VisitForeign_table(ctx *Foreign_tableContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#index_name.
|
||||
VisitIndex_name(ctx *Index_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#trigger_name.
|
||||
VisitTrigger_name(ctx *Trigger_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#view_name.
|
||||
VisitView_name(ctx *View_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#module_name.
|
||||
VisitModule_name(ctx *Module_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#pragma_name.
|
||||
VisitPragma_name(ctx *Pragma_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#savepoint_name.
|
||||
VisitSavepoint_name(ctx *Savepoint_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_alias.
|
||||
VisitTable_alias(ctx *Table_aliasContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#transaction_name.
|
||||
VisitTransaction_name(ctx *Transaction_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#window_name.
|
||||
VisitWindow_name(ctx *Window_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#alias.
|
||||
VisitAlias(ctx *AliasContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#filename.
|
||||
VisitFilename(ctx *FilenameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#base_window_name.
|
||||
VisitBase_window_name(ctx *Base_window_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#simple_func.
|
||||
VisitSimple_func(ctx *Simple_funcContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#aggregate_func.
|
||||
VisitAggregate_func(ctx *Aggregate_funcContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#table_function_name.
|
||||
VisitTable_function_name(ctx *Table_function_nameContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by SQLiteParser#any_name.
|
||||
VisitAny_name(ctx *Any_nameContext) interface{}
|
||||
}
|
189
drivers/sqlite3/internal/sqlparser/sqlparser.go
Normal file
189
drivers/sqlite3/internal/sqlparser/sqlparser.go
Normal file
@ -0,0 +1,189 @@
|
||||
// Package sqlparser contains SQL parsing functionality for SQLite.
|
||||
package sqlparser
|
||||
|
||||
//go:generate ./generate.sh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
"github.com/neilotoole/sq/drivers/sqlite3/internal/sqlparser/sqlite"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
// ExtractTableIdentFromCreateTableStmt extracts table name (and the
|
||||
// table's schema if specified) from a CREATE TABLE statement.
|
||||
// If err is nil, table is guaranteed to be non-empty. If arg unescape is
|
||||
// true, any surrounding quotation chars are trimmed from the returned values.
|
||||
//
|
||||
// CREATE TABLE "sakila"."actor" ( actor_id INTEGER NOT NULL) --> sakila, actor, nil
|
||||
func ExtractTableIdentFromCreateTableStmt(stmt string, unescape bool) (schema, table string, err error) {
|
||||
stmtCtx, err := parseCreateTableStmt(stmt)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if n, ok := stmtCtx.Schema_name().(*sqlite.Schema_nameContext); ok {
|
||||
if n.Any_name() != nil && !n.Any_name().IsEmpty() && n.Any_name().IDENTIFIER() != nil {
|
||||
schema = n.Any_name().IDENTIFIER().GetText()
|
||||
if unescape {
|
||||
schema = trimIdentQuotes(schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if x, ok := stmtCtx.Table_name().(*sqlite.Table_nameContext); ok {
|
||||
if x.Any_name() != nil && !x.Any_name().IsEmpty() && x.Any_name().IDENTIFIER() != nil {
|
||||
table = x.Any_name().IDENTIFIER().GetText()
|
||||
if unescape {
|
||||
table = trimIdentQuotes(table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if table == "" {
|
||||
return "", "", errz.Errorf("failed to extract table name from CREATE TABLE statement")
|
||||
}
|
||||
|
||||
return schema, table, nil
|
||||
}
|
||||
|
||||
// trimIdentQuotes trims any of the legal quote characters from s.
|
||||
// These are double quote, single quote, backtick, and square brackets.
|
||||
//
|
||||
// [actor] -> actor
|
||||
// "actor" -> actor
|
||||
// `actor` -> actor
|
||||
// 'actor' -> actor
|
||||
//
|
||||
// If s is empty, unquoted, or is malformed, it is returned unchanged.
|
||||
func trimIdentQuotes(s string) string {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
|
||||
switch s[0] {
|
||||
case '"', '`', '\'':
|
||||
if s[len(s)-1] == s[0] {
|
||||
return s[1 : len(s)-1]
|
||||
}
|
||||
case '[':
|
||||
if s[len(s)-1] == ']' {
|
||||
return s[1 : len(s)-1]
|
||||
}
|
||||
default:
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func parseCreateTableStmt(input string) (*sqlite.Create_table_stmtContext, error) {
|
||||
lex := sqlite.NewSQLiteLexer(antlr.NewInputStream(input))
|
||||
lex.RemoveErrorListeners() // the generated lexer has default listeners we don't want
|
||||
lexErrs := &antlrErrorListener{name: "lexer"}
|
||||
lex.AddErrorListener(lexErrs)
|
||||
|
||||
p := sqlite.NewSQLiteParser(antlr.NewCommonTokenStream(lex, 0))
|
||||
p.RemoveErrorListeners() // the generated parser has default listeners we don't want
|
||||
parseErrs := &antlrErrorListener{name: "parser"}
|
||||
p.AddErrorListener(parseErrs)
|
||||
|
||||
qCtx := p.Create_table_stmt()
|
||||
|
||||
if err := lexErrs.error(); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
if err := parseErrs.error(); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
return qCtx.(*sqlite.Create_table_stmtContext), nil
|
||||
}
|
||||
|
||||
var _ antlr.ErrorListener = (*antlrErrorListener)(nil)
|
||||
|
||||
// antlrErrorListener implements antlr.ErrorListener.
|
||||
// TODO: this is a copy of the same-named type in libsq/ast/parser.go.
|
||||
// It should be moved to a common package.
|
||||
type antlrErrorListener struct {
|
||||
name string
|
||||
errs []string
|
||||
warnings []string
|
||||
err error
|
||||
}
|
||||
|
||||
// SyntaxError implements antlr.ErrorListener.
|
||||
//
|
||||
//nolint:revive
|
||||
func (el *antlrErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{},
|
||||
line, column int, msg string, e antlr.RecognitionException,
|
||||
) {
|
||||
text := fmt.Sprintf("%s: syntax error: [%d:%d] %s", el.name, line, column, msg)
|
||||
el.errs = append(el.errs, text)
|
||||
}
|
||||
|
||||
// ReportAmbiguity implements antlr.ErrorListener.
|
||||
//
|
||||
//nolint:revive
|
||||
func (el *antlrErrorListener) ReportAmbiguity(recognizer antlr.Parser, dfa *antlr.DFA,
|
||||
startIndex, stopIndex int, exact bool, ambigAlts *antlr.BitSet, configs *antlr.ATNConfigSet,
|
||||
) {
|
||||
tok := recognizer.GetCurrentToken()
|
||||
text := fmt.Sprintf("%s: syntax ambiguity: [%d:%d]", el.name, startIndex, stopIndex)
|
||||
text = text + " >>" + tok.GetText() + "<<"
|
||||
el.warnings = append(el.warnings, text)
|
||||
}
|
||||
|
||||
// ReportAttemptingFullContext implements antlr.ErrorListener.
|
||||
//
|
||||
//nolint:revive
|
||||
func (el *antlrErrorListener) ReportAttemptingFullContext(recognizer antlr.Parser, dfa *antlr.DFA,
|
||||
startIndex, stopIndex int, conflictingAlts *antlr.BitSet, configs *antlr.ATNConfigSet,
|
||||
) {
|
||||
text := fmt.Sprintf("%s: attempting full context: [%d:%d]", el.name, startIndex, stopIndex)
|
||||
el.warnings = append(el.warnings, text)
|
||||
}
|
||||
|
||||
// ReportContextSensitivity implements antlr.ErrorListener.
|
||||
//
|
||||
//nolint:revive
|
||||
func (el *antlrErrorListener) ReportContextSensitivity(recognizer antlr.Parser, dfa *antlr.DFA,
|
||||
startIndex, stopIndex, prediction int, configs *antlr.ATNConfigSet,
|
||||
) {
|
||||
text := fmt.Sprintf("%s: context sensitivity: [%d:%d]", el.name, startIndex, stopIndex)
|
||||
el.warnings = append(el.warnings, text)
|
||||
}
|
||||
|
||||
func (el *antlrErrorListener) error() error {
|
||||
if el.err == nil && len(el.errs) > 0 {
|
||||
msg := strings.Join(el.errs, "\n")
|
||||
el.err = &parseError{msg: msg}
|
||||
}
|
||||
return el.err
|
||||
}
|
||||
|
||||
func (el *antlrErrorListener) String() string {
|
||||
if len(el.errs)+len(el.warnings) == 0 {
|
||||
return fmt.Sprintf("%s: no issues", el.name)
|
||||
}
|
||||
|
||||
strs := make([]string, 0, len(el.errs)+len(el.warnings))
|
||||
strs = append(strs, el.errs...)
|
||||
strs = append(strs, el.warnings...)
|
||||
|
||||
return strings.Join(strs, "\n")
|
||||
}
|
||||
|
||||
// parseError represents an error in lexing/parsing input.
|
||||
type parseError struct {
|
||||
msg string
|
||||
// TODO: parse error should include more detail, such as
|
||||
// the offending token, position, etc.
|
||||
}
|
||||
|
||||
// Error implements error.
|
||||
func (p *parseError) Error() string {
|
||||
return p.msg
|
||||
}
|
69
drivers/sqlite3/internal/sqlparser/sqlparser_test.go
Normal file
69
drivers/sqlite3/internal/sqlparser/sqlparser_test.go
Normal file
@ -0,0 +1,69 @@
|
||||
package sqlparser_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/sqlite3/internal/sqlparser"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestExtractTableNameFromCreateTableStmt(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
unescape bool
|
||||
wantSchema string
|
||||
wantTable string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
in: `CREATE TABLE actor ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: true,
|
||||
wantTable: "actor",
|
||||
},
|
||||
{
|
||||
in: `CREATE TABLE "sakila"."actor" ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: true,
|
||||
wantSchema: "sakila",
|
||||
wantTable: "actor",
|
||||
},
|
||||
{
|
||||
in: `CREATE TABLE "sakila"."actor"."not_legal" ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: true,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
in: `CREATE TABLE [sakila]."actor" ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: true,
|
||||
wantSchema: "sakila",
|
||||
wantTable: "actor",
|
||||
},
|
||||
{
|
||||
in: `CREATE TABLE [sakila]."actor" ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: false,
|
||||
wantSchema: "[sakila]",
|
||||
wantTable: `"actor"`,
|
||||
},
|
||||
{
|
||||
in: `CREATE TABLE "sak ila"."actor" ( actor_id INTEGER NOT NULL)`,
|
||||
unescape: true,
|
||||
wantSchema: "sak ila",
|
||||
wantTable: "actor",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tutil.Name(i, tc.in), func(t *testing.T) {
|
||||
schema, table, err := sqlparser.ExtractTableIdentFromCreateTableStmt(tc.in, tc.unescape)
|
||||
if tc.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.wantSchema, schema)
|
||||
require.Equal(t, tc.wantTable, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
@ -33,7 +35,7 @@ func TestSimple(t *testing.T) {
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
sink, err := th.QuerySQL(src, query)
|
||||
sink, err := th.QuerySQL(src, nil, query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, wantKinds, sink.RecMeta.Kinds())
|
||||
@ -64,7 +66,7 @@ func TestScalarFuncsQuery(t *testing.T) {
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
sink, err := th.QuerySQL(src, query)
|
||||
sink, err := th.QuerySQL(src, nil, query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, wantKinds, sink.RecMeta.Kinds())
|
||||
@ -86,7 +88,7 @@ func TestCurrentTime(t *testing.T) {
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
sink, err := th.QuerySQL(src, query)
|
||||
sink, err := th.QuerySQL(src, nil, query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, wantKinds, sink.RecMeta.Kinds())
|
||||
@ -251,7 +253,7 @@ func TestPayments(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM payment")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM payment")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblPaymentCount, len(sink.Recs))
|
||||
}
|
||||
@ -275,7 +277,7 @@ func TestAggregateFuncsQuery(t *testing.T) {
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
sink, err := th.QuerySQL(src, query)
|
||||
sink, err := th.QuerySQL(src, nil, query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
}
|
||||
@ -295,7 +297,7 @@ func BenchmarkDatabase_SourceMetadata(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
for _, tblName := range tblNames {
|
||||
require.NoError(b, drvr.DropTable(th.Context, db, tblName, true))
|
||||
require.NoError(b, drvr.DropTable(th.Context, db, tablefq.From(tblName), true))
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,7 +341,7 @@ func BenchmarkGetTblRowCounts(b *testing.B) {
|
||||
}
|
||||
|
||||
for _, tblName := range tblNames {
|
||||
require.NoError(b, drvr.DropTable(th.Context, db, tblName, true))
|
||||
require.NoError(b, drvr.DropTable(th.Context, db, tablefq.From(tblName), true))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,9 @@ import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
"github.com/neilotoole/sq/libsq/ast/render"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/kind"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
@ -136,3 +139,28 @@ func buildUpdateStmt(tbl string, cols []string, where string) (string, error) {
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func doRenderFuncSchema(_ *render.Context, fn *ast.FuncNode) (string, error) {
|
||||
if fn.FuncName() != ast.FuncNameSchema {
|
||||
// Shouldn't happen
|
||||
return "", errz.Errorf("expected %s function, got %q", ast.FuncNameSchema, fn.FuncName())
|
||||
}
|
||||
|
||||
const frag = `(SELECT name FROM pragma_database_list ORDER BY seq limit 1)`
|
||||
return frag, nil
|
||||
}
|
||||
|
||||
// doRenderFuncCatalog renders the catalog function. SQLite doesn't
|
||||
// support catalogs, so we just return the string "default". We could
|
||||
// return empty string, but that may be even more confusing, and would
|
||||
// make SQLite the odd man out, as the other SQL drivers (even MySQL)
|
||||
// have a value for catalog.
|
||||
func doRenderFuncCatalog(_ *render.Context, fn *ast.FuncNode) (string, error) {
|
||||
if fn.FuncName() != ast.FuncNameCatalog {
|
||||
// Shouldn't happen
|
||||
return "", errz.Errorf("expected %s function, got %q", ast.FuncNameCatalog, fn.FuncName())
|
||||
}
|
||||
|
||||
const frag = `(SELECT 'default')`
|
||||
return frag, nil
|
||||
}
|
||||
|
@ -9,13 +9,18 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/neilotoole/sq/drivers/sqlite3/internal/sqlparser"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/loz"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/jointype"
|
||||
@ -142,13 +147,13 @@ func (d *driveri) Open(ctx context.Context, src *source.Source) (driver.Database
|
||||
}
|
||||
|
||||
func (d *driveri) doOpen(ctx context.Context, src *source.Source) (*sql.DB, error) {
|
||||
dsn, err := PathFromLocation(src)
|
||||
fp, err := PathFromLocation(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db, err := sql.Open(dbDrvr, dsn)
|
||||
db, err := sql.Open(dbDrvr, fp)
|
||||
if err != nil {
|
||||
return nil, errz.Wrapf(errw(err), "failed to open sqlite3 source with DSN: %s", dsn)
|
||||
return nil, errz.Wrapf(errw(err), "failed to open sqlite3 source with DSN: %s", fp)
|
||||
}
|
||||
|
||||
driver.ConfigureDB(ctx, db, src.Options)
|
||||
@ -212,7 +217,15 @@ func (d *driveri) Ping(ctx context.Context, src *source.Source) error {
|
||||
}
|
||||
defer lg.WarnIfCloseError(d.log, lgm.CloseDB, db)
|
||||
|
||||
return errz.Wrapf(db.PingContext(ctx), "ping %s", src.Handle)
|
||||
if err = db.PingContext(ctx); err != nil {
|
||||
err = errz.Wrapf(err, "ping %s: %s", src.Handle, src.Location)
|
||||
lg.FromContext(ctx).Warn("ping failed",
|
||||
lga.Src, src,
|
||||
lga.Err, err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dialect implements driver.SQLDriver.
|
||||
@ -224,6 +237,7 @@ func (d *driveri) Dialect() dialect.Dialect {
|
||||
MaxBatchValues: 500,
|
||||
Ops: dialect.DefaultOps(),
|
||||
Joins: jointype.All(),
|
||||
Catalog: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,27 +251,55 @@ func placeholders(numCols, numRows int) string {
|
||||
|
||||
// Renderer implements driver.SQLDriver.
|
||||
func (d *driveri) Renderer() *render.Renderer {
|
||||
return render.NewDefaultRenderer()
|
||||
r := render.NewDefaultRenderer()
|
||||
r.FunctionOverrides[ast.FuncNameSchema] = doRenderFuncSchema
|
||||
r.FunctionOverrides[ast.FuncNameCatalog] = doRenderFuncCatalog
|
||||
return r
|
||||
}
|
||||
|
||||
// CopyTable implements driver.SQLDriver.
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) {
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB,
|
||||
fromTbl, toTbl tablefq.T, copyData bool,
|
||||
) (int64, error) {
|
||||
// Per https://stackoverflow.com/questions/12730390/copy-table-structure-to-new-table-in-sqlite3
|
||||
// It is possible to copy the table structure with a simple statement:
|
||||
// CREATE TABLE copied AS SELECT * FROM mytable WHERE 0
|
||||
// However, this does not keep the type information as desired. Thus
|
||||
// we need to do something more complicated.
|
||||
|
||||
var originTblCreateStmt string
|
||||
err := db.QueryRowContext(ctx, fmt.Sprintf("SELECT sql FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||
fromTable)).Scan(&originTblCreateStmt)
|
||||
// First we get the original CREATE TABLE statement.
|
||||
masterTbl := tablefq.T{Schema: fromTbl.Schema, Table: "sqlite_master"}
|
||||
q := fmt.Sprintf("SELECT sql FROM %s WHERE type='table' AND name=%s",
|
||||
masterTbl.Render(stringz.DoubleQuote),
|
||||
stringz.SingleQuote(fromTbl.Table))
|
||||
var ogTblCreateStmt string
|
||||
err := db.QueryRowContext(ctx, q).Scan(&ogTblCreateStmt)
|
||||
if err != nil {
|
||||
return 0, errw(err)
|
||||
}
|
||||
|
||||
// A simple replace of the table name should work to mutate the
|
||||
// above CREATE stmt to use toTable instead of fromTable.
|
||||
destTblCreateStmt := strings.Replace(originTblCreateStmt, fromTable, toTable, 1)
|
||||
// Next, we extract the table identifier from the CREATE TABLE statement.
|
||||
// For example, "main"."actor". Note that the schema part may be empty.
|
||||
ogSchema, ogTbl, err := sqlparser.ExtractTableIdentFromCreateTableStmt(ogTblCreateStmt,
|
||||
false)
|
||||
if err != nil {
|
||||
return 0, errw(err)
|
||||
}
|
||||
|
||||
// Now we know what text to replace in ogTblCreateStmt.
|
||||
replaceTarget := ogTbl
|
||||
if ogSchema != "" {
|
||||
replaceTarget = ogSchema + "." + ogTbl
|
||||
}
|
||||
|
||||
// Replace the old table identifier with the new one, and, voila,
|
||||
// we have our new CREATE TABLE statement.
|
||||
destTblCreateStmt := strings.Replace(
|
||||
ogTblCreateStmt,
|
||||
replaceTarget,
|
||||
toTbl.Render(stringz.DoubleQuote),
|
||||
1,
|
||||
)
|
||||
|
||||
_, err = db.ExecContext(ctx, destTblCreateStmt)
|
||||
if err != nil {
|
||||
@ -268,7 +310,7 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
stmt := fmt.Sprintf("INSERT INTO %q SELECT * FROM %q", toTable, fromTable)
|
||||
stmt := fmt.Sprintf("INSERT INTO %s SELECT * FROM %s", toTbl, fromTbl)
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
if err != nil {
|
||||
return 0, errw(err)
|
||||
@ -564,19 +606,59 @@ func newRecordFromScanRow(meta record.Meta, row []any) (rec record.Record) {
|
||||
}
|
||||
|
||||
// DropTable implements driver.SQLDriver.
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error {
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl tablefq.T, ifExists bool) error {
|
||||
var stmt string
|
||||
|
||||
if ifExists {
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS %q", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE IF EXISTS %s", tbl)
|
||||
} else {
|
||||
stmt = fmt.Sprintf("DROP TABLE %q", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE %s", tbl)
|
||||
}
|
||||
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
return errw(err)
|
||||
}
|
||||
|
||||
// CreateSchema implements driver.SQLDriver. This is implemented for SQLite
|
||||
// by attaching a new database to db, using ATTACH DATABASE. This attached
|
||||
// database is only available on the connection on which the ATTACH DATABASE
|
||||
// command was issued. Thus, db must be a *sql.Conn or *sql.Tx, as
|
||||
// per sqlz.RequireSingleConn. The same constraint applies to DropSchema.
|
||||
//
|
||||
// See: https://www.sqlite.org/lang_attach.html
|
||||
func (d *driveri) CreateSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
if err := sqlz.RequireSingleConn(db); err != nil {
|
||||
return errz.Wrapf(err, "create schema {%s}: ATTACH DATABASE requires single connection", schemaName)
|
||||
}
|
||||
|
||||
// NOTE: Empty string for DATABASE creates a temporary database.
|
||||
// We may want to change this to create a more permanent database, perhaps
|
||||
// in the same directory as the existing db?
|
||||
stmt := `ATTACH DATABASE "" AS ` + stringz.DoubleQuote(schemaName)
|
||||
if _, err := db.ExecContext(ctx, stmt); err != nil {
|
||||
return errz.Wrapf(err, "create schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropSchema implements driver.SQLDriver. As per CreateSchema, db must
|
||||
// be a *sql.Conn or *sql.Tx.
|
||||
//
|
||||
// See https://www.sqlite.org/lang_detach.html
|
||||
func (d *driveri) DropSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
if err := sqlz.RequireSingleConn(db); err != nil {
|
||||
return errz.Wrapf(err, "drop schema {%s}: DETACH DATABASE requires single connection", schemaName)
|
||||
}
|
||||
|
||||
stmt := `DETACH DATABASE ` + stringz.DoubleQuote(schemaName)
|
||||
if _, err := db.ExecContext(ctx, stmt); err != nil {
|
||||
return errz.Wrapf(err, "drop schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateTable implements driver.SQLDriver.
|
||||
func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.TableDef) error {
|
||||
query := buildCreateTableStmt(tblDef)
|
||||
@ -606,6 +688,45 @@ func (d *driveri) CurrentSchema(ctx context.Context, db sqlz.DB) (string, error)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListSchemas implements driver.SQLDriver.
|
||||
func (d *driveri) ListSchemas(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
log := lg.FromContext(ctx)
|
||||
|
||||
const q = `SELECT name FROM pragma_database_list ORDER BY name`
|
||||
var schemas []string
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
defer lg.WarnIfCloseError(log, lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var schema string
|
||||
if err = rows.Scan(&schema); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
// CurrentCatalog implements driver.SQLDriver. SQLite does not support catalogs,
|
||||
// so this method returns an error.
|
||||
func (d *driveri) CurrentCatalog(_ context.Context, _ sqlz.DB) (string, error) {
|
||||
return "", errz.New("sqlite3: catalog mechanism not supported")
|
||||
}
|
||||
|
||||
// ListCatalogs implements driver.SQLDriver. SQLite does not support catalogs,
|
||||
// so this method returns an error.
|
||||
func (d *driveri) ListCatalogs(_ context.Context, _ sqlz.DB) ([]string, error) {
|
||||
return nil, errz.New("sqlite3: catalog mechanism not supported")
|
||||
}
|
||||
|
||||
// AlterTableRename implements driver.SQLDriver.
|
||||
func (d *driveri) AlterTableRename(ctx context.Context, db sqlz.DB, tbl, newName string) error {
|
||||
q := fmt.Sprintf(`ALTER TABLE %q RENAME TO %q`, tbl, newName)
|
||||
@ -939,14 +1060,23 @@ func PathFromLocation(src *source.Source) (string, error) {
|
||||
// and builds a sqlite3 location URL. Each of these forms are allowed:
|
||||
//
|
||||
// sqlite3:///path/to/sakila.db --> sqlite3:///path/to/sakila.db
|
||||
// sqlite3:sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sqlite3:/sakila.db --> sqlite3:///sakila.db
|
||||
// sqlite3:./sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sqlite3:sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// /path/to/sakila.db --> sqlite3:///path/to/sakila.db
|
||||
// sqlite3:sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sqlite3:/sakila.db --> sqlite3:///sakila.db
|
||||
// sqlite3:./sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sqlite3:sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// sakila.db --> sqlite3:///current/working/dir/sakila.db
|
||||
// /path/to/sakila.db --> sqlite3:///path/to/sakila.db
|
||||
//
|
||||
// The final form is particularly nice for shell completion etc.
|
||||
//
|
||||
// Note that this function is OS-dependent, due to the use of pkg filepath.
|
||||
// Thus, on Windows, this is seen:
|
||||
//
|
||||
// C:/Users/sq/sakila.db --> sqlite3://C:/Users/sq/sakila.db
|
||||
//
|
||||
// But that input location gets mangled on non-Windows OSes. This probably
|
||||
// isn't a problem in practice, but longer-term it may make sense to rewrite
|
||||
// MungeLocation to be OS-independent.
|
||||
func MungeLocation(loc string) (string, error) {
|
||||
loc2 := strings.TrimSpace(loc)
|
||||
if loc2 == "" {
|
||||
@ -956,14 +1086,7 @@ func MungeLocation(loc string) (string, error) {
|
||||
loc2 = strings.TrimPrefix(loc2, "sqlite3://")
|
||||
loc2 = strings.TrimPrefix(loc2, "sqlite3:")
|
||||
|
||||
// Now we should be left with just a path, which could be
|
||||
// relative or absolute.
|
||||
u, err := url.Parse(loc2)
|
||||
if err != nil {
|
||||
return "", errz.Wrapf(errw(err), "invalid location: %s", loc)
|
||||
}
|
||||
|
||||
fp, err := filepath.Abs(u.Path)
|
||||
fp, err := filepath.Abs(loc2)
|
||||
if err != nil {
|
||||
return "", errz.Wrapf(errw(err), "invalid location: %s", loc)
|
||||
}
|
||||
|
@ -3,9 +3,10 @@ package sqlite3_test
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/kind"
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
@ -27,7 +28,7 @@ func TestSmoke(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+sakila.TblFilm)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+sakila.TblFilm)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblFilmCount, len(sink.Recs))
|
||||
}
|
||||
@ -39,10 +40,10 @@ func TestQueryEmptyTable(t *testing.T) {
|
||||
src := th.Source(sakila.SL3)
|
||||
|
||||
// Get an empty table by copying an existing one
|
||||
tblName := th.CopyTable(true, src, sakila.TblFilm, "", false)
|
||||
tblName := th.CopyTable(true, src, tablefq.From(sakila.TblFilm), tablefq.T{}, false)
|
||||
require.Equal(t, int64(0), th.RowCount(src, tblName))
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tblName)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(sink.Recs))
|
||||
}
|
||||
@ -77,7 +78,7 @@ func TestExhibitDriverColumnTypesBehavior(t *testing.T) {
|
||||
|
||||
// Create the table
|
||||
th.ExecSQL(src, createStmt)
|
||||
t.Cleanup(func() { th.DropTable(src, tblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(tblName)) })
|
||||
|
||||
// 1. Demonstrate that ColumnType.ScanType now correctly returns
|
||||
// a valid value when rows.ColumnTypes is invoked prior to the first
|
||||
@ -179,11 +180,11 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) {
|
||||
|
||||
err := drvr.CreateTable(th.Context, db, tblDef)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { th.DropTable(src, tblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(tblName)) })
|
||||
|
||||
th.InsertDefaultRow(src, tblName)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tblName)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, len(colNames), len(sink.RecMeta))
|
||||
@ -200,7 +201,7 @@ func TestPathFromLocation(t *testing.T) {
|
||||
}{
|
||||
{loc: "sqlite3:///test.db", want: "/test.db"},
|
||||
{loc: "postgres:///test.db", wantErr: true},
|
||||
{loc: `sqlite3://C:\dir\sakila.db`, want: `C:\dir\sakila.db`},
|
||||
{loc: `sqlite3://C:/dir/sakila.db`, want: `C:/dir/sakila.db`},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -241,9 +242,10 @@ func TestMungeLocation(t *testing.T) {
|
||||
t.Log("cwdWant:", cwdWant)
|
||||
t.Log("root:", root)
|
||||
testCases := []struct {
|
||||
in string
|
||||
want string
|
||||
wantErr bool
|
||||
in string
|
||||
want string
|
||||
onlyForOS string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
@ -277,11 +279,25 @@ func TestMungeLocation(t *testing.T) {
|
||||
in: "/path/to/sakila.db",
|
||||
want: "sqlite3://" + root + "path/to/sakila.db",
|
||||
},
|
||||
{
|
||||
in: `C:/Users/neil/work/sq/drivers/sqlite3/testdata/sakila.db`,
|
||||
want: `sqlite3://C:/Users/neil/work/sq/drivers/sqlite3/testdata/sakila.db`,
|
||||
// The current impl of MungeLocation relies upon OS-specific functions
|
||||
// in pkg filepath. Thus, we skip this test on non-Windows OSes.
|
||||
// MungeLocation could probably be rewritten to be OS-independent?
|
||||
onlyForOS: "windows",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tutil.Name(i, tc.in), func(t *testing.T) {
|
||||
if tc.onlyForOS != "" && tc.onlyForOS != runtime.GOOS {
|
||||
t.Skipf("Skipping because this test is only for OS {%s}, but have {%s}",
|
||||
tc.onlyForOS, runtime.GOOS)
|
||||
return
|
||||
}
|
||||
|
||||
got, err := sqlite3.MungeLocation(tc.in)
|
||||
if tc.wantErr {
|
||||
require.Error(t, err)
|
||||
@ -300,63 +316,14 @@ func TestSQLQuery_Whitespace(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(sakila.SL3Whitespace)
|
||||
|
||||
sink, err := th.QuerySQL(src, `SELECT * FROM "film actor"`)
|
||||
sink, err := th.QuerySQL(src, nil, `SELECT * FROM "film actor"`)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblFilmActorCount, len(sink.Recs))
|
||||
|
||||
sink, err = th.QuerySQL(src, `SELECT * FROM "actor"`)
|
||||
sink, err = th.QuerySQL(src, nil, `SELECT * FROM "actor"`)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "first name", sink.RecMeta[1].Name())
|
||||
require.Equal(t, "first name", sink.RecMeta[1].MungedName())
|
||||
require.Equal(t, "last name", sink.RecMeta[2].Name())
|
||||
require.Equal(t, "last name", sink.RecMeta[2].MungedName())
|
||||
}
|
||||
|
||||
func TestExtension_fts5(t *testing.T) {
|
||||
const tblActorFts = "actor_fts"
|
||||
|
||||
th := testh.New(t)
|
||||
src := th.Add(&source.Source{
|
||||
Handle: "@fts",
|
||||
Type: sqlite3.Type,
|
||||
Location: "sqlite3://" + tutil.MustAbsFilepath("testdata", "sakila_fts5.db"),
|
||||
})
|
||||
|
||||
srcMeta, err := th.SourceMetadata(src)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, src.Handle, srcMeta.Handle)
|
||||
tblMeta1 := srcMeta.Table(tblActorFts)
|
||||
require.NotNil(t, tblMeta1)
|
||||
require.Equal(t, tblActorFts, tblMeta1.Name)
|
||||
require.Equal(t, sqlz.TableTypeVirtual, tblMeta1.TableType)
|
||||
|
||||
require.Equal(t, "actor_id", tblMeta1.Columns[0].Name)
|
||||
require.Equal(t, "integer", tblMeta1.Columns[0].ColumnType)
|
||||
require.Equal(t, "integer", tblMeta1.Columns[0].BaseType)
|
||||
require.Equal(t, kind.Int, tblMeta1.Columns[0].Kind)
|
||||
require.Equal(t, "first_name", tblMeta1.Columns[1].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[1].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[1].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[1].Kind)
|
||||
require.Equal(t, "last_name", tblMeta1.Columns[2].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[2].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[2].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[2].Kind)
|
||||
require.Equal(t, "last_update", tblMeta1.Columns[3].Name)
|
||||
require.Equal(t, "text", tblMeta1.Columns[3].ColumnType)
|
||||
require.Equal(t, "text", tblMeta1.Columns[3].BaseType)
|
||||
require.Equal(t, kind.Text, tblMeta1.Columns[3].Kind)
|
||||
|
||||
tblMeta2, err := th.TableMetadata(src, tblActorFts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tblActorFts, tblMeta2.Name)
|
||||
require.Equal(t, sqlz.TableTypeVirtual, tblMeta2.TableType)
|
||||
require.EqualValues(t, *tblMeta1, *tblMeta2)
|
||||
|
||||
// Verify that the (non-virtual) "actor" table has its type set correctly.
|
||||
actorMeta1 := srcMeta.Table(sakila.TblActor)
|
||||
actorMeta2, err := th.TableMetadata(src, sakila.TblActor)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, actorMeta1.TableType, sqlz.TableTypeTable)
|
||||
require.Equal(t, *actorMeta1, *actorMeta2)
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/testh/fixt"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -301,11 +303,11 @@ func TestDatabaseTypes(t *testing.T) {
|
||||
th := testh.New(t)
|
||||
src := th.Source(handle)
|
||||
insertCount, actualTblName := createTypeTestTable(th, src, true)
|
||||
t.Cleanup(func() { th.DropTable(src, actualTblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(actualTblName)) })
|
||||
|
||||
sink := &testh.RecordSink{}
|
||||
recw := output.NewRecordWriterAdapter(th.Context, sink)
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
err := libsq.QuerySQL(th.Context, th.Open(src), nil, recw, fmt.Sprintf("SELECT * FROM %s", actualTblName))
|
||||
require.NoError(t, err)
|
||||
written, err := recw.Wait()
|
||||
require.NoError(t, err)
|
||||
@ -346,7 +348,7 @@ func Test_MSSQLDB_DriverIssue196(t *testing.T) {
|
||||
|
||||
// Drop the newly-created table on cleanup
|
||||
t.Cleanup(func() {
|
||||
th.DropTable(src, actualTblName)
|
||||
th.DropTable(src, tablefq.From(actualTblName))
|
||||
})
|
||||
|
||||
// Build the INSERT statement
|
||||
|
@ -228,6 +228,15 @@ func getTableMetadata(ctx context.Context, db sqlz.DB, tblCatalog,
|
||||
|
||||
var rowCount, reserved, data, indexSize, unused sql.NullString
|
||||
row := db.QueryRowContext(ctx, fmt.Sprintf(tplTblUsage, tblName))
|
||||
|
||||
// REVISIT: This error can occur:
|
||||
//
|
||||
// sql: Scan error on column index 0, name "name": converting NULL to string is unsupported
|
||||
//
|
||||
// We should probably use sql.NullString? This situation can arise if the table
|
||||
// is deleted while this process is taking place. Maybe wrap the entire thing
|
||||
// in a transaction? Or figure out how to fail more gracefully?
|
||||
|
||||
err := row.Scan(&tblMeta.Name, &rowCount, &reserved, &data, &indexSize, &unused)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
|
@ -9,6 +9,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/xo/dburl"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/loz"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/jointype"
|
||||
@ -115,6 +121,7 @@ func (d *driveri) Dialect() dialect.Dialect {
|
||||
MaxBatchValues: 1000,
|
||||
Ops: dialect.DefaultOps(),
|
||||
Joins: jointype.All(),
|
||||
Catalog: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +156,9 @@ func (d *driveri) Renderer() *render.Renderer {
|
||||
r.Range = renderRange
|
||||
r.PreRender = preRender
|
||||
|
||||
r.FunctionNames[ast.FuncNameSchema] = "SCHEMA_NAME"
|
||||
r.FunctionNames[ast.FuncNameCatalog] = "DB_NAME"
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@ -169,7 +179,25 @@ func (d *driveri) Open(ctx context.Context, src *source.Source) (driver.Database
|
||||
}
|
||||
|
||||
func (d *driveri) doOpen(ctx context.Context, src *source.Source) (*sql.DB, error) {
|
||||
db, err := sql.Open(dbDrvr, src.Location)
|
||||
log := lg.FromContext(ctx)
|
||||
loc := src.Location
|
||||
if src.Catalog != "" {
|
||||
u, err := dburl.Parse(loc)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
vals := u.Query()
|
||||
vals.Set("database", src.Catalog)
|
||||
u.RawQuery = vals.Encode()
|
||||
loc = u.String()
|
||||
log.Debug("Using catalog as database in connection string",
|
||||
lga.Src, src,
|
||||
lga.Catalog, src.Catalog,
|
||||
lga.Conn, source.RedactLocation(loc),
|
||||
)
|
||||
}
|
||||
|
||||
db, err := sql.Open(dbDrvr, loc)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
@ -327,11 +355,10 @@ func (d *driveri) RecordMeta(ctx context.Context, colTypes []*sql.ColumnType) (
|
||||
// TableExists implements driver.SQLDriver.
|
||||
func (d *driveri) TableExists(ctx context.Context, db sqlz.DB, tbl string) (bool, error) {
|
||||
const query = `SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema = 'dbo' AND table_name = @p1`
|
||||
WHERE table_schema = schema_name() AND table_name = @p1`
|
||||
|
||||
var count int64
|
||||
err := db.QueryRowContext(ctx, query, tbl).Scan(&count)
|
||||
if err != nil {
|
||||
if err := db.QueryRowContext(ctx, query, tbl).Scan(&count); err != nil {
|
||||
return false, errw(err)
|
||||
}
|
||||
|
||||
@ -348,6 +375,104 @@ func (d *driveri) CurrentSchema(ctx context.Context, db sqlz.DB) (string, error)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListSchemas implements driver.SQLDriver.
|
||||
func (d *driveri) ListSchemas(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
log := lg.FromContext(ctx)
|
||||
|
||||
const q = `SELECT name FROM sys.schemas ORDER BY name`
|
||||
var schemas []string
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
defer lg.WarnIfCloseError(log, lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var schema string
|
||||
if err = rows.Scan(&schema); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errz.Err(err)
|
||||
}
|
||||
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
// CurrentCatalog implements driver.SQLDriver.
|
||||
func (d *driveri) CurrentCatalog(ctx context.Context, db sqlz.DB) (string, error) {
|
||||
var name string
|
||||
if err := db.QueryRowContext(ctx, `SELECT DB_NAME()`).Scan(&name); err != nil {
|
||||
return "", errw(err)
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ListCatalogs implements driver.SQLDriver.
|
||||
func (d *driveri) ListCatalogs(ctx context.Context, db sqlz.DB) ([]string, error) {
|
||||
catalogs := make([]string, 1, 3)
|
||||
if err := db.QueryRowContext(ctx, `SELECT DB_NAME()`).Scan(&catalogs[0]); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
const q = `SELECT name FROM sys.databases
|
||||
WHERE name != DB_NAME()
|
||||
ORDER BY name`
|
||||
|
||||
rows, err := db.QueryContext(ctx, q)
|
||||
if err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
defer lg.WarnIfCloseError(lg.FromContext(ctx), lgm.CloseDBRows, rows)
|
||||
|
||||
for rows.Next() {
|
||||
var catalog string
|
||||
if err = rows.Scan(&catalog); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
catalogs = append(catalogs, catalog)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errw(err)
|
||||
}
|
||||
|
||||
return catalogs, nil
|
||||
}
|
||||
|
||||
// CreateSchema implements driver.SQLDriver.
|
||||
func (d *driveri) CreateSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
stmt := `CREATE SCHEMA ` + stringz.DoubleQuote(schemaName)
|
||||
if _, err := db.ExecContext(ctx, stmt); err != nil {
|
||||
return errz.Wrapf(err, "failed to create schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
lg.FromContext(ctx).Debug("Created schema", lga.Schema, schemaName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropSchema implements driver.SQLDriver.
|
||||
func (d *driveri) DropSchema(ctx context.Context, db sqlz.DB, schemaName string) error {
|
||||
dropObjectsStmt := genDropSchemaObjectsStmt(schemaName)
|
||||
|
||||
if _, err := db.ExecContext(ctx, dropObjectsStmt); err != nil {
|
||||
return errz.Wrapf(err, "failed to drop objects in schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
dropSchemaStmt := `DROP SCHEMA [` + schemaName + `]`
|
||||
if _, err := db.ExecContext(ctx, dropSchemaStmt); err != nil {
|
||||
return errz.Wrapf(err, "failed to drop schema {%s}", schemaName)
|
||||
}
|
||||
|
||||
lg.FromContext(ctx).Debug("Dropped schema", lga.Schema, schemaName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateTable implements driver.SQLDriver.
|
||||
func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.TableDef) error {
|
||||
stmt := buildCreateTableStmt(tblDef)
|
||||
@ -389,13 +514,15 @@ func (d *driveri) AlterTableRenameColumn(ctx context.Context, db sqlz.DB, tbl, c
|
||||
}
|
||||
|
||||
// CopyTable implements driver.SQLDriver.
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) {
|
||||
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB,
|
||||
fromTable, toTable tablefq.T, copyData bool,
|
||||
) (int64, error) {
|
||||
var stmt string
|
||||
|
||||
if copyData {
|
||||
stmt = fmt.Sprintf("SELECT * INTO %q FROM %q", toTable, fromTable)
|
||||
stmt = fmt.Sprintf("SELECT * INTO %s FROM %s", tblfmt(toTable), tblfmt(fromTable))
|
||||
} else {
|
||||
stmt = fmt.Sprintf("SELECT TOP(0) * INTO %q FROM %q", toTable, fromTable)
|
||||
stmt = fmt.Sprintf("SELECT TOP(0) * INTO %s FROM %s", tblfmt(toTable), tblfmt(fromTable))
|
||||
}
|
||||
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
@ -407,13 +534,17 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
}
|
||||
|
||||
// DropTable implements driver.SQLDriver.
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error {
|
||||
func (d *driveri) DropTable(ctx context.Context, db sqlz.DB, tbl tablefq.T, ifExists bool) error {
|
||||
var stmt string
|
||||
|
||||
// We don't want the catalog for this part.
|
||||
tbl.Catalog = ""
|
||||
tblID := tblfmt(tbl)
|
||||
|
||||
if ifExists {
|
||||
stmt = fmt.Sprintf("IF OBJECT_ID('dbo.%s', 'U') IS NOT NULL DROP TABLE dbo.%q", tbl, tbl)
|
||||
stmt = fmt.Sprintf("IF OBJECT_ID('%s', 'U') IS NOT NULL DROP TABLE %s", tblID, tblID)
|
||||
} else {
|
||||
stmt = fmt.Sprintf("DROP TABLE dbo.%q", tbl)
|
||||
stmt = fmt.Sprintf("DROP TABLE %s", tblID)
|
||||
}
|
||||
|
||||
_, err := db.ExecContext(ctx, stmt)
|
||||
@ -607,7 +738,78 @@ func setIdentityInsert(ctx context.Context, db sqlz.DB, tbl string, on bool) err
|
||||
mode = "OFF"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("SET IDENTITY_INSERT %q %s", tbl, mode)
|
||||
query := fmt.Sprintf("SET IDENTITY_INSERT %s %s", tblfmt(tbl), mode)
|
||||
_, err := db.ExecContext(ctx, query)
|
||||
return errz.Wrapf(errw(err), "failed to SET IDENTITY INSERT %s %s", tbl, mode)
|
||||
return errz.Wrapf(errw(err), "failed to SET IDENTITY INSERT %s %s", tblfmt(tbl), mode)
|
||||
}
|
||||
|
||||
// tblfmt formats a table name for use in a query. The arg can be a string,
|
||||
// or a tablefq.T.
|
||||
func tblfmt[T string | tablefq.T](tbl T) string {
|
||||
tfq := tablefq.From(tbl)
|
||||
return tfq.Render(stringz.DoubleQuote)
|
||||
}
|
||||
|
||||
// genDropSchemaObjectsStmt generates a SQL statement that drops all
|
||||
// objects in the named schema. It is used by driveri.DropSchema.
|
||||
// This statement is necessary because SQLServer
|
||||
// doesn't support "DROP SCHEMA [NAME] CASCADE".
|
||||
// Note that script may not be comprehensive; there could be other
|
||||
// objects that we haven't considered. But it works on all that
|
||||
// that's been tested so far.
|
||||
//
|
||||
// See: https://stackoverflow.com/a/8150428
|
||||
//
|
||||
//nolint:lll
|
||||
func genDropSchemaObjectsStmt(schemaName string) string {
|
||||
const tpl = `
|
||||
declare @SchemaName nvarchar(100) = '%s'
|
||||
declare @SchemaID int = schema_id(@SchemaName)
|
||||
|
||||
declare @n char(1)
|
||||
set @n = char(10)
|
||||
declare @stmt nvarchar(max)
|
||||
|
||||
-- procedures
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'drop procedure [' + @SchemaName + '].[' + name + ']'
|
||||
from sys.procedures where schema_id = @SchemaID
|
||||
|
||||
|
||||
-- check constraints
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'alter table [' + @SchemaName + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
|
||||
from sys.check_constraints where schema_id = @SchemaID
|
||||
|
||||
-- functions
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'drop function [' + @SchemaName + '].[' + name + ']'
|
||||
from sys.objects
|
||||
where schema_id = @SchemaID and type in ( 'FN', 'IF', 'TF' )
|
||||
--
|
||||
-- views
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'drop view [' + @SchemaName + '].[' + name + ']'
|
||||
from sys.views where schema_id = @SchemaID
|
||||
--
|
||||
-- foreign keys
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'alter table [' + @SchemaName + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
|
||||
from sys.foreign_keys where schema_id = @SchemaID
|
||||
|
||||
-- tables
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'drop table [' + @SchemaName + '].[' + name + ']'
|
||||
from sys.tables where schema_id = @SchemaID
|
||||
|
||||
-- user defined types
|
||||
select @stmt = isnull( @stmt + @n, '' ) +
|
||||
'drop type [' + @SchemaName + '].[' + name + ']'
|
||||
from sys.types
|
||||
where schema_id = @SchemaID and is_user_defined = 1
|
||||
|
||||
exec sp_executesql @stmt
|
||||
`
|
||||
|
||||
return fmt.Sprintf(tpl, schemaName)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -25,7 +27,7 @@ func TestSmoke(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
th, src, _, _, _ := testh.NewWith(t, handle)
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM actor")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM actor")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(sakila.TblActorCols()), len(sink.RecMeta))
|
||||
require.Equal(t, sakila.TblActorCount, len(sink.Recs))
|
||||
@ -88,11 +90,11 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) {
|
||||
|
||||
err := drvr.CreateTable(th.Context, db, tblDef)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { th.DropTable(src, tblName) })
|
||||
t.Cleanup(func() { th.DropTable(src, tablefq.From(tblName)) })
|
||||
|
||||
th.InsertDefaultRow(src, tblName)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tblName)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tblName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, len(colNames), len(sink.RecMeta))
|
||||
|
@ -52,7 +52,7 @@ func TestDriver(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.tbl, tblMeta.Name)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tc.tbl)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tc.tbl)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.wantRecs, len(sink.Recs))
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ func TestImport_Ppl(t *testing.T) {
|
||||
require.Equal(t, "person", srcMeta.Tables[0].Name)
|
||||
require.Equal(t, "skill", srcMeta.Tables[1].Name)
|
||||
|
||||
sink, err := th.QuerySQL(scratchDB.Source(), "SELECT * FROM person")
|
||||
sink, err := th.QuerySQL(scratchDB.Source(), nil, "SELECT * FROM person")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(sink.Recs))
|
||||
require.Equal(t, "Nikola", stringz.Val(sink.Recs[0][1]))
|
||||
@ -58,7 +58,7 @@ func TestImport_Ppl(t *testing.T) {
|
||||
require.Equal(t, int64(i+1), stringz.Val(rec[0]))
|
||||
}
|
||||
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), "SELECT * FROM skill")
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), nil, "SELECT * FROM skill")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 6, len(sink.Recs))
|
||||
require.Equal(t, "Electrifying", stringz.Val(sink.Recs[0][2]))
|
||||
@ -95,7 +95,7 @@ func TestImport_RSS(t *testing.T) {
|
||||
require.Equal(t, "channel", srcMeta.Tables[1].Name)
|
||||
require.Equal(t, "item", srcMeta.Tables[2].Name)
|
||||
|
||||
sink, err := th.QuerySQL(scratchDB.Source(), "SELECT * FROM channel")
|
||||
sink, err := th.QuerySQL(scratchDB.Source(), nil, "SELECT * FROM channel")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(sink.Recs))
|
||||
require.Equal(t, "NYT > World", stringz.Val(sink.Recs[0][1]))
|
||||
@ -104,7 +104,7 @@ func TestImport_RSS(t *testing.T) {
|
||||
require.Equal(t, int64(i+1), stringz.Val(rec[0]))
|
||||
}
|
||||
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), "SELECT * FROM category")
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), nil, "SELECT * FROM category")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 251, len(sink.Recs))
|
||||
require.EqualValues(t, "Extradition", stringz.Val(sink.Recs[0][2]))
|
||||
@ -113,7 +113,7 @@ func TestImport_RSS(t *testing.T) {
|
||||
require.Equal(t, int64(i+1), stringz.Val(rec[0]))
|
||||
}
|
||||
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), "SELECT * FROM item")
|
||||
sink, err = th.QuerySQL(scratchDB.Source(), nil, "SELECT * FROM item")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 45, len(sink.Recs))
|
||||
require.EqualValues(t, "Trilobites: Fishing for Clues to Solve Namibia’s Fairy Circle Mystery",
|
||||
|
@ -183,7 +183,7 @@ func TestOpenFileFormats(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.PingContext(th.Context))
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM actor")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM actor")
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sakila.TblActorCols(), sink.RecMeta.MungedNames())
|
||||
@ -251,7 +251,7 @@ func TestSakila_query(t *testing.T) {
|
||||
th := testh.New(t, testh.OptLongOpen())
|
||||
src := th.Source(sakila.XLSX)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM "+tc.sheet)
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM "+tc.sheet)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.wantCols, sink.RecMeta.MungedNames())
|
||||
require.Equal(t, tc.wantCount, len(sink.Recs))
|
||||
@ -278,7 +278,7 @@ func Test_XLSX_BadDateRecognition(t *testing.T) {
|
||||
hasHeader := driver.OptIngestHeader.Get(src.Options)
|
||||
require.True(t, hasHeader)
|
||||
|
||||
sink, err := th.QuerySQL(src, "SELECT * FROM Summary")
|
||||
sink, err := th.QuerySQL(src, nil, "SELECT * FROM Summary")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 21, len(sink.Recs))
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -77,6 +77,7 @@ require (
|
||||
github.com/richardlehane/msoleps v1.0.3 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/rqlite/sql v0.0.0-20221103124402-8f9ff0ceb8f0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
|
||||
|
2
go.sum
2
go.sum
@ -145,6 +145,8 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/rqlite/sql v0.0.0-20221103124402-8f9ff0ceb8f0 h1:C8DZB5okjhCSd7zvkOM+zxGz7S6ulUFIL34bpkqFk+0=
|
||||
github.com/rqlite/sql v0.0.0-20221103124402-8f9ff0ceb8f0/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryboe/q v1.0.19 h1:1dO1anK4gorZRpXBD/edBZkMxIC1tFIwN03nfyOV13A=
|
||||
github.com/ryboe/q v1.0.19/go.mod h1:IoEB3Q2/p6n1qbhIQVuNyakxtnV4rNJ/XJPK+jsEa0M=
|
||||
|
@ -22,9 +22,6 @@ element
|
||||
| funcElement
|
||||
| exprElement;
|
||||
|
||||
// cmpr is a comparison operator.
|
||||
//cmpr: LT_EQ | LT | GT_EQ | GT | EQ | NEQ;
|
||||
|
||||
|
||||
|
||||
funcElement: func (alias)?;
|
||||
@ -34,6 +31,8 @@ funcName
|
||||
| 'avg'
|
||||
| 'max'
|
||||
| 'min'
|
||||
| 'schema'
|
||||
| 'catalog'
|
||||
| PROPRIETARY_FUNC_NAME
|
||||
;
|
||||
|
||||
@ -94,7 +93,7 @@ uniqueFunc implements SQL's DISTINCT mechanism.
|
||||
|
||||
The func takes zero args.
|
||||
*/
|
||||
uniqueFunc: 'unique';
|
||||
uniqueFunc: 'unique' | 'uniq';
|
||||
|
||||
/*
|
||||
|
||||
|
@ -6,7 +6,7 @@ dest_dir="../libsq/ast/internal/slq"
|
||||
mkdir -p $dest_dir
|
||||
|
||||
echo "Generating SLQ parser code from grammar..."
|
||||
alias antlr4='java -Xmx500M -cp "./antlr-4.13.0-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
|
||||
alias antlr4='java -Xmx500M -cp "../tools/antlr-4.13.0-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
|
||||
antlr4 -Dlanguage=Go -listener -visitor -o $dest_dir -package slq SLQ.g4
|
||||
|
||||
echo "Verifying that generated files can build..."
|
||||
|
11
install.sh
11
install.sh
@ -6,8 +6,9 @@
|
||||
|
||||
get_distribution() {
|
||||
lsb_dist=""
|
||||
# Every system that we officially support has /etc/os-release
|
||||
# Every Linux system that we officially support has /etc/os-release
|
||||
if [ -r /etc/os-release ]; then
|
||||
# shellcheck disable=SC1091
|
||||
lsb_dist="$(. /etc/os-release && echo "$ID")"
|
||||
fi
|
||||
# Returning an empty string here should be alright since the
|
||||
@ -102,12 +103,12 @@ if command_exists apk; then
|
||||
# Should be "x86_64" for amd64, and "aarch64" for arm64
|
||||
arch=$(uname -m)
|
||||
|
||||
if [ "$arch" == "x86_64" ]; then
|
||||
if [ "$arch" = "x86_64" ]; then
|
||||
arch="amd64"
|
||||
elif [ "$arch" == "aarch64" ]; then
|
||||
elif [ "$arch" = "aarch64" ]; then
|
||||
arch="arm64"
|
||||
else
|
||||
printf "sq install package not available for architecture %q\n" $arch
|
||||
printf "sq install package not available for architecture: %s\n" "$arch"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -133,7 +134,7 @@ fi
|
||||
|
||||
# Arch Linux
|
||||
if command_exists pacman; then
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
echo "AUR packages shouldn't be installed as root"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -10,6 +10,7 @@ package ast
|
||||
import (
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/lg"
|
||||
|
||||
@ -191,3 +192,54 @@ func (a *AST) AddSegment(seg *SegmentNode) {
|
||||
func errorf(format string, v ...any) error {
|
||||
return errz.Errorf(format, v...)
|
||||
}
|
||||
|
||||
// ParseCatalogSchema parses a string of the form 'catalog.schema'
|
||||
// and returns the catalog and schema. An error is returned if the schema
|
||||
// is empty (but catalog may be empty). Whitespace and quotes are handled
|
||||
// correctly.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// `catalog.schema` -> "catalog", "schema", nil
|
||||
// `schema` -> "", "schema", nil
|
||||
// `"my catalog"."my schema"` -> "my catalog", "my schema", nil
|
||||
//
|
||||
// An error is returned if s is empty.
|
||||
func ParseCatalogSchema(s string) (catalog, schema string, err error) {
|
||||
const errTpl = `invalid catalog.schema: %s`
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return "", "", errz.New("catalog.schema is empty")
|
||||
}
|
||||
|
||||
// We'll hijack the existing parser code. A value "catalog.schema" is
|
||||
// not valid, but ".catalog.schema" works as a selector.
|
||||
|
||||
sel := "." + s
|
||||
a, err := Parse(lg.Discard(), sel)
|
||||
if err != nil {
|
||||
return "", "", errz.Errorf(errTpl, s)
|
||||
}
|
||||
|
||||
if len(a.Segments()) != 1 {
|
||||
return "", "", errz.Errorf(errTpl, s)
|
||||
}
|
||||
|
||||
tblSel := NewInspector(a).FindFirstTableSelector()
|
||||
if tblSel == nil {
|
||||
return "", "", errz.Errorf(errTpl, s)
|
||||
}
|
||||
|
||||
if tblSel.name1 == "" {
|
||||
schema = tblSel.name0
|
||||
} else {
|
||||
catalog = tblSel.SelectorNode.name0
|
||||
schema = tblSel.SelectorNode.name1
|
||||
}
|
||||
if schema == "" {
|
||||
return "", "", errz.Errorf(errTpl, s)
|
||||
}
|
||||
|
||||
return catalog, schema, nil
|
||||
}
|
||||
|
40
libsq/ast/ast_test.go
Normal file
40
libsq/ast/ast_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package ast_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast"
|
||||
"github.com/neilotoole/sq/testh/tutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseCatalogSchema(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
wantCatalog, wantSchema string
|
||||
wantErr bool
|
||||
}{
|
||||
{in: "", wantErr: true},
|
||||
{in: "dbo", wantCatalog: "", wantSchema: "dbo"},
|
||||
{in: "sakila.dbo", wantCatalog: "sakila", wantSchema: "dbo"},
|
||||
{in: `"my catalog"."my schema"`, wantCatalog: "my catalog", wantSchema: "my schema"},
|
||||
{in: `"my catalog""."my schema"`, wantErr: true},
|
||||
{in: `"my catalog"."my schema"."my table"`, wantErr: true},
|
||||
{in: `catalog.schema.table`, wantErr: true},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tutil.Name(i, tc.in), func(t *testing.T) {
|
||||
gotCatalog, gotSchema, gotErr := ast.ParseCatalogSchema(tc.in)
|
||||
if tc.wantErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, gotErr)
|
||||
require.Equal(t, tc.wantCatalog, gotCatalog)
|
||||
require.Equal(t, tc.wantSchema, gotSchema)
|
||||
})
|
||||
}
|
||||
}
|
@ -6,6 +6,17 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/ast/internal/slq"
|
||||
)
|
||||
|
||||
const (
|
||||
FuncNameAvg = "avg"
|
||||
FuncNameCount = "count"
|
||||
FuncNameCountUnique = "count_unique"
|
||||
FuncNameMax = "max"
|
||||
FuncNameMin = "min"
|
||||
FuncNameSchema = "schema"
|
||||
FuncNameCatalog = "catalog"
|
||||
FuncNameSum = "sum"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Node = (*FuncNode)(nil)
|
||||
_ ResultColumn = (*FuncNode)(nil)
|
||||
|
@ -1,6 +1,9 @@
|
||||
package ast
|
||||
|
||||
import "github.com/neilotoole/sq/libsq/ast/internal/slq"
|
||||
import (
|
||||
"github.com/neilotoole/sq/libsq/ast/internal/slq"
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
)
|
||||
|
||||
// HandleNode models a source handle such as "@sakila".
|
||||
type HandleNode struct {
|
||||
@ -36,9 +39,11 @@ func (v *parseTreeVisitor) VisitHandleTable(ctx *slq.HandleTableContext) any {
|
||||
node.handle = ctx.HANDLE().GetText()
|
||||
|
||||
var err error
|
||||
if node.tblName, err = extractSelVal(ctx.NAME()); err != nil {
|
||||
selTbl, err := extractSelVal(ctx.NAME())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.tbl = tablefq.From(selTbl)
|
||||
|
||||
return v.cur.AddChild(node)
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -16,69 +16,75 @@ T__14=15
|
||||
T__15=16
|
||||
T__16=17
|
||||
T__17=18
|
||||
PROPRIETARY_FUNC_NAME=19
|
||||
JOIN_TYPE=20
|
||||
WHERE=21
|
||||
GROUP_BY=22
|
||||
ORDER_ASC=23
|
||||
ORDER_DESC=24
|
||||
ORDER_BY=25
|
||||
ALIAS_RESERVED=26
|
||||
ARG=27
|
||||
NULL=28
|
||||
ID=29
|
||||
WS=30
|
||||
LPAR=31
|
||||
RPAR=32
|
||||
LBRA=33
|
||||
RBRA=34
|
||||
COMMA=35
|
||||
PIPE=36
|
||||
COLON=37
|
||||
NN=38
|
||||
NUMBER=39
|
||||
LT_EQ=40
|
||||
LT=41
|
||||
GT_EQ=42
|
||||
GT=43
|
||||
NEQ=44
|
||||
EQ=45
|
||||
NAME=46
|
||||
HANDLE=47
|
||||
STRING=48
|
||||
LINECOMMENT=49
|
||||
T__18=19
|
||||
T__19=20
|
||||
T__20=21
|
||||
PROPRIETARY_FUNC_NAME=22
|
||||
JOIN_TYPE=23
|
||||
WHERE=24
|
||||
GROUP_BY=25
|
||||
ORDER_ASC=26
|
||||
ORDER_DESC=27
|
||||
ORDER_BY=28
|
||||
ALIAS_RESERVED=29
|
||||
ARG=30
|
||||
NULL=31
|
||||
ID=32
|
||||
WS=33
|
||||
LPAR=34
|
||||
RPAR=35
|
||||
LBRA=36
|
||||
RBRA=37
|
||||
COMMA=38
|
||||
PIPE=39
|
||||
COLON=40
|
||||
NN=41
|
||||
NUMBER=42
|
||||
LT_EQ=43
|
||||
LT=44
|
||||
GT_EQ=45
|
||||
GT=46
|
||||
NEQ=47
|
||||
EQ=48
|
||||
NAME=49
|
||||
HANDLE=50
|
||||
STRING=51
|
||||
LINECOMMENT=52
|
||||
';'=1
|
||||
'*'=2
|
||||
'sum'=3
|
||||
'avg'=4
|
||||
'max'=5
|
||||
'min'=6
|
||||
'unique'=7
|
||||
'count'=8
|
||||
'.['=9
|
||||
'||'=10
|
||||
'/'=11
|
||||
'%'=12
|
||||
'<<'=13
|
||||
'>>'=14
|
||||
'&'=15
|
||||
'&&'=16
|
||||
'~'=17
|
||||
'!'=18
|
||||
'group_by'=22
|
||||
'+'=23
|
||||
'-'=24
|
||||
'null'=28
|
||||
'('=31
|
||||
')'=32
|
||||
'['=33
|
||||
']'=34
|
||||
','=35
|
||||
'|'=36
|
||||
':'=37
|
||||
'<='=40
|
||||
'<'=41
|
||||
'>='=42
|
||||
'>'=43
|
||||
'!='=44
|
||||
'=='=45
|
||||
'schema'=7
|
||||
'catalog'=8
|
||||
'unique'=9
|
||||
'uniq'=10
|
||||
'count'=11
|
||||
'.['=12
|
||||
'||'=13
|
||||
'/'=14
|
||||
'%'=15
|
||||
'<<'=16
|
||||
'>>'=17
|
||||
'&'=18
|
||||
'&&'=19
|
||||
'~'=20
|
||||
'!'=21
|
||||
'group_by'=25
|
||||
'+'=26
|
||||
'-'=27
|
||||
'null'=31
|
||||
'('=34
|
||||
')'=35
|
||||
'['=36
|
||||
']'=37
|
||||
','=38
|
||||
'|'=39
|
||||
':'=40
|
||||
'<='=43
|
||||
'<'=44
|
||||
'>='=45
|
||||
'>'=46
|
||||
'!='=47
|
||||
'=='=48
|
||||
|
File diff suppressed because one or more lines are too long
@ -16,69 +16,75 @@ T__14=15
|
||||
T__15=16
|
||||
T__16=17
|
||||
T__17=18
|
||||
PROPRIETARY_FUNC_NAME=19
|
||||
JOIN_TYPE=20
|
||||
WHERE=21
|
||||
GROUP_BY=22
|
||||
ORDER_ASC=23
|
||||
ORDER_DESC=24
|
||||
ORDER_BY=25
|
||||
ALIAS_RESERVED=26
|
||||
ARG=27
|
||||
NULL=28
|
||||
ID=29
|
||||
WS=30
|
||||
LPAR=31
|
||||
RPAR=32
|
||||
LBRA=33
|
||||
RBRA=34
|
||||
COMMA=35
|
||||
PIPE=36
|
||||
COLON=37
|
||||
NN=38
|
||||
NUMBER=39
|
||||
LT_EQ=40
|
||||
LT=41
|
||||
GT_EQ=42
|
||||
GT=43
|
||||
NEQ=44
|
||||
EQ=45
|
||||
NAME=46
|
||||
HANDLE=47
|
||||
STRING=48
|
||||
LINECOMMENT=49
|
||||
T__18=19
|
||||
T__19=20
|
||||
T__20=21
|
||||
PROPRIETARY_FUNC_NAME=22
|
||||
JOIN_TYPE=23
|
||||
WHERE=24
|
||||
GROUP_BY=25
|
||||
ORDER_ASC=26
|
||||
ORDER_DESC=27
|
||||
ORDER_BY=28
|
||||
ALIAS_RESERVED=29
|
||||
ARG=30
|
||||
NULL=31
|
||||
ID=32
|
||||
WS=33
|
||||
LPAR=34
|
||||
RPAR=35
|
||||
LBRA=36
|
||||
RBRA=37
|
||||
COMMA=38
|
||||
PIPE=39
|
||||
COLON=40
|
||||
NN=41
|
||||
NUMBER=42
|
||||
LT_EQ=43
|
||||
LT=44
|
||||
GT_EQ=45
|
||||
GT=46
|
||||
NEQ=47
|
||||
EQ=48
|
||||
NAME=49
|
||||
HANDLE=50
|
||||
STRING=51
|
||||
LINECOMMENT=52
|
||||
';'=1
|
||||
'*'=2
|
||||
'sum'=3
|
||||
'avg'=4
|
||||
'max'=5
|
||||
'min'=6
|
||||
'unique'=7
|
||||
'count'=8
|
||||
'.['=9
|
||||
'||'=10
|
||||
'/'=11
|
||||
'%'=12
|
||||
'<<'=13
|
||||
'>>'=14
|
||||
'&'=15
|
||||
'&&'=16
|
||||
'~'=17
|
||||
'!'=18
|
||||
'group_by'=22
|
||||
'+'=23
|
||||
'-'=24
|
||||
'null'=28
|
||||
'('=31
|
||||
')'=32
|
||||
'['=33
|
||||
']'=34
|
||||
','=35
|
||||
'|'=36
|
||||
':'=37
|
||||
'<='=40
|
||||
'<'=41
|
||||
'>='=42
|
||||
'>'=43
|
||||
'!='=44
|
||||
'=='=45
|
||||
'schema'=7
|
||||
'catalog'=8
|
||||
'unique'=9
|
||||
'uniq'=10
|
||||
'count'=11
|
||||
'.['=12
|
||||
'||'=13
|
||||
'/'=14
|
||||
'%'=15
|
||||
'<<'=16
|
||||
'>>'=17
|
||||
'&'=18
|
||||
'&&'=19
|
||||
'~'=20
|
||||
'!'=21
|
||||
'group_by'=25
|
||||
'+'=26
|
||||
'-'=27
|
||||
'null'=31
|
||||
'('=34
|
||||
')'=35
|
||||
'['=36
|
||||
']'=37
|
||||
','=38
|
||||
'|'=39
|
||||
':'=40
|
||||
'<='=43
|
||||
'<'=44
|
||||
'>='=45
|
||||
'>'=46
|
||||
'!='=47
|
||||
'=='=48
|
||||
|
@ -43,34 +43,35 @@ func slqlexerLexerInit() {
|
||||
"DEFAULT_MODE",
|
||||
}
|
||||
staticData.LiteralNames = []string{
|
||||
"", "';'", "'*'", "'sum'", "'avg'", "'max'", "'min'", "'unique'", "'count'",
|
||||
"'.['", "'||'", "'/'", "'%'", "'<<'", "'>>'", "'&'", "'&&'", "'~'",
|
||||
"'!'", "", "", "", "'group_by'", "'+'", "'-'", "", "", "", "'null'",
|
||||
"", "", "'('", "')'", "'['", "']'", "','", "'|'", "':'", "", "", "'<='",
|
||||
"'<'", "'>='", "'>'", "'!='", "'=='",
|
||||
"", "';'", "'*'", "'sum'", "'avg'", "'max'", "'min'", "'schema'", "'catalog'",
|
||||
"'unique'", "'uniq'", "'count'", "'.['", "'||'", "'/'", "'%'", "'<<'",
|
||||
"'>>'", "'&'", "'&&'", "'~'", "'!'", "", "", "", "'group_by'", "'+'",
|
||||
"'-'", "", "", "", "'null'", "", "", "'('", "')'", "'['", "']'", "','",
|
||||
"'|'", "':'", "", "", "'<='", "'<'", "'>='", "'>'", "'!='", "'=='",
|
||||
}
|
||||
staticData.SymbolicNames = []string{
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE", "WHERE", "GROUP_BY", "ORDER_ASC",
|
||||
"ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED", "ARG", "NULL", "ID", "WS",
|
||||
"LPAR", "RPAR", "LBRA", "RBRA", "COMMA", "PIPE", "COLON", "NN", "NUMBER",
|
||||
"LT_EQ", "LT", "GT_EQ", "GT", "NEQ", "EQ", "NAME", "HANDLE", "STRING",
|
||||
"LINECOMMENT",
|
||||
"", "", "", "", "", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE", "WHERE", "GROUP_BY",
|
||||
"ORDER_ASC", "ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED", "ARG", "NULL",
|
||||
"ID", "WS", "LPAR", "RPAR", "LBRA", "RBRA", "COMMA", "PIPE", "COLON",
|
||||
"NN", "NUMBER", "LT_EQ", "LT", "GT_EQ", "GT", "NEQ", "EQ", "NAME", "HANDLE",
|
||||
"STRING", "LINECOMMENT",
|
||||
}
|
||||
staticData.RuleNames = []string{
|
||||
"T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
|
||||
"T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16",
|
||||
"T__17", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE", "WHERE", "GROUP_BY",
|
||||
"ORDER_ASC", "ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED", "ARG", "NULL",
|
||||
"ID", "WS", "LPAR", "RPAR", "LBRA", "RBRA", "COMMA", "PIPE", "COLON",
|
||||
"NN", "NUMBER", "INTF", "EXP", "LT_EQ", "LT", "GT_EQ", "GT", "NEQ",
|
||||
"EQ", "NAME", "HANDLE", "STRING", "ESC", "UNICODE", "HEX", "DIGIT",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "LINECOMMENT",
|
||||
"T__17", "T__18", "T__19", "T__20", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE",
|
||||
"WHERE", "GROUP_BY", "ORDER_ASC", "ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED",
|
||||
"ARG", "NULL", "ID", "WS", "LPAR", "RPAR", "LBRA", "RBRA", "COMMA",
|
||||
"PIPE", "COLON", "NN", "NUMBER", "INTF", "EXP", "LT_EQ", "LT", "GT_EQ",
|
||||
"GT", "NEQ", "EQ", "NAME", "HANDLE", "STRING", "ESC", "UNICODE", "HEX",
|
||||
"DIGIT", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
|
||||
"M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"LINECOMMENT",
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 0, 49, 648, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
|
||||
4, 0, 52, 674, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
|
||||
4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2,
|
||||
10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15,
|
||||
7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7,
|
||||
@ -85,283 +86,294 @@ func slqlexerLexerInit() {
|
||||
62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67,
|
||||
2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2,
|
||||
73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78,
|
||||
7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2,
|
||||
1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5,
|
||||
1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7,
|
||||
1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1,
|
||||
11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15,
|
||||
1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1,
|
||||
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19,
|
||||
1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 347, 8, 19, 1, 20, 1, 20, 1,
|
||||
20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 3, 20, 360,
|
||||
8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1,
|
||||
22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24,
|
||||
1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 3, 24, 390, 8,
|
||||
24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25,
|
||||
1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1,
|
||||
25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25,
|
||||
1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1,
|
||||
25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25,
|
||||
1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 448, 8, 25, 1, 26, 1, 26, 1, 26, 1,
|
||||
27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 5, 28, 460, 8, 28, 10, 28,
|
||||
12, 28, 463, 9, 28, 1, 29, 4, 29, 466, 8, 29, 11, 29, 12, 29, 467, 1, 29,
|
||||
1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1,
|
||||
34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 3, 38, 490,
|
||||
8, 38, 1, 38, 1, 38, 1, 38, 4, 38, 495, 8, 38, 11, 38, 12, 38, 496, 1,
|
||||
38, 3, 38, 500, 8, 38, 1, 38, 3, 38, 503, 8, 38, 1, 38, 1, 38, 1, 38, 1,
|
||||
38, 3, 38, 509, 8, 38, 1, 38, 3, 38, 512, 8, 38, 1, 39, 1, 39, 1, 39, 5,
|
||||
39, 517, 8, 39, 10, 39, 12, 39, 520, 9, 39, 3, 39, 522, 8, 39, 1, 40, 1,
|
||||
40, 3, 40, 526, 8, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42,
|
||||
1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1,
|
||||
46, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 550, 8, 47, 1, 48, 1, 48, 1, 48,
|
||||
1, 48, 5, 48, 556, 8, 48, 10, 48, 12, 48, 559, 9, 48, 1, 49, 1, 49, 1,
|
||||
49, 5, 49, 564, 8, 49, 10, 49, 12, 49, 567, 9, 49, 1, 49, 1, 49, 1, 50,
|
||||
1, 50, 1, 50, 3, 50, 574, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1,
|
||||
51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56,
|
||||
1, 57, 1, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1,
|
||||
62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67,
|
||||
1, 67, 1, 68, 1, 68, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1,
|
||||
72, 1, 73, 1, 73, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77,
|
||||
1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 5, 80, 640, 8, 80, 10, 80, 12,
|
||||
80, 643, 9, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 641, 0, 81, 1, 1, 3, 2,
|
||||
5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25,
|
||||
13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43,
|
||||
22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61,
|
||||
31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79,
|
||||
0, 81, 0, 83, 40, 85, 41, 87, 42, 89, 43, 91, 44, 93, 45, 95, 46, 97, 47,
|
||||
99, 48, 101, 0, 103, 0, 105, 0, 107, 0, 109, 0, 111, 0, 113, 0, 115, 0,
|
||||
117, 0, 119, 0, 121, 0, 123, 0, 125, 0, 127, 0, 129, 0, 131, 0, 133, 0,
|
||||
135, 0, 137, 0, 139, 0, 141, 0, 143, 0, 145, 0, 147, 0, 149, 0, 151, 0,
|
||||
153, 0, 155, 0, 157, 0, 159, 0, 161, 49, 1, 0, 35, 3, 0, 65, 90, 95, 95,
|
||||
97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32,
|
||||
32, 1, 0, 48, 57, 1, 0, 49, 57, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45,
|
||||
45, 2, 0, 34, 34, 92, 92, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102,
|
||||
110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65,
|
||||
65, 97, 97, 2, 0, 66, 66, 98, 98, 2, 0, 67, 67, 99, 99, 2, 0, 68, 68, 100,
|
||||
100, 2, 0, 70, 70, 102, 102, 2, 0, 71, 71, 103, 103, 2, 0, 72, 72, 104,
|
||||
104, 2, 0, 73, 73, 105, 105, 2, 0, 74, 74, 106, 106, 2, 0, 75, 75, 107,
|
||||
107, 2, 0, 76, 76, 108, 108, 2, 0, 77, 77, 109, 109, 2, 0, 78, 78, 110,
|
||||
110, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 81, 81, 113,
|
||||
113, 2, 0, 82, 82, 114, 114, 2, 0, 83, 83, 115, 115, 2, 0, 84, 84, 116,
|
||||
116, 2, 0, 85, 85, 117, 117, 2, 0, 86, 86, 118, 118, 2, 0, 87, 87, 119,
|
||||
119, 2, 0, 88, 88, 120, 120, 2, 0, 89, 89, 121, 121, 2, 0, 90, 90, 122,
|
||||
122, 657, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1,
|
||||
0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15,
|
||||
1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0,
|
||||
23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0,
|
||||
0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0,
|
||||
0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0,
|
||||
0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1,
|
||||
0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61,
|
||||
1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0,
|
||||
69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0,
|
||||
0, 77, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0,
|
||||
0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0,
|
||||
0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 1, 163,
|
||||
1, 0, 0, 0, 3, 165, 1, 0, 0, 0, 5, 167, 1, 0, 0, 0, 7, 171, 1, 0, 0, 0,
|
||||
9, 175, 1, 0, 0, 0, 11, 179, 1, 0, 0, 0, 13, 183, 1, 0, 0, 0, 15, 190,
|
||||
1, 0, 0, 0, 17, 196, 1, 0, 0, 0, 19, 199, 1, 0, 0, 0, 21, 202, 1, 0, 0,
|
||||
0, 23, 204, 1, 0, 0, 0, 25, 206, 1, 0, 0, 0, 27, 209, 1, 0, 0, 0, 29, 212,
|
||||
1, 0, 0, 0, 31, 214, 1, 0, 0, 0, 33, 217, 1, 0, 0, 0, 35, 219, 1, 0, 0,
|
||||
0, 37, 221, 1, 0, 0, 0, 39, 346, 1, 0, 0, 0, 41, 359, 1, 0, 0, 0, 43, 361,
|
||||
1, 0, 0, 0, 45, 370, 1, 0, 0, 0, 47, 372, 1, 0, 0, 0, 49, 389, 1, 0, 0,
|
||||
0, 51, 447, 1, 0, 0, 0, 53, 449, 1, 0, 0, 0, 55, 452, 1, 0, 0, 0, 57, 457,
|
||||
1, 0, 0, 0, 59, 465, 1, 0, 0, 0, 61, 471, 1, 0, 0, 0, 63, 473, 1, 0, 0,
|
||||
0, 65, 475, 1, 0, 0, 0, 67, 477, 1, 0, 0, 0, 69, 479, 1, 0, 0, 0, 71, 481,
|
||||
1, 0, 0, 0, 73, 483, 1, 0, 0, 0, 75, 485, 1, 0, 0, 0, 77, 511, 1, 0, 0,
|
||||
0, 79, 521, 1, 0, 0, 0, 81, 523, 1, 0, 0, 0, 83, 529, 1, 0, 0, 0, 85, 532,
|
||||
1, 0, 0, 0, 87, 534, 1, 0, 0, 0, 89, 537, 1, 0, 0, 0, 91, 539, 1, 0, 0,
|
||||
0, 93, 542, 1, 0, 0, 0, 95, 545, 1, 0, 0, 0, 97, 551, 1, 0, 0, 0, 99, 560,
|
||||
1, 0, 0, 0, 101, 570, 1, 0, 0, 0, 103, 575, 1, 0, 0, 0, 105, 581, 1, 0,
|
||||
0, 0, 107, 583, 1, 0, 0, 0, 109, 585, 1, 0, 0, 0, 111, 587, 1, 0, 0, 0,
|
||||
113, 589, 1, 0, 0, 0, 115, 591, 1, 0, 0, 0, 117, 593, 1, 0, 0, 0, 119,
|
||||
595, 1, 0, 0, 0, 121, 597, 1, 0, 0, 0, 123, 599, 1, 0, 0, 0, 125, 601,
|
||||
1, 0, 0, 0, 127, 603, 1, 0, 0, 0, 129, 605, 1, 0, 0, 0, 131, 607, 1, 0,
|
||||
0, 0, 133, 609, 1, 0, 0, 0, 135, 611, 1, 0, 0, 0, 137, 613, 1, 0, 0, 0,
|
||||
139, 615, 1, 0, 0, 0, 141, 617, 1, 0, 0, 0, 143, 619, 1, 0, 0, 0, 145,
|
||||
621, 1, 0, 0, 0, 147, 623, 1, 0, 0, 0, 149, 625, 1, 0, 0, 0, 151, 627,
|
||||
1, 0, 0, 0, 153, 629, 1, 0, 0, 0, 155, 631, 1, 0, 0, 0, 157, 633, 1, 0,
|
||||
0, 0, 159, 635, 1, 0, 0, 0, 161, 637, 1, 0, 0, 0, 163, 164, 5, 59, 0, 0,
|
||||
164, 2, 1, 0, 0, 0, 165, 166, 5, 42, 0, 0, 166, 4, 1, 0, 0, 0, 167, 168,
|
||||
5, 115, 0, 0, 168, 169, 5, 117, 0, 0, 169, 170, 5, 109, 0, 0, 170, 6, 1,
|
||||
0, 0, 0, 171, 172, 5, 97, 0, 0, 172, 173, 5, 118, 0, 0, 173, 174, 5, 103,
|
||||
0, 0, 174, 8, 1, 0, 0, 0, 175, 176, 5, 109, 0, 0, 176, 177, 5, 97, 0, 0,
|
||||
177, 178, 5, 120, 0, 0, 178, 10, 1, 0, 0, 0, 179, 180, 5, 109, 0, 0, 180,
|
||||
181, 5, 105, 0, 0, 181, 182, 5, 110, 0, 0, 182, 12, 1, 0, 0, 0, 183, 184,
|
||||
5, 117, 0, 0, 184, 185, 5, 110, 0, 0, 185, 186, 5, 105, 0, 0, 186, 187,
|
||||
5, 113, 0, 0, 187, 188, 5, 117, 0, 0, 188, 189, 5, 101, 0, 0, 189, 14,
|
||||
1, 0, 0, 0, 190, 191, 5, 99, 0, 0, 191, 192, 5, 111, 0, 0, 192, 193, 5,
|
||||
117, 0, 0, 193, 194, 5, 110, 0, 0, 194, 195, 5, 116, 0, 0, 195, 16, 1,
|
||||
0, 0, 0, 196, 197, 5, 46, 0, 0, 197, 198, 5, 91, 0, 0, 198, 18, 1, 0, 0,
|
||||
0, 199, 200, 5, 124, 0, 0, 200, 201, 5, 124, 0, 0, 201, 20, 1, 0, 0, 0,
|
||||
202, 203, 5, 47, 0, 0, 203, 22, 1, 0, 0, 0, 204, 205, 5, 37, 0, 0, 205,
|
||||
24, 1, 0, 0, 0, 206, 207, 5, 60, 0, 0, 207, 208, 5, 60, 0, 0, 208, 26,
|
||||
1, 0, 0, 0, 209, 210, 5, 62, 0, 0, 210, 211, 5, 62, 0, 0, 211, 28, 1, 0,
|
||||
0, 0, 212, 213, 5, 38, 0, 0, 213, 30, 1, 0, 0, 0, 214, 215, 5, 38, 0, 0,
|
||||
215, 216, 5, 38, 0, 0, 216, 32, 1, 0, 0, 0, 217, 218, 5, 126, 0, 0, 218,
|
||||
34, 1, 0, 0, 0, 219, 220, 5, 33, 0, 0, 220, 36, 1, 0, 0, 0, 221, 222, 5,
|
||||
95, 0, 0, 222, 223, 3, 57, 28, 0, 223, 38, 1, 0, 0, 0, 224, 225, 5, 106,
|
||||
0, 0, 225, 226, 5, 111, 0, 0, 226, 227, 5, 105, 0, 0, 227, 347, 5, 110,
|
||||
0, 0, 228, 229, 5, 105, 0, 0, 229, 230, 5, 110, 0, 0, 230, 231, 5, 110,
|
||||
0, 0, 231, 232, 5, 101, 0, 0, 232, 233, 5, 114, 0, 0, 233, 234, 5, 95,
|
||||
0, 0, 234, 235, 5, 106, 0, 0, 235, 236, 5, 111, 0, 0, 236, 237, 5, 105,
|
||||
0, 0, 237, 347, 5, 110, 0, 0, 238, 239, 5, 108, 0, 0, 239, 240, 5, 101,
|
||||
0, 0, 240, 241, 5, 102, 0, 0, 241, 242, 5, 116, 0, 0, 242, 243, 5, 95,
|
||||
0, 0, 243, 244, 5, 106, 0, 0, 244, 245, 5, 111, 0, 0, 245, 246, 5, 105,
|
||||
0, 0, 246, 347, 5, 110, 0, 0, 247, 248, 5, 108, 0, 0, 248, 249, 5, 106,
|
||||
0, 0, 249, 250, 5, 111, 0, 0, 250, 251, 5, 105, 0, 0, 251, 347, 5, 110,
|
||||
0, 0, 252, 253, 5, 108, 0, 0, 253, 254, 5, 101, 0, 0, 254, 255, 5, 102,
|
||||
0, 0, 255, 256, 5, 116, 0, 0, 256, 257, 5, 95, 0, 0, 257, 258, 5, 111,
|
||||
0, 0, 258, 259, 5, 117, 0, 0, 259, 260, 5, 116, 0, 0, 260, 261, 5, 101,
|
||||
0, 0, 261, 262, 5, 114, 0, 0, 262, 263, 5, 95, 0, 0, 263, 264, 5, 106,
|
||||
0, 0, 264, 265, 5, 111, 0, 0, 265, 266, 5, 105, 0, 0, 266, 347, 5, 110,
|
||||
0, 0, 267, 268, 5, 108, 0, 0, 268, 269, 5, 111, 0, 0, 269, 270, 5, 106,
|
||||
0, 0, 270, 271, 5, 111, 0, 0, 271, 272, 5, 105, 0, 0, 272, 347, 5, 110,
|
||||
0, 0, 273, 274, 5, 114, 0, 0, 274, 275, 5, 105, 0, 0, 275, 276, 5, 103,
|
||||
0, 0, 276, 277, 5, 104, 0, 0, 277, 278, 5, 116, 0, 0, 278, 279, 5, 95,
|
||||
0, 0, 279, 280, 5, 106, 0, 0, 280, 281, 5, 111, 0, 0, 281, 282, 5, 105,
|
||||
0, 0, 282, 347, 5, 110, 0, 0, 283, 284, 5, 114, 0, 0, 284, 285, 5, 106,
|
||||
0, 0, 285, 286, 5, 111, 0, 0, 286, 287, 5, 105, 0, 0, 287, 347, 5, 110,
|
||||
0, 0, 288, 289, 5, 114, 0, 0, 289, 290, 5, 105, 0, 0, 290, 291, 5, 103,
|
||||
0, 0, 291, 292, 5, 104, 0, 0, 292, 293, 5, 116, 0, 0, 293, 294, 5, 95,
|
||||
0, 0, 294, 295, 5, 111, 0, 0, 295, 296, 5, 117, 0, 0, 296, 297, 5, 116,
|
||||
0, 0, 297, 298, 5, 101, 0, 0, 298, 299, 5, 114, 0, 0, 299, 300, 5, 95,
|
||||
0, 0, 300, 301, 5, 106, 0, 0, 301, 302, 5, 111, 0, 0, 302, 303, 5, 105,
|
||||
0, 0, 303, 347, 5, 110, 0, 0, 304, 305, 5, 114, 0, 0, 305, 306, 5, 111,
|
||||
0, 0, 306, 307, 5, 106, 0, 0, 307, 308, 5, 111, 0, 0, 308, 309, 5, 105,
|
||||
0, 0, 309, 347, 5, 110, 0, 0, 310, 311, 5, 102, 0, 0, 311, 312, 5, 117,
|
||||
0, 0, 312, 313, 5, 108, 0, 0, 313, 314, 5, 108, 0, 0, 314, 315, 5, 95,
|
||||
0, 0, 315, 316, 5, 111, 0, 0, 316, 317, 5, 117, 0, 0, 317, 318, 5, 116,
|
||||
0, 0, 318, 319, 5, 101, 0, 0, 319, 320, 5, 114, 0, 0, 320, 321, 5, 95,
|
||||
0, 0, 321, 322, 5, 106, 0, 0, 322, 323, 5, 111, 0, 0, 323, 324, 5, 105,
|
||||
0, 0, 324, 347, 5, 110, 0, 0, 325, 326, 5, 102, 0, 0, 326, 327, 5, 111,
|
||||
0, 0, 327, 328, 5, 106, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 105,
|
||||
0, 0, 330, 347, 5, 110, 0, 0, 331, 332, 5, 99, 0, 0, 332, 333, 5, 114,
|
||||
0, 0, 333, 334, 5, 111, 0, 0, 334, 335, 5, 115, 0, 0, 335, 336, 5, 115,
|
||||
0, 0, 336, 337, 5, 95, 0, 0, 337, 338, 5, 106, 0, 0, 338, 339, 5, 111,
|
||||
0, 0, 339, 340, 5, 105, 0, 0, 340, 347, 5, 110, 0, 0, 341, 342, 5, 120,
|
||||
0, 0, 342, 343, 5, 106, 0, 0, 343, 344, 5, 111, 0, 0, 344, 345, 5, 105,
|
||||
0, 0, 345, 347, 5, 110, 0, 0, 346, 224, 1, 0, 0, 0, 346, 228, 1, 0, 0,
|
||||
0, 346, 238, 1, 0, 0, 0, 346, 247, 1, 0, 0, 0, 346, 252, 1, 0, 0, 0, 346,
|
||||
267, 1, 0, 0, 0, 346, 273, 1, 0, 0, 0, 346, 283, 1, 0, 0, 0, 346, 288,
|
||||
1, 0, 0, 0, 346, 304, 1, 0, 0, 0, 346, 310, 1, 0, 0, 0, 346, 325, 1, 0,
|
||||
0, 0, 346, 331, 1, 0, 0, 0, 346, 341, 1, 0, 0, 0, 347, 40, 1, 0, 0, 0,
|
||||
348, 349, 5, 119, 0, 0, 349, 350, 5, 104, 0, 0, 350, 351, 5, 101, 0, 0,
|
||||
351, 352, 5, 114, 0, 0, 352, 360, 5, 101, 0, 0, 353, 354, 5, 115, 0, 0,
|
||||
354, 355, 5, 101, 0, 0, 355, 356, 5, 108, 0, 0, 356, 357, 5, 101, 0, 0,
|
||||
357, 358, 5, 99, 0, 0, 358, 360, 5, 116, 0, 0, 359, 348, 1, 0, 0, 0, 359,
|
||||
353, 1, 0, 0, 0, 360, 42, 1, 0, 0, 0, 361, 362, 5, 103, 0, 0, 362, 363,
|
||||
5, 114, 0, 0, 363, 364, 5, 111, 0, 0, 364, 365, 5, 117, 0, 0, 365, 366,
|
||||
5, 112, 0, 0, 366, 367, 5, 95, 0, 0, 367, 368, 5, 98, 0, 0, 368, 369, 5,
|
||||
121, 0, 0, 369, 44, 1, 0, 0, 0, 370, 371, 5, 43, 0, 0, 371, 46, 1, 0, 0,
|
||||
0, 372, 373, 5, 45, 0, 0, 373, 48, 1, 0, 0, 0, 374, 375, 5, 111, 0, 0,
|
||||
375, 376, 5, 114, 0, 0, 376, 377, 5, 100, 0, 0, 377, 378, 5, 101, 0, 0,
|
||||
378, 379, 5, 114, 0, 0, 379, 380, 5, 95, 0, 0, 380, 381, 5, 98, 0, 0, 381,
|
||||
390, 5, 121, 0, 0, 382, 383, 5, 115, 0, 0, 383, 384, 5, 111, 0, 0, 384,
|
||||
385, 5, 114, 0, 0, 385, 386, 5, 116, 0, 0, 386, 387, 5, 95, 0, 0, 387,
|
||||
388, 5, 98, 0, 0, 388, 390, 5, 121, 0, 0, 389, 374, 1, 0, 0, 0, 389, 382,
|
||||
1, 0, 0, 0, 390, 50, 1, 0, 0, 0, 391, 392, 5, 58, 0, 0, 392, 393, 5, 99,
|
||||
0, 0, 393, 394, 5, 111, 0, 0, 394, 395, 5, 117, 0, 0, 395, 396, 5, 110,
|
||||
0, 0, 396, 448, 5, 116, 0, 0, 397, 398, 5, 58, 0, 0, 398, 399, 5, 99, 0,
|
||||
0, 399, 400, 5, 111, 0, 0, 400, 401, 5, 117, 0, 0, 401, 402, 5, 110, 0,
|
||||
0, 402, 403, 5, 116, 0, 0, 403, 404, 5, 95, 0, 0, 404, 405, 5, 117, 0,
|
||||
0, 405, 406, 5, 110, 0, 0, 406, 407, 5, 105, 0, 0, 407, 408, 5, 113, 0,
|
||||
0, 408, 409, 5, 117, 0, 0, 409, 448, 5, 101, 0, 0, 410, 411, 5, 58, 0,
|
||||
0, 411, 412, 5, 97, 0, 0, 412, 413, 5, 118, 0, 0, 413, 448, 5, 103, 0,
|
||||
0, 414, 415, 5, 58, 0, 0, 415, 416, 5, 103, 0, 0, 416, 417, 5, 114, 0,
|
||||
0, 417, 418, 5, 111, 0, 0, 418, 419, 5, 117, 0, 0, 419, 420, 5, 112, 0,
|
||||
0, 420, 421, 5, 95, 0, 0, 421, 422, 5, 98, 0, 0, 422, 448, 5, 121, 0, 0,
|
||||
423, 424, 5, 58, 0, 0, 424, 425, 5, 109, 0, 0, 425, 426, 5, 97, 0, 0, 426,
|
||||
448, 5, 120, 0, 0, 427, 428, 5, 58, 0, 0, 428, 429, 5, 109, 0, 0, 429,
|
||||
430, 5, 105, 0, 0, 430, 448, 5, 110, 0, 0, 431, 432, 5, 58, 0, 0, 432,
|
||||
433, 5, 111, 0, 0, 433, 434, 5, 114, 0, 0, 434, 435, 5, 100, 0, 0, 435,
|
||||
436, 5, 101, 0, 0, 436, 437, 5, 114, 0, 0, 437, 438, 5, 95, 0, 0, 438,
|
||||
439, 5, 98, 0, 0, 439, 448, 5, 121, 0, 0, 440, 441, 5, 58, 0, 0, 441, 442,
|
||||
5, 117, 0, 0, 442, 443, 5, 110, 0, 0, 443, 444, 5, 105, 0, 0, 444, 445,
|
||||
5, 113, 0, 0, 445, 446, 5, 117, 0, 0, 446, 448, 5, 101, 0, 0, 447, 391,
|
||||
1, 0, 0, 0, 447, 397, 1, 0, 0, 0, 447, 410, 1, 0, 0, 0, 447, 414, 1, 0,
|
||||
0, 0, 447, 423, 1, 0, 0, 0, 447, 427, 1, 0, 0, 0, 447, 431, 1, 0, 0, 0,
|
||||
447, 440, 1, 0, 0, 0, 448, 52, 1, 0, 0, 0, 449, 450, 5, 36, 0, 0, 450,
|
||||
451, 3, 57, 28, 0, 451, 54, 1, 0, 0, 0, 452, 453, 5, 110, 0, 0, 453, 454,
|
||||
5, 117, 0, 0, 454, 455, 5, 108, 0, 0, 455, 456, 5, 108, 0, 0, 456, 56,
|
||||
1, 0, 0, 0, 457, 461, 7, 0, 0, 0, 458, 460, 7, 1, 0, 0, 459, 458, 1, 0,
|
||||
0, 0, 460, 463, 1, 0, 0, 0, 461, 459, 1, 0, 0, 0, 461, 462, 1, 0, 0, 0,
|
||||
462, 58, 1, 0, 0, 0, 463, 461, 1, 0, 0, 0, 464, 466, 7, 2, 0, 0, 465, 464,
|
||||
1, 0, 0, 0, 466, 467, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0,
|
||||
0, 0, 468, 469, 1, 0, 0, 0, 469, 470, 6, 29, 0, 0, 470, 60, 1, 0, 0, 0,
|
||||
471, 472, 5, 40, 0, 0, 472, 62, 1, 0, 0, 0, 473, 474, 5, 41, 0, 0, 474,
|
||||
64, 1, 0, 0, 0, 475, 476, 5, 91, 0, 0, 476, 66, 1, 0, 0, 0, 477, 478, 5,
|
||||
93, 0, 0, 478, 68, 1, 0, 0, 0, 479, 480, 5, 44, 0, 0, 480, 70, 1, 0, 0,
|
||||
0, 481, 482, 5, 124, 0, 0, 482, 72, 1, 0, 0, 0, 483, 484, 5, 58, 0, 0,
|
||||
484, 74, 1, 0, 0, 0, 485, 486, 3, 79, 39, 0, 486, 76, 1, 0, 0, 0, 487,
|
||||
512, 3, 75, 37, 0, 488, 490, 5, 45, 0, 0, 489, 488, 1, 0, 0, 0, 489, 490,
|
||||
1, 0, 0, 0, 490, 491, 1, 0, 0, 0, 491, 492, 3, 79, 39, 0, 492, 494, 5,
|
||||
46, 0, 0, 493, 495, 7, 3, 0, 0, 494, 493, 1, 0, 0, 0, 495, 496, 1, 0, 0,
|
||||
0, 496, 494, 1, 0, 0, 0, 496, 497, 1, 0, 0, 0, 497, 499, 1, 0, 0, 0, 498,
|
||||
500, 3, 81, 40, 0, 499, 498, 1, 0, 0, 0, 499, 500, 1, 0, 0, 0, 500, 512,
|
||||
1, 0, 0, 0, 501, 503, 5, 45, 0, 0, 502, 501, 1, 0, 0, 0, 502, 503, 1, 0,
|
||||
0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 3, 79, 39, 0, 505, 506, 3, 81, 40,
|
||||
0, 506, 512, 1, 0, 0, 0, 507, 509, 5, 45, 0, 0, 508, 507, 1, 0, 0, 0, 508,
|
||||
509, 1, 0, 0, 0, 509, 510, 1, 0, 0, 0, 510, 512, 3, 79, 39, 0, 511, 487,
|
||||
1, 0, 0, 0, 511, 489, 1, 0, 0, 0, 511, 502, 1, 0, 0, 0, 511, 508, 1, 0,
|
||||
0, 0, 512, 78, 1, 0, 0, 0, 513, 522, 5, 48, 0, 0, 514, 518, 7, 4, 0, 0,
|
||||
515, 517, 7, 3, 0, 0, 516, 515, 1, 0, 0, 0, 517, 520, 1, 0, 0, 0, 518,
|
||||
516, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 522, 1, 0, 0, 0, 520, 518,
|
||||
1, 0, 0, 0, 521, 513, 1, 0, 0, 0, 521, 514, 1, 0, 0, 0, 522, 80, 1, 0,
|
||||
0, 0, 523, 525, 7, 5, 0, 0, 524, 526, 7, 6, 0, 0, 525, 524, 1, 0, 0, 0,
|
||||
525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 3, 79, 39, 0, 528,
|
||||
82, 1, 0, 0, 0, 529, 530, 5, 60, 0, 0, 530, 531, 5, 61, 0, 0, 531, 84,
|
||||
1, 0, 0, 0, 532, 533, 5, 60, 0, 0, 533, 86, 1, 0, 0, 0, 534, 535, 5, 62,
|
||||
0, 0, 535, 536, 5, 61, 0, 0, 536, 88, 1, 0, 0, 0, 537, 538, 5, 62, 0, 0,
|
||||
538, 90, 1, 0, 0, 0, 539, 540, 5, 33, 0, 0, 540, 541, 5, 61, 0, 0, 541,
|
||||
92, 1, 0, 0, 0, 542, 543, 5, 61, 0, 0, 543, 544, 5, 61, 0, 0, 544, 94,
|
||||
1, 0, 0, 0, 545, 549, 5, 46, 0, 0, 546, 550, 3, 53, 26, 0, 547, 550, 3,
|
||||
57, 28, 0, 548, 550, 3, 99, 49, 0, 549, 546, 1, 0, 0, 0, 549, 547, 1, 0,
|
||||
0, 0, 549, 548, 1, 0, 0, 0, 550, 96, 1, 0, 0, 0, 551, 552, 5, 64, 0, 0,
|
||||
552, 557, 3, 57, 28, 0, 553, 554, 5, 47, 0, 0, 554, 556, 3, 57, 28, 0,
|
||||
555, 553, 1, 0, 0, 0, 556, 559, 1, 0, 0, 0, 557, 555, 1, 0, 0, 0, 557,
|
||||
558, 1, 0, 0, 0, 558, 98, 1, 0, 0, 0, 559, 557, 1, 0, 0, 0, 560, 565, 5,
|
||||
34, 0, 0, 561, 564, 3, 101, 50, 0, 562, 564, 8, 7, 0, 0, 563, 561, 1, 0,
|
||||
0, 0, 563, 562, 1, 0, 0, 0, 564, 567, 1, 0, 0, 0, 565, 563, 1, 0, 0, 0,
|
||||
565, 566, 1, 0, 0, 0, 566, 568, 1, 0, 0, 0, 567, 565, 1, 0, 0, 0, 568,
|
||||
569, 5, 34, 0, 0, 569, 100, 1, 0, 0, 0, 570, 573, 5, 92, 0, 0, 571, 574,
|
||||
7, 8, 0, 0, 572, 574, 3, 103, 51, 0, 573, 571, 1, 0, 0, 0, 573, 572, 1,
|
||||
0, 0, 0, 574, 102, 1, 0, 0, 0, 575, 576, 5, 117, 0, 0, 576, 577, 3, 105,
|
||||
52, 0, 577, 578, 3, 105, 52, 0, 578, 579, 3, 105, 52, 0, 579, 580, 3, 105,
|
||||
52, 0, 580, 104, 1, 0, 0, 0, 581, 582, 7, 9, 0, 0, 582, 106, 1, 0, 0, 0,
|
||||
583, 584, 7, 3, 0, 0, 584, 108, 1, 0, 0, 0, 585, 586, 7, 10, 0, 0, 586,
|
||||
110, 1, 0, 0, 0, 587, 588, 7, 11, 0, 0, 588, 112, 1, 0, 0, 0, 589, 590,
|
||||
7, 12, 0, 0, 590, 114, 1, 0, 0, 0, 591, 592, 7, 13, 0, 0, 592, 116, 1,
|
||||
0, 0, 0, 593, 594, 7, 5, 0, 0, 594, 118, 1, 0, 0, 0, 595, 596, 7, 14, 0,
|
||||
0, 596, 120, 1, 0, 0, 0, 597, 598, 7, 15, 0, 0, 598, 122, 1, 0, 0, 0, 599,
|
||||
600, 7, 16, 0, 0, 600, 124, 1, 0, 0, 0, 601, 602, 7, 17, 0, 0, 602, 126,
|
||||
1, 0, 0, 0, 603, 604, 7, 18, 0, 0, 604, 128, 1, 0, 0, 0, 605, 606, 7, 19,
|
||||
0, 0, 606, 130, 1, 0, 0, 0, 607, 608, 7, 20, 0, 0, 608, 132, 1, 0, 0, 0,
|
||||
609, 610, 7, 21, 0, 0, 610, 134, 1, 0, 0, 0, 611, 612, 7, 22, 0, 0, 612,
|
||||
136, 1, 0, 0, 0, 613, 614, 7, 23, 0, 0, 614, 138, 1, 0, 0, 0, 615, 616,
|
||||
7, 24, 0, 0, 616, 140, 1, 0, 0, 0, 617, 618, 7, 25, 0, 0, 618, 142, 1,
|
||||
0, 0, 0, 619, 620, 7, 26, 0, 0, 620, 144, 1, 0, 0, 0, 621, 622, 7, 27,
|
||||
0, 0, 622, 146, 1, 0, 0, 0, 623, 624, 7, 28, 0, 0, 624, 148, 1, 0, 0, 0,
|
||||
625, 626, 7, 29, 0, 0, 626, 150, 1, 0, 0, 0, 627, 628, 7, 30, 0, 0, 628,
|
||||
152, 1, 0, 0, 0, 629, 630, 7, 31, 0, 0, 630, 154, 1, 0, 0, 0, 631, 632,
|
||||
7, 32, 0, 0, 632, 156, 1, 0, 0, 0, 633, 634, 7, 33, 0, 0, 634, 158, 1,
|
||||
0, 0, 0, 635, 636, 7, 34, 0, 0, 636, 160, 1, 0, 0, 0, 637, 641, 5, 35,
|
||||
0, 0, 638, 640, 9, 0, 0, 0, 639, 638, 1, 0, 0, 0, 640, 643, 1, 0, 0, 0,
|
||||
641, 642, 1, 0, 0, 0, 641, 639, 1, 0, 0, 0, 642, 644, 1, 0, 0, 0, 643,
|
||||
641, 1, 0, 0, 0, 644, 645, 5, 10, 0, 0, 645, 646, 1, 0, 0, 0, 646, 647,
|
||||
6, 80, 0, 0, 647, 162, 1, 0, 0, 0, 22, 0, 346, 359, 389, 447, 461, 467,
|
||||
489, 496, 499, 502, 508, 511, 518, 521, 525, 549, 557, 563, 565, 573, 641,
|
||||
1, 6, 0, 0,
|
||||
7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7,
|
||||
83, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1,
|
||||
3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1,
|
||||
6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1,
|
||||
8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1,
|
||||
10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12,
|
||||
1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1,
|
||||
16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21,
|
||||
1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22,
|
||||
1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22,
|
||||
1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22,
|
||||
1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22,
|
||||
1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22,
|
||||
1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1,
|
||||
22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 373,
|
||||
8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1,
|
||||
23, 1, 23, 3, 23, 386, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24,
|
||||
1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1,
|
||||
27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27,
|
||||
1, 27, 3, 27, 416, 8, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1,
|
||||
28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28,
|
||||
1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1,
|
||||
28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28,
|
||||
1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1,
|
||||
28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 3, 28, 474, 8, 28,
|
||||
1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 5,
|
||||
31, 486, 8, 31, 10, 31, 12, 31, 489, 9, 31, 1, 32, 4, 32, 492, 8, 32, 11,
|
||||
32, 12, 32, 493, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35,
|
||||
1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1,
|
||||
41, 1, 41, 3, 41, 516, 8, 41, 1, 41, 1, 41, 1, 41, 4, 41, 521, 8, 41, 11,
|
||||
41, 12, 41, 522, 1, 41, 3, 41, 526, 8, 41, 1, 41, 3, 41, 529, 8, 41, 1,
|
||||
41, 1, 41, 1, 41, 1, 41, 3, 41, 535, 8, 41, 1, 41, 3, 41, 538, 8, 41, 1,
|
||||
42, 1, 42, 1, 42, 5, 42, 543, 8, 42, 10, 42, 12, 42, 546, 9, 42, 3, 42,
|
||||
548, 8, 42, 1, 43, 1, 43, 3, 43, 552, 8, 43, 1, 43, 1, 43, 1, 44, 1, 44,
|
||||
1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1,
|
||||
48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 576, 8, 50,
|
||||
1, 51, 1, 51, 1, 51, 1, 51, 5, 51, 582, 8, 51, 10, 51, 12, 51, 585, 9,
|
||||
51, 1, 52, 1, 52, 1, 52, 5, 52, 590, 8, 52, 10, 52, 12, 52, 593, 9, 52,
|
||||
1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 3, 53, 600, 8, 53, 1, 54, 1, 54, 1,
|
||||
54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58,
|
||||
1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 63, 1,
|
||||
63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 68, 1, 68,
|
||||
1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1,
|
||||
74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79,
|
||||
1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 1, 82, 1, 82, 1, 83, 1, 83, 5, 83, 666,
|
||||
8, 83, 10, 83, 12, 83, 669, 9, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 667,
|
||||
0, 84, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10,
|
||||
21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19,
|
||||
39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28,
|
||||
57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37,
|
||||
75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 0, 87, 0, 89, 43, 91, 44, 93,
|
||||
45, 95, 46, 97, 47, 99, 48, 101, 49, 103, 50, 105, 51, 107, 0, 109, 0,
|
||||
111, 0, 113, 0, 115, 0, 117, 0, 119, 0, 121, 0, 123, 0, 125, 0, 127, 0,
|
||||
129, 0, 131, 0, 133, 0, 135, 0, 137, 0, 139, 0, 141, 0, 143, 0, 145, 0,
|
||||
147, 0, 149, 0, 151, 0, 153, 0, 155, 0, 157, 0, 159, 0, 161, 0, 163, 0,
|
||||
165, 0, 167, 52, 1, 0, 35, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57,
|
||||
65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 1,
|
||||
0, 49, 57, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 2, 0, 34, 34,
|
||||
92, 92, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114,
|
||||
114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65, 65, 97, 97, 2,
|
||||
0, 66, 66, 98, 98, 2, 0, 67, 67, 99, 99, 2, 0, 68, 68, 100, 100, 2, 0,
|
||||
70, 70, 102, 102, 2, 0, 71, 71, 103, 103, 2, 0, 72, 72, 104, 104, 2, 0,
|
||||
73, 73, 105, 105, 2, 0, 74, 74, 106, 106, 2, 0, 75, 75, 107, 107, 2, 0,
|
||||
76, 76, 108, 108, 2, 0, 77, 77, 109, 109, 2, 0, 78, 78, 110, 110, 2, 0,
|
||||
79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 81, 81, 113, 113, 2, 0,
|
||||
82, 82, 114, 114, 2, 0, 83, 83, 115, 115, 2, 0, 84, 84, 116, 116, 2, 0,
|
||||
85, 85, 117, 117, 2, 0, 86, 86, 118, 118, 2, 0, 87, 87, 119, 119, 2, 0,
|
||||
88, 88, 120, 120, 2, 0, 89, 89, 121, 121, 2, 0, 90, 90, 122, 122, 683,
|
||||
0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0,
|
||||
0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0,
|
||||
0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0,
|
||||
0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1,
|
||||
0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39,
|
||||
1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0,
|
||||
47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0,
|
||||
0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0,
|
||||
0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0,
|
||||
0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1,
|
||||
0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 89,
|
||||
1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0,
|
||||
97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0,
|
||||
0, 0, 105, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 3, 171,
|
||||
1, 0, 0, 0, 5, 173, 1, 0, 0, 0, 7, 177, 1, 0, 0, 0, 9, 181, 1, 0, 0, 0,
|
||||
11, 185, 1, 0, 0, 0, 13, 189, 1, 0, 0, 0, 15, 196, 1, 0, 0, 0, 17, 204,
|
||||
1, 0, 0, 0, 19, 211, 1, 0, 0, 0, 21, 216, 1, 0, 0, 0, 23, 222, 1, 0, 0,
|
||||
0, 25, 225, 1, 0, 0, 0, 27, 228, 1, 0, 0, 0, 29, 230, 1, 0, 0, 0, 31, 232,
|
||||
1, 0, 0, 0, 33, 235, 1, 0, 0, 0, 35, 238, 1, 0, 0, 0, 37, 240, 1, 0, 0,
|
||||
0, 39, 243, 1, 0, 0, 0, 41, 245, 1, 0, 0, 0, 43, 247, 1, 0, 0, 0, 45, 372,
|
||||
1, 0, 0, 0, 47, 385, 1, 0, 0, 0, 49, 387, 1, 0, 0, 0, 51, 396, 1, 0, 0,
|
||||
0, 53, 398, 1, 0, 0, 0, 55, 415, 1, 0, 0, 0, 57, 473, 1, 0, 0, 0, 59, 475,
|
||||
1, 0, 0, 0, 61, 478, 1, 0, 0, 0, 63, 483, 1, 0, 0, 0, 65, 491, 1, 0, 0,
|
||||
0, 67, 497, 1, 0, 0, 0, 69, 499, 1, 0, 0, 0, 71, 501, 1, 0, 0, 0, 73, 503,
|
||||
1, 0, 0, 0, 75, 505, 1, 0, 0, 0, 77, 507, 1, 0, 0, 0, 79, 509, 1, 0, 0,
|
||||
0, 81, 511, 1, 0, 0, 0, 83, 537, 1, 0, 0, 0, 85, 547, 1, 0, 0, 0, 87, 549,
|
||||
1, 0, 0, 0, 89, 555, 1, 0, 0, 0, 91, 558, 1, 0, 0, 0, 93, 560, 1, 0, 0,
|
||||
0, 95, 563, 1, 0, 0, 0, 97, 565, 1, 0, 0, 0, 99, 568, 1, 0, 0, 0, 101,
|
||||
571, 1, 0, 0, 0, 103, 577, 1, 0, 0, 0, 105, 586, 1, 0, 0, 0, 107, 596,
|
||||
1, 0, 0, 0, 109, 601, 1, 0, 0, 0, 111, 607, 1, 0, 0, 0, 113, 609, 1, 0,
|
||||
0, 0, 115, 611, 1, 0, 0, 0, 117, 613, 1, 0, 0, 0, 119, 615, 1, 0, 0, 0,
|
||||
121, 617, 1, 0, 0, 0, 123, 619, 1, 0, 0, 0, 125, 621, 1, 0, 0, 0, 127,
|
||||
623, 1, 0, 0, 0, 129, 625, 1, 0, 0, 0, 131, 627, 1, 0, 0, 0, 133, 629,
|
||||
1, 0, 0, 0, 135, 631, 1, 0, 0, 0, 137, 633, 1, 0, 0, 0, 139, 635, 1, 0,
|
||||
0, 0, 141, 637, 1, 0, 0, 0, 143, 639, 1, 0, 0, 0, 145, 641, 1, 0, 0, 0,
|
||||
147, 643, 1, 0, 0, 0, 149, 645, 1, 0, 0, 0, 151, 647, 1, 0, 0, 0, 153,
|
||||
649, 1, 0, 0, 0, 155, 651, 1, 0, 0, 0, 157, 653, 1, 0, 0, 0, 159, 655,
|
||||
1, 0, 0, 0, 161, 657, 1, 0, 0, 0, 163, 659, 1, 0, 0, 0, 165, 661, 1, 0,
|
||||
0, 0, 167, 663, 1, 0, 0, 0, 169, 170, 5, 59, 0, 0, 170, 2, 1, 0, 0, 0,
|
||||
171, 172, 5, 42, 0, 0, 172, 4, 1, 0, 0, 0, 173, 174, 5, 115, 0, 0, 174,
|
||||
175, 5, 117, 0, 0, 175, 176, 5, 109, 0, 0, 176, 6, 1, 0, 0, 0, 177, 178,
|
||||
5, 97, 0, 0, 178, 179, 5, 118, 0, 0, 179, 180, 5, 103, 0, 0, 180, 8, 1,
|
||||
0, 0, 0, 181, 182, 5, 109, 0, 0, 182, 183, 5, 97, 0, 0, 183, 184, 5, 120,
|
||||
0, 0, 184, 10, 1, 0, 0, 0, 185, 186, 5, 109, 0, 0, 186, 187, 5, 105, 0,
|
||||
0, 187, 188, 5, 110, 0, 0, 188, 12, 1, 0, 0, 0, 189, 190, 5, 115, 0, 0,
|
||||
190, 191, 5, 99, 0, 0, 191, 192, 5, 104, 0, 0, 192, 193, 5, 101, 0, 0,
|
||||
193, 194, 5, 109, 0, 0, 194, 195, 5, 97, 0, 0, 195, 14, 1, 0, 0, 0, 196,
|
||||
197, 5, 99, 0, 0, 197, 198, 5, 97, 0, 0, 198, 199, 5, 116, 0, 0, 199, 200,
|
||||
5, 97, 0, 0, 200, 201, 5, 108, 0, 0, 201, 202, 5, 111, 0, 0, 202, 203,
|
||||
5, 103, 0, 0, 203, 16, 1, 0, 0, 0, 204, 205, 5, 117, 0, 0, 205, 206, 5,
|
||||
110, 0, 0, 206, 207, 5, 105, 0, 0, 207, 208, 5, 113, 0, 0, 208, 209, 5,
|
||||
117, 0, 0, 209, 210, 5, 101, 0, 0, 210, 18, 1, 0, 0, 0, 211, 212, 5, 117,
|
||||
0, 0, 212, 213, 5, 110, 0, 0, 213, 214, 5, 105, 0, 0, 214, 215, 5, 113,
|
||||
0, 0, 215, 20, 1, 0, 0, 0, 216, 217, 5, 99, 0, 0, 217, 218, 5, 111, 0,
|
||||
0, 218, 219, 5, 117, 0, 0, 219, 220, 5, 110, 0, 0, 220, 221, 5, 116, 0,
|
||||
0, 221, 22, 1, 0, 0, 0, 222, 223, 5, 46, 0, 0, 223, 224, 5, 91, 0, 0, 224,
|
||||
24, 1, 0, 0, 0, 225, 226, 5, 124, 0, 0, 226, 227, 5, 124, 0, 0, 227, 26,
|
||||
1, 0, 0, 0, 228, 229, 5, 47, 0, 0, 229, 28, 1, 0, 0, 0, 230, 231, 5, 37,
|
||||
0, 0, 231, 30, 1, 0, 0, 0, 232, 233, 5, 60, 0, 0, 233, 234, 5, 60, 0, 0,
|
||||
234, 32, 1, 0, 0, 0, 235, 236, 5, 62, 0, 0, 236, 237, 5, 62, 0, 0, 237,
|
||||
34, 1, 0, 0, 0, 238, 239, 5, 38, 0, 0, 239, 36, 1, 0, 0, 0, 240, 241, 5,
|
||||
38, 0, 0, 241, 242, 5, 38, 0, 0, 242, 38, 1, 0, 0, 0, 243, 244, 5, 126,
|
||||
0, 0, 244, 40, 1, 0, 0, 0, 245, 246, 5, 33, 0, 0, 246, 42, 1, 0, 0, 0,
|
||||
247, 248, 5, 95, 0, 0, 248, 249, 3, 63, 31, 0, 249, 44, 1, 0, 0, 0, 250,
|
||||
251, 5, 106, 0, 0, 251, 252, 5, 111, 0, 0, 252, 253, 5, 105, 0, 0, 253,
|
||||
373, 5, 110, 0, 0, 254, 255, 5, 105, 0, 0, 255, 256, 5, 110, 0, 0, 256,
|
||||
257, 5, 110, 0, 0, 257, 258, 5, 101, 0, 0, 258, 259, 5, 114, 0, 0, 259,
|
||||
260, 5, 95, 0, 0, 260, 261, 5, 106, 0, 0, 261, 262, 5, 111, 0, 0, 262,
|
||||
263, 5, 105, 0, 0, 263, 373, 5, 110, 0, 0, 264, 265, 5, 108, 0, 0, 265,
|
||||
266, 5, 101, 0, 0, 266, 267, 5, 102, 0, 0, 267, 268, 5, 116, 0, 0, 268,
|
||||
269, 5, 95, 0, 0, 269, 270, 5, 106, 0, 0, 270, 271, 5, 111, 0, 0, 271,
|
||||
272, 5, 105, 0, 0, 272, 373, 5, 110, 0, 0, 273, 274, 5, 108, 0, 0, 274,
|
||||
275, 5, 106, 0, 0, 275, 276, 5, 111, 0, 0, 276, 277, 5, 105, 0, 0, 277,
|
||||
373, 5, 110, 0, 0, 278, 279, 5, 108, 0, 0, 279, 280, 5, 101, 0, 0, 280,
|
||||
281, 5, 102, 0, 0, 281, 282, 5, 116, 0, 0, 282, 283, 5, 95, 0, 0, 283,
|
||||
284, 5, 111, 0, 0, 284, 285, 5, 117, 0, 0, 285, 286, 5, 116, 0, 0, 286,
|
||||
287, 5, 101, 0, 0, 287, 288, 5, 114, 0, 0, 288, 289, 5, 95, 0, 0, 289,
|
||||
290, 5, 106, 0, 0, 290, 291, 5, 111, 0, 0, 291, 292, 5, 105, 0, 0, 292,
|
||||
373, 5, 110, 0, 0, 293, 294, 5, 108, 0, 0, 294, 295, 5, 111, 0, 0, 295,
|
||||
296, 5, 106, 0, 0, 296, 297, 5, 111, 0, 0, 297, 298, 5, 105, 0, 0, 298,
|
||||
373, 5, 110, 0, 0, 299, 300, 5, 114, 0, 0, 300, 301, 5, 105, 0, 0, 301,
|
||||
302, 5, 103, 0, 0, 302, 303, 5, 104, 0, 0, 303, 304, 5, 116, 0, 0, 304,
|
||||
305, 5, 95, 0, 0, 305, 306, 5, 106, 0, 0, 306, 307, 5, 111, 0, 0, 307,
|
||||
308, 5, 105, 0, 0, 308, 373, 5, 110, 0, 0, 309, 310, 5, 114, 0, 0, 310,
|
||||
311, 5, 106, 0, 0, 311, 312, 5, 111, 0, 0, 312, 313, 5, 105, 0, 0, 313,
|
||||
373, 5, 110, 0, 0, 314, 315, 5, 114, 0, 0, 315, 316, 5, 105, 0, 0, 316,
|
||||
317, 5, 103, 0, 0, 317, 318, 5, 104, 0, 0, 318, 319, 5, 116, 0, 0, 319,
|
||||
320, 5, 95, 0, 0, 320, 321, 5, 111, 0, 0, 321, 322, 5, 117, 0, 0, 322,
|
||||
323, 5, 116, 0, 0, 323, 324, 5, 101, 0, 0, 324, 325, 5, 114, 0, 0, 325,
|
||||
326, 5, 95, 0, 0, 326, 327, 5, 106, 0, 0, 327, 328, 5, 111, 0, 0, 328,
|
||||
329, 5, 105, 0, 0, 329, 373, 5, 110, 0, 0, 330, 331, 5, 114, 0, 0, 331,
|
||||
332, 5, 111, 0, 0, 332, 333, 5, 106, 0, 0, 333, 334, 5, 111, 0, 0, 334,
|
||||
335, 5, 105, 0, 0, 335, 373, 5, 110, 0, 0, 336, 337, 5, 102, 0, 0, 337,
|
||||
338, 5, 117, 0, 0, 338, 339, 5, 108, 0, 0, 339, 340, 5, 108, 0, 0, 340,
|
||||
341, 5, 95, 0, 0, 341, 342, 5, 111, 0, 0, 342, 343, 5, 117, 0, 0, 343,
|
||||
344, 5, 116, 0, 0, 344, 345, 5, 101, 0, 0, 345, 346, 5, 114, 0, 0, 346,
|
||||
347, 5, 95, 0, 0, 347, 348, 5, 106, 0, 0, 348, 349, 5, 111, 0, 0, 349,
|
||||
350, 5, 105, 0, 0, 350, 373, 5, 110, 0, 0, 351, 352, 5, 102, 0, 0, 352,
|
||||
353, 5, 111, 0, 0, 353, 354, 5, 106, 0, 0, 354, 355, 5, 111, 0, 0, 355,
|
||||
356, 5, 105, 0, 0, 356, 373, 5, 110, 0, 0, 357, 358, 5, 99, 0, 0, 358,
|
||||
359, 5, 114, 0, 0, 359, 360, 5, 111, 0, 0, 360, 361, 5, 115, 0, 0, 361,
|
||||
362, 5, 115, 0, 0, 362, 363, 5, 95, 0, 0, 363, 364, 5, 106, 0, 0, 364,
|
||||
365, 5, 111, 0, 0, 365, 366, 5, 105, 0, 0, 366, 373, 5, 110, 0, 0, 367,
|
||||
368, 5, 120, 0, 0, 368, 369, 5, 106, 0, 0, 369, 370, 5, 111, 0, 0, 370,
|
||||
371, 5, 105, 0, 0, 371, 373, 5, 110, 0, 0, 372, 250, 1, 0, 0, 0, 372, 254,
|
||||
1, 0, 0, 0, 372, 264, 1, 0, 0, 0, 372, 273, 1, 0, 0, 0, 372, 278, 1, 0,
|
||||
0, 0, 372, 293, 1, 0, 0, 0, 372, 299, 1, 0, 0, 0, 372, 309, 1, 0, 0, 0,
|
||||
372, 314, 1, 0, 0, 0, 372, 330, 1, 0, 0, 0, 372, 336, 1, 0, 0, 0, 372,
|
||||
351, 1, 0, 0, 0, 372, 357, 1, 0, 0, 0, 372, 367, 1, 0, 0, 0, 373, 46, 1,
|
||||
0, 0, 0, 374, 375, 5, 119, 0, 0, 375, 376, 5, 104, 0, 0, 376, 377, 5, 101,
|
||||
0, 0, 377, 378, 5, 114, 0, 0, 378, 386, 5, 101, 0, 0, 379, 380, 5, 115,
|
||||
0, 0, 380, 381, 5, 101, 0, 0, 381, 382, 5, 108, 0, 0, 382, 383, 5, 101,
|
||||
0, 0, 383, 384, 5, 99, 0, 0, 384, 386, 5, 116, 0, 0, 385, 374, 1, 0, 0,
|
||||
0, 385, 379, 1, 0, 0, 0, 386, 48, 1, 0, 0, 0, 387, 388, 5, 103, 0, 0, 388,
|
||||
389, 5, 114, 0, 0, 389, 390, 5, 111, 0, 0, 390, 391, 5, 117, 0, 0, 391,
|
||||
392, 5, 112, 0, 0, 392, 393, 5, 95, 0, 0, 393, 394, 5, 98, 0, 0, 394, 395,
|
||||
5, 121, 0, 0, 395, 50, 1, 0, 0, 0, 396, 397, 5, 43, 0, 0, 397, 52, 1, 0,
|
||||
0, 0, 398, 399, 5, 45, 0, 0, 399, 54, 1, 0, 0, 0, 400, 401, 5, 111, 0,
|
||||
0, 401, 402, 5, 114, 0, 0, 402, 403, 5, 100, 0, 0, 403, 404, 5, 101, 0,
|
||||
0, 404, 405, 5, 114, 0, 0, 405, 406, 5, 95, 0, 0, 406, 407, 5, 98, 0, 0,
|
||||
407, 416, 5, 121, 0, 0, 408, 409, 5, 115, 0, 0, 409, 410, 5, 111, 0, 0,
|
||||
410, 411, 5, 114, 0, 0, 411, 412, 5, 116, 0, 0, 412, 413, 5, 95, 0, 0,
|
||||
413, 414, 5, 98, 0, 0, 414, 416, 5, 121, 0, 0, 415, 400, 1, 0, 0, 0, 415,
|
||||
408, 1, 0, 0, 0, 416, 56, 1, 0, 0, 0, 417, 418, 5, 58, 0, 0, 418, 419,
|
||||
5, 99, 0, 0, 419, 420, 5, 111, 0, 0, 420, 421, 5, 117, 0, 0, 421, 422,
|
||||
5, 110, 0, 0, 422, 474, 5, 116, 0, 0, 423, 424, 5, 58, 0, 0, 424, 425,
|
||||
5, 99, 0, 0, 425, 426, 5, 111, 0, 0, 426, 427, 5, 117, 0, 0, 427, 428,
|
||||
5, 110, 0, 0, 428, 429, 5, 116, 0, 0, 429, 430, 5, 95, 0, 0, 430, 431,
|
||||
5, 117, 0, 0, 431, 432, 5, 110, 0, 0, 432, 433, 5, 105, 0, 0, 433, 434,
|
||||
5, 113, 0, 0, 434, 435, 5, 117, 0, 0, 435, 474, 5, 101, 0, 0, 436, 437,
|
||||
5, 58, 0, 0, 437, 438, 5, 97, 0, 0, 438, 439, 5, 118, 0, 0, 439, 474, 5,
|
||||
103, 0, 0, 440, 441, 5, 58, 0, 0, 441, 442, 5, 103, 0, 0, 442, 443, 5,
|
||||
114, 0, 0, 443, 444, 5, 111, 0, 0, 444, 445, 5, 117, 0, 0, 445, 446, 5,
|
||||
112, 0, 0, 446, 447, 5, 95, 0, 0, 447, 448, 5, 98, 0, 0, 448, 474, 5, 121,
|
||||
0, 0, 449, 450, 5, 58, 0, 0, 450, 451, 5, 109, 0, 0, 451, 452, 5, 97, 0,
|
||||
0, 452, 474, 5, 120, 0, 0, 453, 454, 5, 58, 0, 0, 454, 455, 5, 109, 0,
|
||||
0, 455, 456, 5, 105, 0, 0, 456, 474, 5, 110, 0, 0, 457, 458, 5, 58, 0,
|
||||
0, 458, 459, 5, 111, 0, 0, 459, 460, 5, 114, 0, 0, 460, 461, 5, 100, 0,
|
||||
0, 461, 462, 5, 101, 0, 0, 462, 463, 5, 114, 0, 0, 463, 464, 5, 95, 0,
|
||||
0, 464, 465, 5, 98, 0, 0, 465, 474, 5, 121, 0, 0, 466, 467, 5, 58, 0, 0,
|
||||
467, 468, 5, 117, 0, 0, 468, 469, 5, 110, 0, 0, 469, 470, 5, 105, 0, 0,
|
||||
470, 471, 5, 113, 0, 0, 471, 472, 5, 117, 0, 0, 472, 474, 5, 101, 0, 0,
|
||||
473, 417, 1, 0, 0, 0, 473, 423, 1, 0, 0, 0, 473, 436, 1, 0, 0, 0, 473,
|
||||
440, 1, 0, 0, 0, 473, 449, 1, 0, 0, 0, 473, 453, 1, 0, 0, 0, 473, 457,
|
||||
1, 0, 0, 0, 473, 466, 1, 0, 0, 0, 474, 58, 1, 0, 0, 0, 475, 476, 5, 36,
|
||||
0, 0, 476, 477, 3, 63, 31, 0, 477, 60, 1, 0, 0, 0, 478, 479, 5, 110, 0,
|
||||
0, 479, 480, 5, 117, 0, 0, 480, 481, 5, 108, 0, 0, 481, 482, 5, 108, 0,
|
||||
0, 482, 62, 1, 0, 0, 0, 483, 487, 7, 0, 0, 0, 484, 486, 7, 1, 0, 0, 485,
|
||||
484, 1, 0, 0, 0, 486, 489, 1, 0, 0, 0, 487, 485, 1, 0, 0, 0, 487, 488,
|
||||
1, 0, 0, 0, 488, 64, 1, 0, 0, 0, 489, 487, 1, 0, 0, 0, 490, 492, 7, 2,
|
||||
0, 0, 491, 490, 1, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0,
|
||||
493, 494, 1, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 496, 6, 32, 0, 0, 496,
|
||||
66, 1, 0, 0, 0, 497, 498, 5, 40, 0, 0, 498, 68, 1, 0, 0, 0, 499, 500, 5,
|
||||
41, 0, 0, 500, 70, 1, 0, 0, 0, 501, 502, 5, 91, 0, 0, 502, 72, 1, 0, 0,
|
||||
0, 503, 504, 5, 93, 0, 0, 504, 74, 1, 0, 0, 0, 505, 506, 5, 44, 0, 0, 506,
|
||||
76, 1, 0, 0, 0, 507, 508, 5, 124, 0, 0, 508, 78, 1, 0, 0, 0, 509, 510,
|
||||
5, 58, 0, 0, 510, 80, 1, 0, 0, 0, 511, 512, 3, 85, 42, 0, 512, 82, 1, 0,
|
||||
0, 0, 513, 538, 3, 81, 40, 0, 514, 516, 5, 45, 0, 0, 515, 514, 1, 0, 0,
|
||||
0, 515, 516, 1, 0, 0, 0, 516, 517, 1, 0, 0, 0, 517, 518, 3, 85, 42, 0,
|
||||
518, 520, 5, 46, 0, 0, 519, 521, 7, 3, 0, 0, 520, 519, 1, 0, 0, 0, 521,
|
||||
522, 1, 0, 0, 0, 522, 520, 1, 0, 0, 0, 522, 523, 1, 0, 0, 0, 523, 525,
|
||||
1, 0, 0, 0, 524, 526, 3, 87, 43, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1,
|
||||
0, 0, 0, 526, 538, 1, 0, 0, 0, 527, 529, 5, 45, 0, 0, 528, 527, 1, 0, 0,
|
||||
0, 528, 529, 1, 0, 0, 0, 529, 530, 1, 0, 0, 0, 530, 531, 3, 85, 42, 0,
|
||||
531, 532, 3, 87, 43, 0, 532, 538, 1, 0, 0, 0, 533, 535, 5, 45, 0, 0, 534,
|
||||
533, 1, 0, 0, 0, 534, 535, 1, 0, 0, 0, 535, 536, 1, 0, 0, 0, 536, 538,
|
||||
3, 85, 42, 0, 537, 513, 1, 0, 0, 0, 537, 515, 1, 0, 0, 0, 537, 528, 1,
|
||||
0, 0, 0, 537, 534, 1, 0, 0, 0, 538, 84, 1, 0, 0, 0, 539, 548, 5, 48, 0,
|
||||
0, 540, 544, 7, 4, 0, 0, 541, 543, 7, 3, 0, 0, 542, 541, 1, 0, 0, 0, 543,
|
||||
546, 1, 0, 0, 0, 544, 542, 1, 0, 0, 0, 544, 545, 1, 0, 0, 0, 545, 548,
|
||||
1, 0, 0, 0, 546, 544, 1, 0, 0, 0, 547, 539, 1, 0, 0, 0, 547, 540, 1, 0,
|
||||
0, 0, 548, 86, 1, 0, 0, 0, 549, 551, 7, 5, 0, 0, 550, 552, 7, 6, 0, 0,
|
||||
551, 550, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 553, 1, 0, 0, 0, 553,
|
||||
554, 3, 85, 42, 0, 554, 88, 1, 0, 0, 0, 555, 556, 5, 60, 0, 0, 556, 557,
|
||||
5, 61, 0, 0, 557, 90, 1, 0, 0, 0, 558, 559, 5, 60, 0, 0, 559, 92, 1, 0,
|
||||
0, 0, 560, 561, 5, 62, 0, 0, 561, 562, 5, 61, 0, 0, 562, 94, 1, 0, 0, 0,
|
||||
563, 564, 5, 62, 0, 0, 564, 96, 1, 0, 0, 0, 565, 566, 5, 33, 0, 0, 566,
|
||||
567, 5, 61, 0, 0, 567, 98, 1, 0, 0, 0, 568, 569, 5, 61, 0, 0, 569, 570,
|
||||
5, 61, 0, 0, 570, 100, 1, 0, 0, 0, 571, 575, 5, 46, 0, 0, 572, 576, 3,
|
||||
59, 29, 0, 573, 576, 3, 63, 31, 0, 574, 576, 3, 105, 52, 0, 575, 572, 1,
|
||||
0, 0, 0, 575, 573, 1, 0, 0, 0, 575, 574, 1, 0, 0, 0, 576, 102, 1, 0, 0,
|
||||
0, 577, 578, 5, 64, 0, 0, 578, 583, 3, 63, 31, 0, 579, 580, 5, 47, 0, 0,
|
||||
580, 582, 3, 63, 31, 0, 581, 579, 1, 0, 0, 0, 582, 585, 1, 0, 0, 0, 583,
|
||||
581, 1, 0, 0, 0, 583, 584, 1, 0, 0, 0, 584, 104, 1, 0, 0, 0, 585, 583,
|
||||
1, 0, 0, 0, 586, 591, 5, 34, 0, 0, 587, 590, 3, 107, 53, 0, 588, 590, 8,
|
||||
7, 0, 0, 589, 587, 1, 0, 0, 0, 589, 588, 1, 0, 0, 0, 590, 593, 1, 0, 0,
|
||||
0, 591, 589, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 594, 1, 0, 0, 0, 593,
|
||||
591, 1, 0, 0, 0, 594, 595, 5, 34, 0, 0, 595, 106, 1, 0, 0, 0, 596, 599,
|
||||
5, 92, 0, 0, 597, 600, 7, 8, 0, 0, 598, 600, 3, 109, 54, 0, 599, 597, 1,
|
||||
0, 0, 0, 599, 598, 1, 0, 0, 0, 600, 108, 1, 0, 0, 0, 601, 602, 5, 117,
|
||||
0, 0, 602, 603, 3, 111, 55, 0, 603, 604, 3, 111, 55, 0, 604, 605, 3, 111,
|
||||
55, 0, 605, 606, 3, 111, 55, 0, 606, 110, 1, 0, 0, 0, 607, 608, 7, 9, 0,
|
||||
0, 608, 112, 1, 0, 0, 0, 609, 610, 7, 3, 0, 0, 610, 114, 1, 0, 0, 0, 611,
|
||||
612, 7, 10, 0, 0, 612, 116, 1, 0, 0, 0, 613, 614, 7, 11, 0, 0, 614, 118,
|
||||
1, 0, 0, 0, 615, 616, 7, 12, 0, 0, 616, 120, 1, 0, 0, 0, 617, 618, 7, 13,
|
||||
0, 0, 618, 122, 1, 0, 0, 0, 619, 620, 7, 5, 0, 0, 620, 124, 1, 0, 0, 0,
|
||||
621, 622, 7, 14, 0, 0, 622, 126, 1, 0, 0, 0, 623, 624, 7, 15, 0, 0, 624,
|
||||
128, 1, 0, 0, 0, 625, 626, 7, 16, 0, 0, 626, 130, 1, 0, 0, 0, 627, 628,
|
||||
7, 17, 0, 0, 628, 132, 1, 0, 0, 0, 629, 630, 7, 18, 0, 0, 630, 134, 1,
|
||||
0, 0, 0, 631, 632, 7, 19, 0, 0, 632, 136, 1, 0, 0, 0, 633, 634, 7, 20,
|
||||
0, 0, 634, 138, 1, 0, 0, 0, 635, 636, 7, 21, 0, 0, 636, 140, 1, 0, 0, 0,
|
||||
637, 638, 7, 22, 0, 0, 638, 142, 1, 0, 0, 0, 639, 640, 7, 23, 0, 0, 640,
|
||||
144, 1, 0, 0, 0, 641, 642, 7, 24, 0, 0, 642, 146, 1, 0, 0, 0, 643, 644,
|
||||
7, 25, 0, 0, 644, 148, 1, 0, 0, 0, 645, 646, 7, 26, 0, 0, 646, 150, 1,
|
||||
0, 0, 0, 647, 648, 7, 27, 0, 0, 648, 152, 1, 0, 0, 0, 649, 650, 7, 28,
|
||||
0, 0, 650, 154, 1, 0, 0, 0, 651, 652, 7, 29, 0, 0, 652, 156, 1, 0, 0, 0,
|
||||
653, 654, 7, 30, 0, 0, 654, 158, 1, 0, 0, 0, 655, 656, 7, 31, 0, 0, 656,
|
||||
160, 1, 0, 0, 0, 657, 658, 7, 32, 0, 0, 658, 162, 1, 0, 0, 0, 659, 660,
|
||||
7, 33, 0, 0, 660, 164, 1, 0, 0, 0, 661, 662, 7, 34, 0, 0, 662, 166, 1,
|
||||
0, 0, 0, 663, 667, 5, 35, 0, 0, 664, 666, 9, 0, 0, 0, 665, 664, 1, 0, 0,
|
||||
0, 666, 669, 1, 0, 0, 0, 667, 668, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668,
|
||||
670, 1, 0, 0, 0, 669, 667, 1, 0, 0, 0, 670, 671, 5, 10, 0, 0, 671, 672,
|
||||
1, 0, 0, 0, 672, 673, 6, 83, 0, 0, 673, 168, 1, 0, 0, 0, 22, 0, 372, 385,
|
||||
415, 473, 487, 493, 515, 522, 525, 528, 534, 537, 544, 547, 551, 575, 583,
|
||||
589, 591, 599, 667, 1, 6, 0, 0,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
@ -420,35 +432,38 @@ const (
|
||||
SLQLexerT__15 = 16
|
||||
SLQLexerT__16 = 17
|
||||
SLQLexerT__17 = 18
|
||||
SLQLexerPROPRIETARY_FUNC_NAME = 19
|
||||
SLQLexerJOIN_TYPE = 20
|
||||
SLQLexerWHERE = 21
|
||||
SLQLexerGROUP_BY = 22
|
||||
SLQLexerORDER_ASC = 23
|
||||
SLQLexerORDER_DESC = 24
|
||||
SLQLexerORDER_BY = 25
|
||||
SLQLexerALIAS_RESERVED = 26
|
||||
SLQLexerARG = 27
|
||||
SLQLexerNULL = 28
|
||||
SLQLexerID = 29
|
||||
SLQLexerWS = 30
|
||||
SLQLexerLPAR = 31
|
||||
SLQLexerRPAR = 32
|
||||
SLQLexerLBRA = 33
|
||||
SLQLexerRBRA = 34
|
||||
SLQLexerCOMMA = 35
|
||||
SLQLexerPIPE = 36
|
||||
SLQLexerCOLON = 37
|
||||
SLQLexerNN = 38
|
||||
SLQLexerNUMBER = 39
|
||||
SLQLexerLT_EQ = 40
|
||||
SLQLexerLT = 41
|
||||
SLQLexerGT_EQ = 42
|
||||
SLQLexerGT = 43
|
||||
SLQLexerNEQ = 44
|
||||
SLQLexerEQ = 45
|
||||
SLQLexerNAME = 46
|
||||
SLQLexerHANDLE = 47
|
||||
SLQLexerSTRING = 48
|
||||
SLQLexerLINECOMMENT = 49
|
||||
SLQLexerT__18 = 19
|
||||
SLQLexerT__19 = 20
|
||||
SLQLexerT__20 = 21
|
||||
SLQLexerPROPRIETARY_FUNC_NAME = 22
|
||||
SLQLexerJOIN_TYPE = 23
|
||||
SLQLexerWHERE = 24
|
||||
SLQLexerGROUP_BY = 25
|
||||
SLQLexerORDER_ASC = 26
|
||||
SLQLexerORDER_DESC = 27
|
||||
SLQLexerORDER_BY = 28
|
||||
SLQLexerALIAS_RESERVED = 29
|
||||
SLQLexerARG = 30
|
||||
SLQLexerNULL = 31
|
||||
SLQLexerID = 32
|
||||
SLQLexerWS = 33
|
||||
SLQLexerLPAR = 34
|
||||
SLQLexerRPAR = 35
|
||||
SLQLexerLBRA = 36
|
||||
SLQLexerRBRA = 37
|
||||
SLQLexerCOMMA = 38
|
||||
SLQLexerPIPE = 39
|
||||
SLQLexerCOLON = 40
|
||||
SLQLexerNN = 41
|
||||
SLQLexerNUMBER = 42
|
||||
SLQLexerLT_EQ = 43
|
||||
SLQLexerLT = 44
|
||||
SLQLexerGT_EQ = 45
|
||||
SLQLexerGT = 46
|
||||
SLQLexerNEQ = 47
|
||||
SLQLexerEQ = 48
|
||||
SLQLexerNAME = 49
|
||||
SLQLexerHANDLE = 50
|
||||
SLQLexerSTRING = 51
|
||||
SLQLexerLINECOMMENT = 52
|
||||
)
|
||||
|
@ -32,19 +32,19 @@ var SLQParserStaticData struct {
|
||||
func slqParserInit() {
|
||||
staticData := &SLQParserStaticData
|
||||
staticData.LiteralNames = []string{
|
||||
"", "';'", "'*'", "'sum'", "'avg'", "'max'", "'min'", "'unique'", "'count'",
|
||||
"'.['", "'||'", "'/'", "'%'", "'<<'", "'>>'", "'&'", "'&&'", "'~'",
|
||||
"'!'", "", "", "", "'group_by'", "'+'", "'-'", "", "", "", "'null'",
|
||||
"", "", "'('", "')'", "'['", "']'", "','", "'|'", "':'", "", "", "'<='",
|
||||
"'<'", "'>='", "'>'", "'!='", "'=='",
|
||||
"", "';'", "'*'", "'sum'", "'avg'", "'max'", "'min'", "'schema'", "'catalog'",
|
||||
"'unique'", "'uniq'", "'count'", "'.['", "'||'", "'/'", "'%'", "'<<'",
|
||||
"'>>'", "'&'", "'&&'", "'~'", "'!'", "", "", "", "'group_by'", "'+'",
|
||||
"'-'", "", "", "", "'null'", "", "", "'('", "')'", "'['", "']'", "','",
|
||||
"'|'", "':'", "", "", "'<='", "'<'", "'>='", "'>'", "'!='", "'=='",
|
||||
}
|
||||
staticData.SymbolicNames = []string{
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE", "WHERE", "GROUP_BY", "ORDER_ASC",
|
||||
"ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED", "ARG", "NULL", "ID", "WS",
|
||||
"LPAR", "RPAR", "LBRA", "RBRA", "COMMA", "PIPE", "COLON", "NN", "NUMBER",
|
||||
"LT_EQ", "LT", "GT_EQ", "GT", "NEQ", "EQ", "NAME", "HANDLE", "STRING",
|
||||
"LINECOMMENT",
|
||||
"", "", "", "", "", "PROPRIETARY_FUNC_NAME", "JOIN_TYPE", "WHERE", "GROUP_BY",
|
||||
"ORDER_ASC", "ORDER_DESC", "ORDER_BY", "ALIAS_RESERVED", "ARG", "NULL",
|
||||
"ID", "WS", "LPAR", "RPAR", "LBRA", "RBRA", "COMMA", "PIPE", "COLON",
|
||||
"NN", "NUMBER", "LT_EQ", "LT", "GT_EQ", "GT", "NEQ", "EQ", "NAME", "HANDLE",
|
||||
"STRING", "LINECOMMENT",
|
||||
}
|
||||
staticData.RuleNames = []string{
|
||||
"stmtList", "query", "segment", "element", "funcElement", "func", "funcName",
|
||||
@ -55,7 +55,7 @@ func slqParserInit() {
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 1, 49, 283, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7,
|
||||
4, 1, 52, 283, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7,
|
||||
4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7,
|
||||
10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15,
|
||||
2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2,
|
||||
@ -85,105 +85,105 @@ func slqParserInit() {
|
||||
24, 3, 24, 268, 8, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 274, 8, 24, 10,
|
||||
24, 12, 24, 277, 9, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 0, 1, 48, 27,
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
|
||||
38, 40, 42, 44, 46, 48, 50, 52, 0, 8, 2, 0, 3, 6, 19, 19, 1, 0, 23, 24,
|
||||
3, 0, 27, 27, 29, 29, 48, 48, 2, 0, 2, 2, 11, 12, 1, 0, 13, 15, 1, 0, 40,
|
||||
43, 3, 0, 28, 28, 38, 39, 48, 48, 2, 0, 17, 18, 23, 24, 309, 0, 57, 1,
|
||||
0, 0, 0, 2, 78, 1, 0, 0, 0, 4, 86, 1, 0, 0, 0, 6, 106, 1, 0, 0, 0, 8, 108,
|
||||
1, 0, 0, 0, 10, 112, 1, 0, 0, 0, 12, 127, 1, 0, 0, 0, 14, 129, 1, 0, 0,
|
||||
0, 16, 139, 1, 0, 0, 0, 18, 145, 1, 0, 0, 0, 20, 147, 1, 0, 0, 0, 22, 158,
|
||||
1, 0, 0, 0, 24, 167, 1, 0, 0, 0, 26, 169, 1, 0, 0, 0, 28, 181, 1, 0, 0,
|
||||
0, 30, 185, 1, 0, 0, 0, 32, 197, 1, 0, 0, 0, 34, 201, 1, 0, 0, 0, 36, 208,
|
||||
1, 0, 0, 0, 38, 210, 1, 0, 0, 0, 40, 212, 1, 0, 0, 0, 42, 215, 1, 0, 0,
|
||||
0, 44, 217, 1, 0, 0, 0, 46, 230, 1, 0, 0, 0, 48, 246, 1, 0, 0, 0, 50, 278,
|
||||
1, 0, 0, 0, 52, 280, 1, 0, 0, 0, 54, 56, 5, 1, 0, 0, 55, 54, 1, 0, 0, 0,
|
||||
56, 59, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 60, 1,
|
||||
0, 0, 0, 59, 57, 1, 0, 0, 0, 60, 69, 3, 2, 1, 0, 61, 63, 5, 1, 0, 0, 62,
|
||||
61, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0, 64, 62, 1, 0, 0, 0, 64, 65, 1, 0, 0,
|
||||
0, 65, 66, 1, 0, 0, 0, 66, 68, 3, 2, 1, 0, 67, 62, 1, 0, 0, 0, 68, 71,
|
||||
1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 69, 70, 1, 0, 0, 0, 70, 75, 1, 0, 0, 0,
|
||||
71, 69, 1, 0, 0, 0, 72, 74, 5, 1, 0, 0, 73, 72, 1, 0, 0, 0, 74, 77, 1,
|
||||
0, 0, 0, 75, 73, 1, 0, 0, 0, 75, 76, 1, 0, 0, 0, 76, 1, 1, 0, 0, 0, 77,
|
||||
75, 1, 0, 0, 0, 78, 83, 3, 4, 2, 0, 79, 80, 5, 36, 0, 0, 80, 82, 3, 4,
|
||||
2, 0, 81, 79, 1, 0, 0, 0, 82, 85, 1, 0, 0, 0, 83, 81, 1, 0, 0, 0, 83, 84,
|
||||
1, 0, 0, 0, 84, 3, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 86, 91, 3, 6, 3, 0,
|
||||
87, 88, 5, 35, 0, 0, 88, 90, 3, 6, 3, 0, 89, 87, 1, 0, 0, 0, 90, 93, 1,
|
||||
0, 0, 0, 91, 89, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92, 5, 1, 0, 0, 0, 93,
|
||||
91, 1, 0, 0, 0, 94, 107, 3, 40, 20, 0, 95, 107, 3, 42, 21, 0, 96, 107,
|
||||
3, 34, 17, 0, 97, 107, 3, 14, 7, 0, 98, 107, 3, 26, 13, 0, 99, 107, 3,
|
||||
30, 15, 0, 100, 107, 3, 44, 22, 0, 101, 107, 3, 18, 9, 0, 102, 107, 3,
|
||||
20, 10, 0, 103, 107, 3, 22, 11, 0, 104, 107, 3, 8, 4, 0, 105, 107, 3, 46,
|
||||
23, 0, 106, 94, 1, 0, 0, 0, 106, 95, 1, 0, 0, 0, 106, 96, 1, 0, 0, 0, 106,
|
||||
97, 1, 0, 0, 0, 106, 98, 1, 0, 0, 0, 106, 99, 1, 0, 0, 0, 106, 100, 1,
|
||||
0, 0, 0, 106, 101, 1, 0, 0, 0, 106, 102, 1, 0, 0, 0, 106, 103, 1, 0, 0,
|
||||
0, 106, 104, 1, 0, 0, 0, 106, 105, 1, 0, 0, 0, 107, 7, 1, 0, 0, 0, 108,
|
||||
110, 3, 10, 5, 0, 109, 111, 3, 36, 18, 0, 110, 109, 1, 0, 0, 0, 110, 111,
|
||||
1, 0, 0, 0, 111, 9, 1, 0, 0, 0, 112, 113, 3, 12, 6, 0, 113, 123, 5, 31,
|
||||
0, 0, 114, 119, 3, 48, 24, 0, 115, 116, 5, 35, 0, 0, 116, 118, 3, 48, 24,
|
||||
0, 117, 115, 1, 0, 0, 0, 118, 121, 1, 0, 0, 0, 119, 117, 1, 0, 0, 0, 119,
|
||||
120, 1, 0, 0, 0, 120, 124, 1, 0, 0, 0, 121, 119, 1, 0, 0, 0, 122, 124,
|
||||
5, 2, 0, 0, 123, 114, 1, 0, 0, 0, 123, 122, 1, 0, 0, 0, 123, 124, 1, 0,
|
||||
0, 0, 124, 125, 1, 0, 0, 0, 125, 126, 5, 32, 0, 0, 126, 11, 1, 0, 0, 0,
|
||||
127, 128, 7, 0, 0, 0, 128, 13, 1, 0, 0, 0, 129, 130, 5, 20, 0, 0, 130,
|
||||
131, 5, 31, 0, 0, 131, 134, 3, 16, 8, 0, 132, 133, 5, 35, 0, 0, 133, 135,
|
||||
3, 48, 24, 0, 134, 132, 1, 0, 0, 0, 134, 135, 1, 0, 0, 0, 135, 136, 1,
|
||||
0, 0, 0, 136, 137, 5, 32, 0, 0, 137, 15, 1, 0, 0, 0, 138, 140, 5, 47, 0,
|
||||
0, 139, 138, 1, 0, 0, 0, 139, 140, 1, 0, 0, 0, 140, 141, 1, 0, 0, 0, 141,
|
||||
143, 5, 46, 0, 0, 142, 144, 3, 36, 18, 0, 143, 142, 1, 0, 0, 0, 143, 144,
|
||||
1, 0, 0, 0, 144, 17, 1, 0, 0, 0, 145, 146, 5, 7, 0, 0, 146, 19, 1, 0, 0,
|
||||
0, 147, 153, 5, 8, 0, 0, 148, 150, 5, 31, 0, 0, 149, 151, 3, 32, 16, 0,
|
||||
150, 149, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152,
|
||||
154, 5, 32, 0, 0, 153, 148, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 156,
|
||||
1, 0, 0, 0, 155, 157, 3, 36, 18, 0, 156, 155, 1, 0, 0, 0, 156, 157, 1,
|
||||
0, 0, 0, 157, 21, 1, 0, 0, 0, 158, 159, 5, 21, 0, 0, 159, 161, 5, 31, 0,
|
||||
0, 160, 162, 3, 48, 24, 0, 161, 160, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0,
|
||||
162, 163, 1, 0, 0, 0, 163, 164, 5, 32, 0, 0, 164, 23, 1, 0, 0, 0, 165,
|
||||
168, 3, 32, 16, 0, 166, 168, 3, 10, 5, 0, 167, 165, 1, 0, 0, 0, 167, 166,
|
||||
1, 0, 0, 0, 168, 25, 1, 0, 0, 0, 169, 170, 5, 22, 0, 0, 170, 171, 5, 31,
|
||||
0, 0, 171, 176, 3, 24, 12, 0, 172, 173, 5, 35, 0, 0, 173, 175, 3, 24, 12,
|
||||
0, 174, 172, 1, 0, 0, 0, 175, 178, 1, 0, 0, 0, 176, 174, 1, 0, 0, 0, 176,
|
||||
177, 1, 0, 0, 0, 177, 179, 1, 0, 0, 0, 178, 176, 1, 0, 0, 0, 179, 180,
|
||||
5, 32, 0, 0, 180, 27, 1, 0, 0, 0, 181, 183, 3, 32, 16, 0, 182, 184, 7,
|
||||
1, 0, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 29, 1, 0, 0,
|
||||
0, 185, 186, 5, 25, 0, 0, 186, 187, 5, 31, 0, 0, 187, 192, 3, 28, 14, 0,
|
||||
188, 189, 5, 35, 0, 0, 189, 191, 3, 28, 14, 0, 190, 188, 1, 0, 0, 0, 191,
|
||||
194, 1, 0, 0, 0, 192, 190, 1, 0, 0, 0, 192, 193, 1, 0, 0, 0, 193, 195,
|
||||
1, 0, 0, 0, 194, 192, 1, 0, 0, 0, 195, 196, 5, 32, 0, 0, 196, 31, 1, 0,
|
||||
0, 0, 197, 199, 5, 46, 0, 0, 198, 200, 5, 46, 0, 0, 199, 198, 1, 0, 0,
|
||||
0, 199, 200, 1, 0, 0, 0, 200, 33, 1, 0, 0, 0, 201, 203, 3, 32, 16, 0, 202,
|
||||
204, 3, 36, 18, 0, 203, 202, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 35,
|
||||
1, 0, 0, 0, 205, 209, 5, 26, 0, 0, 206, 207, 5, 37, 0, 0, 207, 209, 7,
|
||||
2, 0, 0, 208, 205, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 209, 37, 1, 0, 0,
|
||||
0, 210, 211, 5, 27, 0, 0, 211, 39, 1, 0, 0, 0, 212, 213, 5, 47, 0, 0, 213,
|
||||
214, 5, 46, 0, 0, 214, 41, 1, 0, 0, 0, 215, 216, 5, 47, 0, 0, 216, 43,
|
||||
1, 0, 0, 0, 217, 226, 5, 9, 0, 0, 218, 219, 5, 38, 0, 0, 219, 220, 5, 37,
|
||||
0, 0, 220, 227, 5, 38, 0, 0, 221, 222, 5, 38, 0, 0, 222, 227, 5, 37, 0,
|
||||
0, 223, 224, 5, 37, 0, 0, 224, 227, 5, 38, 0, 0, 225, 227, 5, 38, 0, 0,
|
||||
226, 218, 1, 0, 0, 0, 226, 221, 1, 0, 0, 0, 226, 223, 1, 0, 0, 0, 226,
|
||||
225, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 229,
|
||||
5, 34, 0, 0, 229, 45, 1, 0, 0, 0, 230, 232, 3, 48, 24, 0, 231, 233, 3,
|
||||
36, 18, 0, 232, 231, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 47, 1, 0, 0,
|
||||
0, 234, 235, 6, 24, -1, 0, 235, 236, 5, 31, 0, 0, 236, 237, 3, 48, 24,
|
||||
0, 237, 238, 5, 32, 0, 0, 238, 247, 1, 0, 0, 0, 239, 247, 3, 32, 16, 0,
|
||||
240, 247, 3, 50, 25, 0, 241, 247, 3, 38, 19, 0, 242, 243, 3, 52, 26, 0,
|
||||
243, 244, 3, 48, 24, 9, 244, 247, 1, 0, 0, 0, 245, 247, 3, 10, 5, 0, 246,
|
||||
234, 1, 0, 0, 0, 246, 239, 1, 0, 0, 0, 246, 240, 1, 0, 0, 0, 246, 241,
|
||||
1, 0, 0, 0, 246, 242, 1, 0, 0, 0, 246, 245, 1, 0, 0, 0, 247, 275, 1, 0,
|
||||
0, 0, 248, 249, 10, 8, 0, 0, 249, 250, 5, 10, 0, 0, 250, 274, 3, 48, 24,
|
||||
9, 251, 252, 10, 7, 0, 0, 252, 253, 7, 3, 0, 0, 253, 274, 3, 48, 24, 8,
|
||||
254, 255, 10, 6, 0, 0, 255, 256, 7, 1, 0, 0, 256, 274, 3, 48, 24, 7, 257,
|
||||
258, 10, 5, 0, 0, 258, 259, 7, 4, 0, 0, 259, 274, 3, 48, 24, 6, 260, 261,
|
||||
10, 4, 0, 0, 261, 262, 7, 5, 0, 0, 262, 274, 3, 48, 24, 5, 263, 267, 10,
|
||||
3, 0, 0, 264, 268, 5, 45, 0, 0, 265, 268, 5, 44, 0, 0, 266, 268, 1, 0,
|
||||
0, 0, 267, 264, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 266, 1, 0, 0, 0,
|
||||
268, 269, 1, 0, 0, 0, 269, 274, 3, 48, 24, 4, 270, 271, 10, 2, 0, 0, 271,
|
||||
272, 5, 16, 0, 0, 272, 274, 3, 48, 24, 3, 273, 248, 1, 0, 0, 0, 273, 251,
|
||||
1, 0, 0, 0, 273, 254, 1, 0, 0, 0, 273, 257, 1, 0, 0, 0, 273, 260, 1, 0,
|
||||
0, 0, 273, 263, 1, 0, 0, 0, 273, 270, 1, 0, 0, 0, 274, 277, 1, 0, 0, 0,
|
||||
275, 273, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 49, 1, 0, 0, 0, 277, 275,
|
||||
1, 0, 0, 0, 278, 279, 7, 6, 0, 0, 279, 51, 1, 0, 0, 0, 280, 281, 7, 7,
|
||||
0, 0, 281, 53, 1, 0, 0, 0, 30, 57, 64, 69, 75, 83, 91, 106, 110, 119, 123,
|
||||
134, 139, 143, 150, 153, 156, 161, 167, 176, 183, 192, 199, 203, 208, 226,
|
||||
232, 246, 267, 273, 275,
|
||||
38, 40, 42, 44, 46, 48, 50, 52, 0, 9, 2, 0, 3, 8, 22, 22, 1, 0, 9, 10,
|
||||
1, 0, 26, 27, 3, 0, 30, 30, 32, 32, 51, 51, 2, 0, 2, 2, 14, 15, 1, 0, 16,
|
||||
18, 1, 0, 43, 46, 3, 0, 31, 31, 41, 42, 51, 51, 2, 0, 20, 21, 26, 27, 309,
|
||||
0, 57, 1, 0, 0, 0, 2, 78, 1, 0, 0, 0, 4, 86, 1, 0, 0, 0, 6, 106, 1, 0,
|
||||
0, 0, 8, 108, 1, 0, 0, 0, 10, 112, 1, 0, 0, 0, 12, 127, 1, 0, 0, 0, 14,
|
||||
129, 1, 0, 0, 0, 16, 139, 1, 0, 0, 0, 18, 145, 1, 0, 0, 0, 20, 147, 1,
|
||||
0, 0, 0, 22, 158, 1, 0, 0, 0, 24, 167, 1, 0, 0, 0, 26, 169, 1, 0, 0, 0,
|
||||
28, 181, 1, 0, 0, 0, 30, 185, 1, 0, 0, 0, 32, 197, 1, 0, 0, 0, 34, 201,
|
||||
1, 0, 0, 0, 36, 208, 1, 0, 0, 0, 38, 210, 1, 0, 0, 0, 40, 212, 1, 0, 0,
|
||||
0, 42, 215, 1, 0, 0, 0, 44, 217, 1, 0, 0, 0, 46, 230, 1, 0, 0, 0, 48, 246,
|
||||
1, 0, 0, 0, 50, 278, 1, 0, 0, 0, 52, 280, 1, 0, 0, 0, 54, 56, 5, 1, 0,
|
||||
0, 55, 54, 1, 0, 0, 0, 56, 59, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 57, 58,
|
||||
1, 0, 0, 0, 58, 60, 1, 0, 0, 0, 59, 57, 1, 0, 0, 0, 60, 69, 3, 2, 1, 0,
|
||||
61, 63, 5, 1, 0, 0, 62, 61, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0, 64, 62, 1,
|
||||
0, 0, 0, 64, 65, 1, 0, 0, 0, 65, 66, 1, 0, 0, 0, 66, 68, 3, 2, 1, 0, 67,
|
||||
62, 1, 0, 0, 0, 68, 71, 1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 69, 70, 1, 0, 0,
|
||||
0, 70, 75, 1, 0, 0, 0, 71, 69, 1, 0, 0, 0, 72, 74, 5, 1, 0, 0, 73, 72,
|
||||
1, 0, 0, 0, 74, 77, 1, 0, 0, 0, 75, 73, 1, 0, 0, 0, 75, 76, 1, 0, 0, 0,
|
||||
76, 1, 1, 0, 0, 0, 77, 75, 1, 0, 0, 0, 78, 83, 3, 4, 2, 0, 79, 80, 5, 39,
|
||||
0, 0, 80, 82, 3, 4, 2, 0, 81, 79, 1, 0, 0, 0, 82, 85, 1, 0, 0, 0, 83, 81,
|
||||
1, 0, 0, 0, 83, 84, 1, 0, 0, 0, 84, 3, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0,
|
||||
86, 91, 3, 6, 3, 0, 87, 88, 5, 38, 0, 0, 88, 90, 3, 6, 3, 0, 89, 87, 1,
|
||||
0, 0, 0, 90, 93, 1, 0, 0, 0, 91, 89, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92,
|
||||
5, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 94, 107, 3, 40, 20, 0, 95, 107, 3, 42,
|
||||
21, 0, 96, 107, 3, 34, 17, 0, 97, 107, 3, 14, 7, 0, 98, 107, 3, 26, 13,
|
||||
0, 99, 107, 3, 30, 15, 0, 100, 107, 3, 44, 22, 0, 101, 107, 3, 18, 9, 0,
|
||||
102, 107, 3, 20, 10, 0, 103, 107, 3, 22, 11, 0, 104, 107, 3, 8, 4, 0, 105,
|
||||
107, 3, 46, 23, 0, 106, 94, 1, 0, 0, 0, 106, 95, 1, 0, 0, 0, 106, 96, 1,
|
||||
0, 0, 0, 106, 97, 1, 0, 0, 0, 106, 98, 1, 0, 0, 0, 106, 99, 1, 0, 0, 0,
|
||||
106, 100, 1, 0, 0, 0, 106, 101, 1, 0, 0, 0, 106, 102, 1, 0, 0, 0, 106,
|
||||
103, 1, 0, 0, 0, 106, 104, 1, 0, 0, 0, 106, 105, 1, 0, 0, 0, 107, 7, 1,
|
||||
0, 0, 0, 108, 110, 3, 10, 5, 0, 109, 111, 3, 36, 18, 0, 110, 109, 1, 0,
|
||||
0, 0, 110, 111, 1, 0, 0, 0, 111, 9, 1, 0, 0, 0, 112, 113, 3, 12, 6, 0,
|
||||
113, 123, 5, 34, 0, 0, 114, 119, 3, 48, 24, 0, 115, 116, 5, 38, 0, 0, 116,
|
||||
118, 3, 48, 24, 0, 117, 115, 1, 0, 0, 0, 118, 121, 1, 0, 0, 0, 119, 117,
|
||||
1, 0, 0, 0, 119, 120, 1, 0, 0, 0, 120, 124, 1, 0, 0, 0, 121, 119, 1, 0,
|
||||
0, 0, 122, 124, 5, 2, 0, 0, 123, 114, 1, 0, 0, 0, 123, 122, 1, 0, 0, 0,
|
||||
123, 124, 1, 0, 0, 0, 124, 125, 1, 0, 0, 0, 125, 126, 5, 35, 0, 0, 126,
|
||||
11, 1, 0, 0, 0, 127, 128, 7, 0, 0, 0, 128, 13, 1, 0, 0, 0, 129, 130, 5,
|
||||
23, 0, 0, 130, 131, 5, 34, 0, 0, 131, 134, 3, 16, 8, 0, 132, 133, 5, 38,
|
||||
0, 0, 133, 135, 3, 48, 24, 0, 134, 132, 1, 0, 0, 0, 134, 135, 1, 0, 0,
|
||||
0, 135, 136, 1, 0, 0, 0, 136, 137, 5, 35, 0, 0, 137, 15, 1, 0, 0, 0, 138,
|
||||
140, 5, 50, 0, 0, 139, 138, 1, 0, 0, 0, 139, 140, 1, 0, 0, 0, 140, 141,
|
||||
1, 0, 0, 0, 141, 143, 5, 49, 0, 0, 142, 144, 3, 36, 18, 0, 143, 142, 1,
|
||||
0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 17, 1, 0, 0, 0, 145, 146, 7, 1, 0,
|
||||
0, 146, 19, 1, 0, 0, 0, 147, 153, 5, 11, 0, 0, 148, 150, 5, 34, 0, 0, 149,
|
||||
151, 3, 32, 16, 0, 150, 149, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 152,
|
||||
1, 0, 0, 0, 152, 154, 5, 35, 0, 0, 153, 148, 1, 0, 0, 0, 153, 154, 1, 0,
|
||||
0, 0, 154, 156, 1, 0, 0, 0, 155, 157, 3, 36, 18, 0, 156, 155, 1, 0, 0,
|
||||
0, 156, 157, 1, 0, 0, 0, 157, 21, 1, 0, 0, 0, 158, 159, 5, 24, 0, 0, 159,
|
||||
161, 5, 34, 0, 0, 160, 162, 3, 48, 24, 0, 161, 160, 1, 0, 0, 0, 161, 162,
|
||||
1, 0, 0, 0, 162, 163, 1, 0, 0, 0, 163, 164, 5, 35, 0, 0, 164, 23, 1, 0,
|
||||
0, 0, 165, 168, 3, 32, 16, 0, 166, 168, 3, 10, 5, 0, 167, 165, 1, 0, 0,
|
||||
0, 167, 166, 1, 0, 0, 0, 168, 25, 1, 0, 0, 0, 169, 170, 5, 25, 0, 0, 170,
|
||||
171, 5, 34, 0, 0, 171, 176, 3, 24, 12, 0, 172, 173, 5, 38, 0, 0, 173, 175,
|
||||
3, 24, 12, 0, 174, 172, 1, 0, 0, 0, 175, 178, 1, 0, 0, 0, 176, 174, 1,
|
||||
0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 179, 1, 0, 0, 0, 178, 176, 1, 0, 0,
|
||||
0, 179, 180, 5, 35, 0, 0, 180, 27, 1, 0, 0, 0, 181, 183, 3, 32, 16, 0,
|
||||
182, 184, 7, 2, 0, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184,
|
||||
29, 1, 0, 0, 0, 185, 186, 5, 28, 0, 0, 186, 187, 5, 34, 0, 0, 187, 192,
|
||||
3, 28, 14, 0, 188, 189, 5, 38, 0, 0, 189, 191, 3, 28, 14, 0, 190, 188,
|
||||
1, 0, 0, 0, 191, 194, 1, 0, 0, 0, 192, 190, 1, 0, 0, 0, 192, 193, 1, 0,
|
||||
0, 0, 193, 195, 1, 0, 0, 0, 194, 192, 1, 0, 0, 0, 195, 196, 5, 35, 0, 0,
|
||||
196, 31, 1, 0, 0, 0, 197, 199, 5, 49, 0, 0, 198, 200, 5, 49, 0, 0, 199,
|
||||
198, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 33, 1, 0, 0, 0, 201, 203, 3,
|
||||
32, 16, 0, 202, 204, 3, 36, 18, 0, 203, 202, 1, 0, 0, 0, 203, 204, 1, 0,
|
||||
0, 0, 204, 35, 1, 0, 0, 0, 205, 209, 5, 29, 0, 0, 206, 207, 5, 40, 0, 0,
|
||||
207, 209, 7, 3, 0, 0, 208, 205, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 209,
|
||||
37, 1, 0, 0, 0, 210, 211, 5, 30, 0, 0, 211, 39, 1, 0, 0, 0, 212, 213, 5,
|
||||
50, 0, 0, 213, 214, 5, 49, 0, 0, 214, 41, 1, 0, 0, 0, 215, 216, 5, 50,
|
||||
0, 0, 216, 43, 1, 0, 0, 0, 217, 226, 5, 12, 0, 0, 218, 219, 5, 41, 0, 0,
|
||||
219, 220, 5, 40, 0, 0, 220, 227, 5, 41, 0, 0, 221, 222, 5, 41, 0, 0, 222,
|
||||
227, 5, 40, 0, 0, 223, 224, 5, 40, 0, 0, 224, 227, 5, 41, 0, 0, 225, 227,
|
||||
5, 41, 0, 0, 226, 218, 1, 0, 0, 0, 226, 221, 1, 0, 0, 0, 226, 223, 1, 0,
|
||||
0, 0, 226, 225, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0,
|
||||
228, 229, 5, 37, 0, 0, 229, 45, 1, 0, 0, 0, 230, 232, 3, 48, 24, 0, 231,
|
||||
233, 3, 36, 18, 0, 232, 231, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 47,
|
||||
1, 0, 0, 0, 234, 235, 6, 24, -1, 0, 235, 236, 5, 34, 0, 0, 236, 237, 3,
|
||||
48, 24, 0, 237, 238, 5, 35, 0, 0, 238, 247, 1, 0, 0, 0, 239, 247, 3, 32,
|
||||
16, 0, 240, 247, 3, 50, 25, 0, 241, 247, 3, 38, 19, 0, 242, 243, 3, 52,
|
||||
26, 0, 243, 244, 3, 48, 24, 9, 244, 247, 1, 0, 0, 0, 245, 247, 3, 10, 5,
|
||||
0, 246, 234, 1, 0, 0, 0, 246, 239, 1, 0, 0, 0, 246, 240, 1, 0, 0, 0, 246,
|
||||
241, 1, 0, 0, 0, 246, 242, 1, 0, 0, 0, 246, 245, 1, 0, 0, 0, 247, 275,
|
||||
1, 0, 0, 0, 248, 249, 10, 8, 0, 0, 249, 250, 5, 13, 0, 0, 250, 274, 3,
|
||||
48, 24, 9, 251, 252, 10, 7, 0, 0, 252, 253, 7, 4, 0, 0, 253, 274, 3, 48,
|
||||
24, 8, 254, 255, 10, 6, 0, 0, 255, 256, 7, 2, 0, 0, 256, 274, 3, 48, 24,
|
||||
7, 257, 258, 10, 5, 0, 0, 258, 259, 7, 5, 0, 0, 259, 274, 3, 48, 24, 6,
|
||||
260, 261, 10, 4, 0, 0, 261, 262, 7, 6, 0, 0, 262, 274, 3, 48, 24, 5, 263,
|
||||
267, 10, 3, 0, 0, 264, 268, 5, 48, 0, 0, 265, 268, 5, 47, 0, 0, 266, 268,
|
||||
1, 0, 0, 0, 267, 264, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 266, 1, 0,
|
||||
0, 0, 268, 269, 1, 0, 0, 0, 269, 274, 3, 48, 24, 4, 270, 271, 10, 2, 0,
|
||||
0, 271, 272, 5, 19, 0, 0, 272, 274, 3, 48, 24, 3, 273, 248, 1, 0, 0, 0,
|
||||
273, 251, 1, 0, 0, 0, 273, 254, 1, 0, 0, 0, 273, 257, 1, 0, 0, 0, 273,
|
||||
260, 1, 0, 0, 0, 273, 263, 1, 0, 0, 0, 273, 270, 1, 0, 0, 0, 274, 277,
|
||||
1, 0, 0, 0, 275, 273, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 49, 1, 0,
|
||||
0, 0, 277, 275, 1, 0, 0, 0, 278, 279, 7, 7, 0, 0, 279, 51, 1, 0, 0, 0,
|
||||
280, 281, 7, 8, 0, 0, 281, 53, 1, 0, 0, 0, 30, 57, 64, 69, 75, 83, 91,
|
||||
106, 110, 119, 123, 134, 139, 143, 150, 153, 156, 161, 167, 176, 183, 192,
|
||||
199, 203, 208, 226, 232, 246, 267, 273, 275,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
@ -240,37 +240,40 @@ const (
|
||||
SLQParserT__15 = 16
|
||||
SLQParserT__16 = 17
|
||||
SLQParserT__17 = 18
|
||||
SLQParserPROPRIETARY_FUNC_NAME = 19
|
||||
SLQParserJOIN_TYPE = 20
|
||||
SLQParserWHERE = 21
|
||||
SLQParserGROUP_BY = 22
|
||||
SLQParserORDER_ASC = 23
|
||||
SLQParserORDER_DESC = 24
|
||||
SLQParserORDER_BY = 25
|
||||
SLQParserALIAS_RESERVED = 26
|
||||
SLQParserARG = 27
|
||||
SLQParserNULL = 28
|
||||
SLQParserID = 29
|
||||
SLQParserWS = 30
|
||||
SLQParserLPAR = 31
|
||||
SLQParserRPAR = 32
|
||||
SLQParserLBRA = 33
|
||||
SLQParserRBRA = 34
|
||||
SLQParserCOMMA = 35
|
||||
SLQParserPIPE = 36
|
||||
SLQParserCOLON = 37
|
||||
SLQParserNN = 38
|
||||
SLQParserNUMBER = 39
|
||||
SLQParserLT_EQ = 40
|
||||
SLQParserLT = 41
|
||||
SLQParserGT_EQ = 42
|
||||
SLQParserGT = 43
|
||||
SLQParserNEQ = 44
|
||||
SLQParserEQ = 45
|
||||
SLQParserNAME = 46
|
||||
SLQParserHANDLE = 47
|
||||
SLQParserSTRING = 48
|
||||
SLQParserLINECOMMENT = 49
|
||||
SLQParserT__18 = 19
|
||||
SLQParserT__19 = 20
|
||||
SLQParserT__20 = 21
|
||||
SLQParserPROPRIETARY_FUNC_NAME = 22
|
||||
SLQParserJOIN_TYPE = 23
|
||||
SLQParserWHERE = 24
|
||||
SLQParserGROUP_BY = 25
|
||||
SLQParserORDER_ASC = 26
|
||||
SLQParserORDER_DESC = 27
|
||||
SLQParserORDER_BY = 28
|
||||
SLQParserALIAS_RESERVED = 29
|
||||
SLQParserARG = 30
|
||||
SLQParserNULL = 31
|
||||
SLQParserID = 32
|
||||
SLQParserWS = 33
|
||||
SLQParserLPAR = 34
|
||||
SLQParserRPAR = 35
|
||||
SLQParserLBRA = 36
|
||||
SLQParserRBRA = 37
|
||||
SLQParserCOMMA = 38
|
||||
SLQParserPIPE = 39
|
||||
SLQParserCOLON = 40
|
||||
SLQParserNN = 41
|
||||
SLQParserNUMBER = 42
|
||||
SLQParserLT_EQ = 43
|
||||
SLQParserLT = 44
|
||||
SLQParserGT_EQ = 45
|
||||
SLQParserGT = 46
|
||||
SLQParserNEQ = 47
|
||||
SLQParserEQ = 48
|
||||
SLQParserNAME = 49
|
||||
SLQParserHANDLE = 50
|
||||
SLQParserSTRING = 51
|
||||
SLQParserLINECOMMENT = 52
|
||||
)
|
||||
|
||||
// SLQParser rules.
|
||||
@ -1624,7 +1627,7 @@ func (p *SLQParser) Func_() (localctx IFuncContext) {
|
||||
goto errorExit
|
||||
}
|
||||
switch p.GetTokenStream().LA(1) {
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__16, SLQParserT__17, SLQParserPROPRIETARY_FUNC_NAME, SLQParserORDER_ASC, SLQParserORDER_DESC, SLQParserARG, SLQParserNULL, SLQParserLPAR, SLQParserNN, SLQParserNUMBER, SLQParserNAME, SLQParserSTRING:
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__6, SLQParserT__7, SLQParserT__19, SLQParserT__20, SLQParserPROPRIETARY_FUNC_NAME, SLQParserORDER_ASC, SLQParserORDER_DESC, SLQParserARG, SLQParserNULL, SLQParserLPAR, SLQParserNN, SLQParserNUMBER, SLQParserNAME, SLQParserSTRING:
|
||||
{
|
||||
p.SetState(114)
|
||||
p.expr(0)
|
||||
@ -1784,7 +1787,7 @@ func (p *SLQParser) FuncName() (localctx IFuncNameContext) {
|
||||
p.SetState(127)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&524408) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&4194808) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -2240,13 +2243,18 @@ func (s *UniqueFuncContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
|
||||
func (p *SLQParser) UniqueFunc() (localctx IUniqueFuncContext) {
|
||||
localctx = NewUniqueFuncContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 18, SLQParserRULE_uniqueFunc)
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(145)
|
||||
p.Match(SLQParserT__6)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !(_la == SLQParserT__8 || _la == SLQParserT__9) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
p.Consume()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2390,7 +2398,7 @@ func (p *SLQParser) CountFunc() (localctx ICountFuncContext) {
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(147)
|
||||
p.Match(SLQParserT__7)
|
||||
p.Match(SLQParserT__10)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
@ -2600,7 +2608,7 @@ func (p *SLQParser) Where() (localctx IWhereContext) {
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&352670930829432) != 0 {
|
||||
if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&2821367446635000) != 0 {
|
||||
{
|
||||
p.SetState(160)
|
||||
p.expr(0)
|
||||
@ -2755,7 +2763,7 @@ func (p *SLQParser) GroupByTerm() (localctx IGroupByTermContext) {
|
||||
p.Selector()
|
||||
}
|
||||
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserPROPRIETARY_FUNC_NAME:
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__6, SLQParserT__7, SLQParserPROPRIETARY_FUNC_NAME:
|
||||
p.EnterOuterAlt(localctx, 2)
|
||||
{
|
||||
p.SetState(166)
|
||||
@ -3777,7 +3785,7 @@ func (p *SLQParser) Alias() (localctx IAliasContext) {
|
||||
p.SetState(207)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&281475647799296) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&2251805182394368) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -4235,7 +4243,7 @@ func (p *SLQParser) RowRange() (localctx IRowRangeContext) {
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(217)
|
||||
p.Match(SLQParserT__8)
|
||||
p.Match(SLQParserT__11)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
@ -4812,7 +4820,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
p.Arg()
|
||||
}
|
||||
|
||||
case SLQParserT__16, SLQParserT__17, SLQParserORDER_ASC, SLQParserORDER_DESC:
|
||||
case SLQParserT__19, SLQParserT__20, SLQParserORDER_ASC, SLQParserORDER_DESC:
|
||||
{
|
||||
p.SetState(242)
|
||||
p.UnaryOperator()
|
||||
@ -4822,7 +4830,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
p.expr(9)
|
||||
}
|
||||
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserPROPRIETARY_FUNC_NAME:
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__6, SLQParserT__7, SLQParserPROPRIETARY_FUNC_NAME:
|
||||
{
|
||||
p.SetState(245)
|
||||
p.Func_()
|
||||
@ -4866,7 +4874,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
}
|
||||
{
|
||||
p.SetState(249)
|
||||
p.Match(SLQParserT__9)
|
||||
p.Match(SLQParserT__12)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
@ -4890,7 +4898,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
p.SetState(252)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&6148) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&49156) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -4940,7 +4948,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
p.SetState(258)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&57344) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&458752) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -4965,7 +4973,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
p.SetState(261)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&16492674416640) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&131941395333120) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -5013,7 +5021,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
}
|
||||
}
|
||||
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__16, SLQParserT__17, SLQParserPROPRIETARY_FUNC_NAME, SLQParserORDER_ASC, SLQParserORDER_DESC, SLQParserARG, SLQParserNULL, SLQParserLPAR, SLQParserNN, SLQParserNUMBER, SLQParserNAME, SLQParserSTRING:
|
||||
case SLQParserT__2, SLQParserT__3, SLQParserT__4, SLQParserT__5, SLQParserT__6, SLQParserT__7, SLQParserT__19, SLQParserT__20, SLQParserPROPRIETARY_FUNC_NAME, SLQParserORDER_ASC, SLQParserORDER_DESC, SLQParserARG, SLQParserNULL, SLQParserLPAR, SLQParserNN, SLQParserNUMBER, SLQParserNAME, SLQParserSTRING:
|
||||
|
||||
default:
|
||||
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
|
||||
@ -5035,7 +5043,7 @@ func (p *SLQParser) expr(_p int) (localctx IExprContext) {
|
||||
}
|
||||
{
|
||||
p.SetState(271)
|
||||
p.Match(SLQParserT__15)
|
||||
p.Match(SLQParserT__18)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
@ -5180,7 +5188,7 @@ func (p *SLQParser) Literal() (localctx ILiteralContext) {
|
||||
p.SetState(278)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&282299878866944) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&2258399030935552) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
@ -5296,7 +5304,7 @@ func (p *SLQParser) UnaryOperator() (localctx IUnaryOperatorContext) {
|
||||
p.SetState(280)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&25559040) != 0) {
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&204472320) != 0) {
|
||||
p.GetErrorHandler().RecoverInline(p)
|
||||
} else {
|
||||
p.GetErrorHandler().ReportMatch(p)
|
||||
|
@ -3,6 +3,8 @@ package ast
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/jointype"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/ast/internal/slq"
|
||||
@ -104,8 +106,8 @@ func (v *parseTreeVisitor) VisitJoinTable(ctx *slq.JoinTableContext) any {
|
||||
},
|
||||
name0: tblName,
|
||||
},
|
||||
handle: handle,
|
||||
tblName: tblName,
|
||||
handle: handle,
|
||||
tbl: tablefq.From(tblName),
|
||||
}
|
||||
|
||||
var aliasCtx *slq.AliasContext
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
// .actor --> FROM "actor"
|
||||
// .actor:a --> FROM "actor" "a"
|
||||
func doFromTable(rc *Context, tblSel *ast.TblSelectorNode) (string, error) {
|
||||
tblName := tblSel.TblName()
|
||||
if tblName == "" {
|
||||
tbl := tblSel.Table()
|
||||
if tbl.Table == "" {
|
||||
return "", errz.Errorf("selector has empty table name: {%s}", tblSel.Text())
|
||||
}
|
||||
|
||||
clause := "FROM " + rc.Dialect.Enquote(tblName)
|
||||
clause := "FROM " + tbl.Render(rc.Dialect.Enquote)
|
||||
alias := tblSel.Alias()
|
||||
if alias != "" {
|
||||
clause += " AS " + rc.Dialect.Enquote(alias)
|
||||
|
@ -12,6 +12,17 @@ import (
|
||||
func doFunction(rc *Context, fn *ast.FuncNode) (string, error) {
|
||||
sb := strings.Builder{}
|
||||
fnName := strings.ToLower(fn.FuncName())
|
||||
|
||||
if f, ok := rc.Renderer.FunctionOverrides[fnName]; ok {
|
||||
// The SQL function name has a custom renderer.
|
||||
return f(rc, fn)
|
||||
}
|
||||
|
||||
if f, ok := rc.Renderer.FunctionNames[fnName]; ok {
|
||||
// The SLQ function name is mapped to a different SQL function
|
||||
// for this dialect.
|
||||
fnName = f
|
||||
}
|
||||
children := fn.Children()
|
||||
|
||||
if len(children) == 0 {
|
||||
|
@ -38,7 +38,7 @@ func doJoin(rc *Context, leftTbl *ast.TblSelectorNode, joins []*ast.JoinNode) (s
|
||||
}
|
||||
|
||||
sql := "FROM "
|
||||
sql = sqlAppend(sql, enquote(leftTbl.TblName()))
|
||||
sql = sqlAppend(sql, leftTbl.Table().Render(enquote))
|
||||
if leftTbl.Alias() != "" {
|
||||
sql = sqlAppend(sql, "AS "+enquote(leftTbl.Alias()))
|
||||
}
|
||||
@ -56,7 +56,7 @@ func doJoin(rc *Context, leftTbl *ast.TblSelectorNode, joins []*ast.JoinNode) (s
|
||||
}
|
||||
|
||||
tbl := join.Table()
|
||||
s = sqlAppend(s, enquote(tbl.TblName()))
|
||||
s = sqlAppend(s, tbl.Table().Render(enquote))
|
||||
if tbl.Alias() != "" {
|
||||
s = sqlAppend(s, "AS "+enquote(tbl.Alias()))
|
||||
}
|
||||
@ -77,9 +77,9 @@ func doJoin(rc *Context, leftTbl *ast.TblSelectorNode, joins []*ast.JoinNode) (s
|
||||
if colSel, ok := children[0].(*ast.ColSelectorNode); ok {
|
||||
// TODO: should be able to handle ast.TblColSelector also?
|
||||
colName := colSel.ColName()
|
||||
text := enquote(allTbls[i].TblAliasOrName()) + "." + enquote(colName)
|
||||
text := allTbls[i].TblAliasOrName().Render(enquote) + "." + enquote(colName)
|
||||
text += " = "
|
||||
text += enquote(allTbls[i+1].TblAliasOrName()) + "." + enquote(colName)
|
||||
text += allTbls[i+1].TblAliasOrName().Render(enquote) + "." + enquote(colName)
|
||||
s = sqlAppend(s, text)
|
||||
sql = sqlAppend(sql, s)
|
||||
continue
|
||||
|
@ -52,6 +52,16 @@ type Renderer struct {
|
||||
// Function renders a function fragment.
|
||||
Function func(rc *Context, fn *ast.FuncNode) (string, error)
|
||||
|
||||
// FunctionNames is a map of SLQ function name to SQL function name.
|
||||
// It can be used by the Renderer.Function impl. Note that FunctionOverrides
|
||||
// has precedence over FunctionNames.
|
||||
FunctionNames map[string]string
|
||||
|
||||
// FunctionOverrides is a map of SLQ function name to a custom
|
||||
// function to render that function. It can be used by the Renderer.Function
|
||||
// imp. FunctionOverrides has precedence over FunctionNames.
|
||||
FunctionOverrides map[string]func(rc *Context, fn *ast.FuncNode) (string, error)
|
||||
|
||||
// Literal renders a literal fragment.
|
||||
Literal func(rc *Context, lit *ast.LiteralNode) (string, error)
|
||||
|
||||
@ -81,19 +91,21 @@ type Renderer struct {
|
||||
// as needed.
|
||||
func NewDefaultRenderer() *Renderer {
|
||||
return &Renderer{
|
||||
FromTable: doFromTable,
|
||||
SelectCols: doSelectCols,
|
||||
Range: doRange,
|
||||
OrderBy: doOrderBy,
|
||||
GroupBy: doGroupBy,
|
||||
Join: doJoin,
|
||||
Function: doFunction,
|
||||
Literal: doLiteral,
|
||||
Where: doWhere,
|
||||
Expr: doExpr,
|
||||
Operator: doOperator,
|
||||
Distinct: doDistinct,
|
||||
Render: doRender,
|
||||
FromTable: doFromTable,
|
||||
SelectCols: doSelectCols,
|
||||
Range: doRange,
|
||||
OrderBy: doOrderBy,
|
||||
GroupBy: doGroupBy,
|
||||
Join: doJoin,
|
||||
Function: doFunction,
|
||||
FunctionOverrides: map[string]func(rc *Context, fn *ast.FuncNode) (string, error){},
|
||||
FunctionNames: map[string]string{},
|
||||
Literal: doLiteral,
|
||||
Where: doWhere,
|
||||
Expr: doExpr,
|
||||
Operator: doOperator,
|
||||
Distinct: doDistinct,
|
||||
Render: doRender,
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +177,7 @@ func renderSelectorNode(d dialect.Dialect, node ast.Node) (string, error) {
|
||||
case *ast.TblColSelectorNode:
|
||||
return d.Enquote(node.TblName()) + "." + d.Enquote(node.ColName()), nil
|
||||
case *ast.TblSelectorNode:
|
||||
return d.Enquote(node.TblName()), nil
|
||||
return node.Table().Render(d.Enquote), nil
|
||||
default:
|
||||
return "", errz.Errorf(
|
||||
"expected selector node type, but got %T: %s",
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/tablefq"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/stringz"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
@ -128,42 +130,49 @@ var _ Node = (*TblSelectorNode)(nil)
|
||||
type TblSelectorNode struct {
|
||||
SelectorNode
|
||||
|
||||
handle string
|
||||
tblName string
|
||||
handle string
|
||||
tbl tablefq.T
|
||||
}
|
||||
|
||||
// newTblSelector creates a new TblSelectorNode from ctx.
|
||||
func newTblSelector(selNode *SelectorNode) (*TblSelectorNode, error) { //nolint:unparam
|
||||
n := &TblSelectorNode{
|
||||
SelectorNode: *selNode,
|
||||
tblName: selNode.name0,
|
||||
tbl: tablefq.From(selNode.name0),
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// TblName returns the table name. This is the raw value without punctuation.
|
||||
func (n *TblSelectorNode) TblName() string {
|
||||
return n.tblName
|
||||
// SetTable sets the table value.
|
||||
func (n *TblSelectorNode) SetTable(tbl tablefq.T) {
|
||||
n.tbl = tbl
|
||||
}
|
||||
|
||||
// Table returns the table name. This is the raw value without punctuation.
|
||||
func (n *TblSelectorNode) Table() tablefq.T {
|
||||
return n.tbl
|
||||
}
|
||||
|
||||
// SyncTblNameAlias sets the table name to the alias value,
|
||||
// if the alias is non-empty, and then sets the alias to empty.
|
||||
func (n *TblSelectorNode) SyncTblNameAlias() {
|
||||
if n.alias != "" {
|
||||
n.tblName = n.alias
|
||||
n.tbl = tablefq.From(n.alias)
|
||||
n.alias = ""
|
||||
}
|
||||
}
|
||||
|
||||
// TblAliasOrName returns the table alias if set; if not, it
|
||||
// returns the table name.
|
||||
func (n *TblSelectorNode) TblAliasOrName() string {
|
||||
func (n *TblSelectorNode) TblAliasOrName() tablefq.T {
|
||||
if n.alias != "" {
|
||||
return n.alias
|
||||
t := n.tbl
|
||||
t.Table = n.alias
|
||||
return t
|
||||
}
|
||||
|
||||
return n.tblName
|
||||
return n.tbl
|
||||
}
|
||||
|
||||
// Alias returns the node's alias, or empty string.
|
||||
@ -184,7 +193,7 @@ func (n *TblSelectorNode) SetHandle(h string) {
|
||||
// SelValue returns the table name.
|
||||
// TODO: Can we get rid of this method SelValue?
|
||||
func (n *TblSelectorNode) SelValue() (string, error) {
|
||||
return n.TblName(), nil
|
||||
return n.tbl.Table, nil
|
||||
}
|
||||
|
||||
// String returns a log/debug-friendly representation.
|
||||
|
@ -3,11 +3,15 @@
|
||||
package lga
|
||||
|
||||
const (
|
||||
After = "after"
|
||||
Alt = "alt"
|
||||
Before = "before"
|
||||
Catalog = "catalog"
|
||||
Cmd = "cmd"
|
||||
Col = "column"
|
||||
Count = "count"
|
||||
Commit = "commit"
|
||||
Conn = "conn"
|
||||
Cleanup = "cleanup"
|
||||
DB = "db"
|
||||
DBType = "db_type"
|
||||
@ -24,6 +28,8 @@ const (
|
||||
Key = "key"
|
||||
Kind = "kind"
|
||||
Loc = "loc"
|
||||
New = "new"
|
||||
Old = "old"
|
||||
Opts = "opts"
|
||||
Path = "path"
|
||||
Pid = "pid"
|
||||
|
@ -2,11 +2,15 @@
|
||||
// Ideally these functions would be merged into that package.
|
||||
package loz
|
||||
|
||||
// All returns a new slice containing elems.
|
||||
import "github.com/samber/lo"
|
||||
|
||||
// All returns a new slice containing elems. If elems is
|
||||
// nil, an empty slice is returned.
|
||||
func All[T any](elems ...T) []T {
|
||||
a := make([]T, len(elems))
|
||||
copy(a, elems)
|
||||
return a
|
||||
if elems == nil {
|
||||
return []T{}
|
||||
}
|
||||
return elems
|
||||
}
|
||||
|
||||
// Apply returns a new slice whose elements are the result of applying fn to
|
||||
@ -126,3 +130,24 @@ func IsSliceZeroed[T comparable](a []T) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NilIfZero returns nil if t is T's zero value; otherwise it
|
||||
// returns a pointer to t.
|
||||
func NilIfZero[T comparable](t T) *T {
|
||||
if lo.IsEmpty(t) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
// ZeroIfNil returns the zero value of T if t is nil, otherwise
|
||||
// it returns the dereferenced value of t.
|
||||
func ZeroIfNil[T comparable](t *T) T {
|
||||
if t == nil {
|
||||
var v T
|
||||
return v
|
||||
}
|
||||
|
||||
return *t
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ func TestAll(t *testing.T) {
|
||||
|
||||
gotStrings := loz.All("hello", "world")
|
||||
require.Equal(t, []string{"hello", "world"}, gotStrings)
|
||||
|
||||
wantInts := []int{1, 2, 3}
|
||||
gotInts := loz.All(wantInts...)
|
||||
require.Equal(t, wantInts, gotInts)
|
||||
require.False(t, &gotInts == &wantInts,
|
||||
"wantInts and gotInts should not be the same slice")
|
||||
}
|
||||
|
||||
func TestToSliceType(t *testing.T) {
|
||||
|
70
libsq/core/sqlz/connector.go
Normal file
70
libsq/core/sqlz/connector.go
Normal file
@ -0,0 +1,70 @@
|
||||
package sqlz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ConnectorWith returns a stdlib driver.Connector that wraps the
|
||||
// supplied impl, applying the non-nil fn to the connection returned
|
||||
// by Connect. If fn is nil, impl is returned unchanged.
|
||||
//
|
||||
// If impl implements io.Closer, the returned connector will also
|
||||
// implement io.Closer. This behavior conforms to the expectations
|
||||
// of driver.Connector:
|
||||
//
|
||||
// If a Connector implements io.Closer, the sql package's DB.Close
|
||||
// method will call Close and return error (if any).
|
||||
func ConnectorWith(impl driver.Connector, fn func(ctx context.Context, conn driver.Conn) error) driver.Connector {
|
||||
if fn == nil {
|
||||
return impl
|
||||
}
|
||||
|
||||
c := connector{impl: impl, fn: fn}
|
||||
|
||||
if _, ok := impl.(io.Closer); ok {
|
||||
return connectorCloser{c}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
var _ driver.Connector = (*connector)(nil)
|
||||
|
||||
type connector struct {
|
||||
impl driver.Connector
|
||||
fn func(ctx context.Context, conn driver.Conn) error
|
||||
}
|
||||
|
||||
// Connect implements driver.Connector.
|
||||
func (c connector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||
conn, err := c.impl.Connect(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = c.fn(ctx, conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Driver implements driver.Connector.
|
||||
func (c connector) Driver() driver.Driver {
|
||||
return c.impl.Driver()
|
||||
}
|
||||
|
||||
var (
|
||||
_ driver.Connector = (*connectorCloser)(nil)
|
||||
_ io.Closer = (*connectorCloser)(nil)
|
||||
)
|
||||
|
||||
type connectorCloser struct {
|
||||
connector
|
||||
}
|
||||
|
||||
// Close implements io.Closer.
|
||||
func (c connectorCloser) Close() error {
|
||||
return c.impl.(io.Closer).Close()
|
||||
}
|
84
libsq/core/sqlz/connector_test.go
Normal file
84
libsq/core/sqlz/connector_test.go
Normal file
@ -0,0 +1,84 @@
|
||||
package sqlz_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/mattn/go-sqlite3"
|
||||
"github.com/neilotoole/sq/libsq/core/sqlz"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var _ driver.Connector = (*tConnector)(nil)
|
||||
|
||||
type tConnector struct{}
|
||||
|
||||
func (t tConnector) Connect(_ context.Context) (driver.Conn, error) {
|
||||
return &sqlite3.SQLiteConn{}, nil
|
||||
}
|
||||
|
||||
func (t tConnector) Driver() driver.Driver {
|
||||
return &sqlite3.SQLiteDriver{}
|
||||
}
|
||||
|
||||
var (
|
||||
_ driver.Connector = (*tConnectorCloser)(nil)
|
||||
_ io.Closer = (*tConnectorCloser)(nil)
|
||||
)
|
||||
|
||||
type tConnectorCloser struct{}
|
||||
|
||||
func (t tConnectorCloser) Connect(_ context.Context) (driver.Conn, error) {
|
||||
return &sqlite3.SQLiteConn{}, nil
|
||||
}
|
||||
|
||||
func (t tConnectorCloser) Driver() driver.Driver {
|
||||
return &sqlite3.SQLiteDriver{}
|
||||
}
|
||||
|
||||
func (t tConnectorCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestConnectorWith(t *testing.T) {
|
||||
var c driver.Connector
|
||||
var invoked bool
|
||||
fn := func(ctx context.Context, conn driver.Conn) error {
|
||||
invoked = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test that ConnectorWith returns the same connector
|
||||
// if fn is nil.
|
||||
c = tConnector{}
|
||||
c2 := sqlz.ConnectorWith(c, nil)
|
||||
require.Equal(t, c, c2)
|
||||
|
||||
c = tConnector{}
|
||||
c2 = sqlz.ConnectorWith(c, fn)
|
||||
require.NotEqual(t, c, c2)
|
||||
|
||||
_, ok := c2.(io.Closer)
|
||||
require.False(t, ok, "shouldn't be an io.Closer")
|
||||
|
||||
conn, err := c2.Connect(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, conn)
|
||||
require.True(t, invoked)
|
||||
invoked = false // reset
|
||||
|
||||
// Test that ConnectorWith returns a connector that
|
||||
// implements io.Closer if the underlying connector
|
||||
// implements io.Closer.
|
||||
c = tConnectorCloser{}
|
||||
c2 = sqlz.ConnectorWith(c, fn)
|
||||
_, ok = c2.(io.Closer)
|
||||
require.True(t, ok, "should be an io.Closer")
|
||||
|
||||
conn, err = c2.Connect(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, conn)
|
||||
require.True(t, invoked)
|
||||
}
|
@ -65,3 +65,16 @@ const (
|
||||
TableTypeView = "view"
|
||||
TableTypeVirtual = "virtual"
|
||||
)
|
||||
|
||||
// RequireSingleConn returns nil if db is a type that guarantees a
|
||||
// single database connection. That is, RequireSingleConn returns an
|
||||
// error if db does not have type *sql.Conn or *sql.Tx.
|
||||
func RequireSingleConn(db DB) error {
|
||||
switch db.(type) {
|
||||
case *sql.Conn, *sql.Tx:
|
||||
default:
|
||||
return errz.Errorf("sql.Conn or sql.Tx required, but was %T", db)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -418,6 +418,8 @@ func LineCount(r io.Reader, skipEmpty bool) int {
|
||||
}
|
||||
|
||||
// TrimLen returns s but with a maximum length of maxLen.
|
||||
// This func is only tested with ASCII chars; results are not
|
||||
// guaranteed for multibyte runes.
|
||||
func TrimLen(s string, maxLen int) string {
|
||||
if len(s) <= maxLen {
|
||||
return s
|
||||
@ -426,6 +428,38 @@ func TrimLen(s string, maxLen int) string {
|
||||
return s[:maxLen]
|
||||
}
|
||||
|
||||
// TrimLenMiddle returns s but with a maximum length of maxLen,
|
||||
// with the middle of s replaced with "...". If maxLen is a small
|
||||
// number, the ellipsis may be shorter, e.g. a single char.
|
||||
// This func is only tested with ASCII chars; results are not
|
||||
// guaranteed for multibyte runes.
|
||||
func TrimLenMiddle(s string, maxLen int) string {
|
||||
length := len(s)
|
||||
if maxLen <= 0 {
|
||||
return ""
|
||||
}
|
||||
if length <= maxLen {
|
||||
return s
|
||||
}
|
||||
|
||||
switch maxLen {
|
||||
case 1:
|
||||
return s[0:1]
|
||||
case 2:
|
||||
return string(s[0]) + string(s[length-1])
|
||||
case 3:
|
||||
return string(s[0]) + "." + string(s[length-1])
|
||||
case 4:
|
||||
return string(s[0]) + ".." + string(s[length-1])
|
||||
case 5:
|
||||
return string(s[0]) + "..." + string(s[length-1])
|
||||
default:
|
||||
}
|
||||
|
||||
trimLen := ((maxLen + 1) / 2) - 2
|
||||
return s[:trimLen] + "..." + s[len(s)-trimLen:]
|
||||
}
|
||||
|
||||
// DoubleQuote double-quotes (and escapes) s.
|
||||
//
|
||||
// hello "world" --> "hello ""world"""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user