Skip to content

Commit eeb064f

Browse files
authored
Merge pull request #28 from future-architect/merge_upstream
Merge upstream
2 parents 9d0218f + ed6eed4 commit eeb064f

File tree

89 files changed

+58413
-7014
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+58413
-7014
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
name: Deploy GitHub Pages for branches
3+
4+
on:
5+
push:
6+
branches:
7+
- main
8+
9+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
10+
permissions:
11+
contents: read
12+
pages: write
13+
id-token: write
14+
15+
jobs:
16+
build:
17+
if: github.repository == 'tanzaku/postgresql-cst-parser'
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: "22"
28+
29+
- name: Install Rust toolchain
30+
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
31+
32+
- name: Add cargo to PATH
33+
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
34+
35+
- name: Install wasm-pack
36+
run: cargo install wasm-pack
37+
38+
- name: Build
39+
run: bash ./update-gh-page.sh
40+
41+
- name: Upload artifact
42+
uses: actions/upload-pages-artifact@v3
43+
with:
44+
path: ./docs
45+
46+
deploy:
47+
if: github.repository == 'tanzaku/postgresql-cst-parser'
48+
needs: build
49+
environment:
50+
name: github-pages
51+
url: ${{ steps.deployment.outputs.page_url }}
52+
runs-on: ubuntu-latest
53+
steps:
54+
- name: Deploy to GitHub Pages
55+
if: ${{ !env.ACT }}
56+
id: deployment
57+
uses: actions/deploy-pages@v4

.github/workflows/rust.yml

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,33 @@ name: Rust
22

33
on:
44
push:
5-
branches: [ "main" ]
5+
branches: ["main"]
66
pull_request:
7-
branches: [ "main" ]
87

98
env:
109
CARGO_TERM_COLOR: always
1110

1211
jobs:
1312
build:
14-
1513
runs-on: ubuntu-latest
1614

1715
steps:
18-
- uses: actions/checkout@v4
19-
- name: Build
20-
run: cargo build --verbose
21-
- name: Run tests
22-
run: cargo test --verbose
23-
- name: clippy
24-
uses: actions-rs/clippy-check@v1
25-
with:
26-
token: ${{ secrets.GITHUB_TOKEN }}
16+
- uses: actions/checkout@v4
17+
- name: Build
18+
run: cargo build --verbose
19+
- name: Run tests
20+
run: cargo test --verbose
21+
- name: Run tests with features
22+
run: cargo test --verbose --features regex-match
23+
- name: Run benchmarks
24+
run: cargo bench
25+
- name: Run benchmarks with features
26+
run: cargo bench --features regex-match
27+
- name: Clippy (automata)
28+
run: cargo clippy -p automata -- -D warnings
29+
- name: Clippy (lexer-generator)
30+
run: cargo clippy -p lexer-generator -- -D warnings
31+
- name: Clippy (parser-generator)
32+
run: cargo clippy -p parser-generator -- -D warnings
33+
- name: Clippy (postgresql-cst-parser)
34+
run: cargo clippy -p postgresql-cst-parser -- -D warnings

CHANGELOG

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# CHANGELOG
2+
3+
## [0.2.0] - 2025-04-04
4+
5+
### Improvements
6+
- Significant performance enhancement
7+
8+
## [0.1.0] - 2025-03-21
9+
10+
### Added
11+
- Initial release
12+
- PostgreSQL 17 syntax support
13+
- CST generation functionality following [gram.y](https://github.com/postgres/postgres/blob/REL_17_0/src/backend/parser/gram.y) structure
14+
- Pure Rust implementation enabling WebAssembly compilation via wasm-bindgen

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
resolver = "2"
33

44
members = [
5+
"crates/automata",
56
"crates/lexer-generator",
67
"crates/parser-generator",
78
"crates/postgresql-cst-parser",
@@ -11,7 +12,7 @@ members = [
1112
default-members = ["crates/postgresql-cst-parser"]
1213

1314
[workspace.package]
14-
exclude = ["crates/lexer-generator", "crates/parser-generator", "crates/postgresql-cst-parser-wasm"]
15+
exclude = ["crates/automata", "crates/lexer-generator", "crates/parser-generator", "crates/postgresql-cst-parser-wasm"]
1516

1617
[profile.release.package.postgresql-cst-parser-wasm]
1718
opt-level = "s"

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) [year] [fullname]
3+
Copyright (c) 2024 tanzaku
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
2+
3+
.PHONY: clean prepare-source prepare-original-source make-patch
4+
5+
prepare-source: copy-from-original-source
6+
patch -p1 < $(ROOT_DIR)/patches/patch_scan.patch
7+
8+
prepare-original-source: clean
9+
mkdir -p ./tmp
10+
cd ./tmp; git clone -b 17-6.0.0 --depth=1 [email protected]:pganalyze/libpg_query.git
11+
sed -i 's/sed -i ""/sed -i/g' ./tmp/libpg_query/Makefile
12+
cd ./tmp/libpg_query; make $(ROOT_DIR)tmp/libpg_query/tmp/postgres
13+
mkdir -p ./crates/lexer-generator/resources
14+
mkdir -p ./crates/parser-generator/resources
15+
16+
copy-from-original-source: prepare-original-source
17+
cp $(ROOT_DIR)tmp/libpg_query/tmp/postgres/src/backend/parser/scan.l $(ROOT_DIR)crates/lexer-generator/resources
18+
cp $(ROOT_DIR)tmp/libpg_query/tmp/postgres/src/include/parser/kwlist.h $(ROOT_DIR)crates/lexer-generator/resources
19+
cp $(ROOT_DIR)tmp/libpg_query/tmp/postgres/src/backend/parser/parser.c $(ROOT_DIR)crates/lexer-generator/resources
20+
cp $(ROOT_DIR)tmp/libpg_query/tmp/postgres/src/backend/parser/gram.y $(ROOT_DIR)crates/parser-generator/resources
21+
22+
make-patch: prepare-original-source
23+
diff -u ./tmp/libpg_query/tmp/postgres/src/backend/parser/scan.l ./crates/lexer-generator/resources/scan.l > ./patches/patch_scan.patch || true
24+
25+
clean:
26+
-@ rm -rf ./tmp

README.ja.md

Lines changed: 137 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,158 @@
11
# postgresql-cst-parser
22

3+
[![Crates.io](https://img.shields.io/crates/v/postgresql-cst-parser.svg)](https://crates.io/crates/postgresql-cst-parser)
4+
5+
**注意:このパーサーはPostgreSQLの公式プロジェクトではなく、独立した非公式ツールです。**
6+
37
## 概要
48

5-
`postgresql-cst-parser`は、Pure Rust で開発された PostgreSQL 専用の Lossless Syntax Tree(CST)パーサーです。この文書では、パーサーの特徴、動機、使用方法、および実装の詳細について説明します。
9+
`postgresql-cst-parser`は、Pure Rustで開発されたPostgreSQL専用の具象構文木(CST)パーサーです。このドキュメントでは、パーサーの機能、開発のモチベーション、使用方法、および実装の詳細について説明します。
610

711
## 主な特徴
812

9-
- **自動生成された CST パーサー**: PostgreSQL の文法から自動的に生成されるため、幅広い文法に対応。
10-
- **部分的な制限**: スキャナーの一部の実装が不完全であるため、全ての文法に対応しているわけではありません。
13+
- **PostgreSQL 17対応**: 最新のPostgreSQL 17の構文をサポートしています。
14+
- **構造化されたCST出力**: 生成されるCSTは、PostgreSQLの[gram.y](https://github.com/postgres/postgres/blob/REL_17_0/src/backend/parser/gram.y)ファイルで定義された構造に厳密に従います。
15+
- **`cstree`の利用**: 構文木の構築に`cstree`クレートを使用しています。
16+
- **wasm-bindgenとの併用**: Pure Rust で書かれているため、wasm-bindgen と併用できます。
17+
- **PL/pgSQL**: 現在はサポートされていません。
1118

12-
## 開発の動機
19+
## 開発のモチベーション
1320

14-
1. Rust から利用でき、広範な文法をサポートする PostgreSQL の CST パーサーが不足している。
15-
2. [pg_query.rs](https://github.com/pganalyze/pg_query.rs)はとても素晴らしいライブラリだが、CST は構築できず WebAssembly(wasm)でビルドできない。
21+
Rustから使用可能で、すべての構文をサポートし、(Pure Rust で書かれており) wasm-bindgen が利用可能なライブラリが必要だったため開発しました。
1622

1723
## 使用方法
1824

19-
以下のコード例のようにして使用します。
25+
以下のように使用することができます:
2026

2127
```rust
22-
let resolved_root = postgresql_cst_parser::parse("SELECT 1;");
23-
dbg!(resolved_root);
28+
use postgresql_cst_parser::{parse, syntax_kind::SyntaxKind};
29+
30+
fn main() {
31+
// Parse SQL query and get the syntax tree
32+
let sql = "SELECT tbl.a as a, tbl.b from TBL tbl WHERE tbl.a > 0;";
33+
let root = parse(sql).unwrap();
34+
35+
// Example 1: Extract all column references from the query
36+
let column_refs: Vec<String> = root
37+
.descendants()
38+
.filter(|node| node.kind() == SyntaxKind::columnref)
39+
.map(|node| node.text().to_string())
40+
.collect();
41+
42+
println!("Column references: {:?}", column_refs); // ["tbl.a", "tbl.b", "tbl.a"]
43+
44+
// Example 2: Find the WHERE condition
45+
if let Some(where_clause) = root
46+
.descendants()
47+
.find(|node| node.kind() == SyntaxKind::where_clause)
48+
{
49+
println!("WHERE condition: {}", where_clause.text());
50+
}
51+
52+
// Example 3: Get the selected table name
53+
if let Some(relation_expr) = root
54+
.descendants()
55+
.find(|node| node.kind() == SyntaxKind::relation_expr)
56+
{
57+
if let Some(name_node) = relation_expr
58+
.descendants()
59+
.find(|node| node.kind() == SyntaxKind::ColId)
60+
{
61+
println!("Table name: {}", name_node.text());
62+
}
63+
}
64+
65+
// Example 4: Parse complex SQL and extract specific nodes
66+
let complex_sql = "WITH data AS (SELECT id, value FROM source WHERE value > 10)
67+
SELECT d.id, d.value, COUNT(*) OVER (PARTITION BY d.id)
68+
FROM data d JOIN other o ON d.id = o.id
69+
ORDER BY d.value DESC LIMIT 10;";
70+
71+
let complex_root = parse(complex_sql).unwrap();
72+
73+
// Extract CTEs (Common Table Expressions)
74+
let ctes: Vec<_> = complex_root
75+
.descendants()
76+
.filter(|node| node.kind() == SyntaxKind::common_table_expr)
77+
.collect();
78+
79+
// Extract window functions
80+
let window_funcs: Vec<_> = complex_root
81+
.descendants()
82+
.filter(|node| node.kind() == SyntaxKind::over_clause)
83+
.collect();
84+
85+
println!("Number of CTEs: {}", ctes.len());
86+
println!("Number of window functions: {}", window_funcs.len());
87+
}
88+
```
89+
90+
生成される構文木の例:
91+
92+
```sql
93+
SELECT tbl.a as a from TBL tbl;
2494
```
2595

26-
さらに、このパーサーを実際に体験してみたい場合は、[こちら](https://tanzaku.github.io/postgresql-cst-parser/)でオンラインで直接試すことができます。実際のコードを入力し、パーサーがどのように動作するかを確認してみましょう。
96+
```
97+
98+
99+
100+
101+
102+
103+
104+
105+
106+
107+
108+
109+
110+
111+
112+
113+
114+
115+
116+
117+
118+
119+
120+
121+
122+
123+
124+
125+
126+
127+
128+
129+
130+
131+
132+
133+
134+
135+
136+
137+
138+
139+
140+
141+
142+
143+
```
144+
145+
## オンラインデモ
146+
147+
[こちら](https://tanzaku.github.io/postgresql-cst-parser/)でパーサーを直接試すことができます。SQLクエリを入力して、生成された構文木をリアルタイムで確認できます。
27148

28-
## 実装方法
149+
## 実装
29150

30-
実装には、PostgreSQL の [scan.l](https://github.com/postgres/postgres/blob/REL_16_STABLE/src/backend/parser/scan.l)[gram.y](https://github.com/postgres/postgres/blob/REL_16_STABLE/src/backend/parser/gram.y) に対する [libpg_query の patch](https://github.com/pganalyze/libpg_query/tree/16-latest/patches)を適用したものを使用しています`scan.l`Rust 用に書き換えられ`scan.l``gram.y` を基にして構文解析表を作成し、パーサーを構築しています。
151+
この実装は、PostgreSQLの[scan.l](https://github.com/postgres/postgres/blob/REL_17_0/src/backend/parser/scan.l)[gram.y](https://github.com/postgres/postgres/blob/REL_17_0/src/backend/parser/gram.y)に対して[libpg_query](https://github.com/pganalyze/libpg_query/tree/17-6.0.0/patches)のパッチを適用したファイルを使用しています`scan.l`はさらに Rust 用に書き直したうえで`scan.l``gram.y`に基づいて構文解析テーブルを作成し、パーサーを構築しています。
31152

32153
## ライセンス
33154

34-
`kwlist.h`, `scan.l`, `gram.y` は PostgreSQL License です。
35-
その他のファイルは MIT License の下で公開されています。
155+
- `kwlist.h``parser.c``scan.l``gram.y`はPostgreSQLライセンスの下にあります。
156+
- `lexer_ported.rs``generated.rs`はPostgreSQLから移植されたコードを含むため、移植部分はPostgreSQLライセンスの下にあります。
157+
- このプロジェクトでは、`scan.l``gram.y`に対して[libpg_query](https://github.com/pganalyze/libpg_query)のパッチを当てていますが、パッチそのものはこのリポジトリには含まれていません。
158+
- その他のファイルはMITライセンスの下で公開されています。

0 commit comments

Comments
 (0)