# Peg Parser New Statement

> Add a new SQL statement type to DuckDB's PEG parser. Use when the user asks to add, implement, or support parsing for a new SQL statement or syntax (e.g. CREATE TRIGGER, DROP TRIGGER, CREATE MATERIALIZED VIEW) in the PEG parser.

- **Type:** Skill
- **Install:** `agentstack add skill-mondaycom-duckdb-claude-peg-parser-new-statement`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [mondaycom](https://agentstack.voostack.com/s/mondaycom)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [mondaycom](https://github.com/mondaycom)
- **Source:** https://github.com/mondaycom/duckdb-claude/tree/main/skills/peg-parser-new-statement

## Install

```sh
agentstack add skill-mondaycom-duckdb-claude-peg-parser-new-statement
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Add a New Statement to the PEG Parser

Add `$ARGUMENTS` to DuckDB's PEG parser. The PEG parser lives in `extension/autocomplete/` and runs as a parser override extension before the legacy Postgres parser.

**Choose your path** based on the statement form:
- **CREATE-form** (e.g. `CREATE TRIGGER`, `CREATE MATERIALIZED VIEW`) → follow Shared Steps, then Part A
- **DROP-form** (e.g. `DROP TRIGGER`) → follow Shared Steps, then Part B

---

## Shared Step 1 — Add the catalog type

In `src/include/duckdb/common/enums/catalog_type.hpp`, add:

```cpp
XXX_ENTRY = ,
```

In `src/common/enums/catalog_type.cpp`, add to both `CatalogTypeToString` and `CatalogTypeFromString`.

---

## Shared Step 2 — Add enums (if needed)

Create `src/include/duckdb/common/enums/xxx_type.hpp` for any new enums specific to this statement, then regenerate:

```bash
python3 scripts/generate_enum_util.py
```

---

## Part A: CREATE-form statements

### A1 — Define the grammar

Create `extension/autocomplete/grammar/statements/create_xxx.gram`.

Wire the new statement into `CreateStatementVariation` in `create_table.gram`:

```
CreateStatementVariation  Copy() const override;
    string ToString() const override;
    DUCKDB_API void Serialize(Serializer &serializer) const override;
    DUCKDB_API static unique_ptr Deserialize(Deserializer &deserializer);
};

} // namespace duckdb
```

**Implementation**: `src/parser/parsed_data/create_xxx_info.cpp`
- Constructor: `CreateXxxInfo() : CreateInfo(CatalogType::XXX_ENTRY, INVALID_SCHEMA) {}`
- `Copy()`: call `CopyProperties(*result)` then copy each field
- `ToString()`: reconstruct the SQL string

If a field is a `unique_ptr` (not `SelectStatement`), it cannot be auto-serialized. Store the SQL text alongside it:

```cpp
string sql_body_text;          // serialized
unique_ptr sql_body; // runtime only
```

Add to `src/parser/parsed_data/CMakeLists.txt`:
```cmake
create_xxx_info.cpp
```

---

### A3 — Add serialization config

In `src/include/duckdb/storage/serialization/create_info.json`, add:

```json
{
  "class": "CreateXxxInfo",
  "base": "CreateInfo",
  "enum": "XXX_ENTRY",
  "includes": ["duckdb/parser/parsed_data/create_xxx_info.hpp"],
  "members": [
    { "id": 200, "name": "field_name", "type": "string" },
    { "id": 201, "name": "my_enum",    "type": "MyEnumType" },
    { "id": 202, "name": "my_bool",    "type": "bool" }
  ]
}
```

Supported types: `string`, `bool`, `int64_t`, `uint64_t`, `vector`, `unique_ptr`, any registered enum. `SQLStatement*` is **not** supported — use `string` instead.

```bash
python3 scripts/generate_serialization.py
```

---

### A4 — Write the transformer

Create `extension/autocomplete/transformer/transform_create_xxx.cpp`.

See the **Transformer patterns** section below for how to handle indexing, choices, optionals, lists, enums, and nested statements.

Add to `extension/autocomplete/transformer/CMakeLists.txt`:
```cmake
transform_create_xxx.cpp
```

---

### A5 — Register the transformer

In `extension/autocomplete/transformer/peg_transformer_factory.cpp`:

1. Add a `RegisterCreateXxx()` function and call it from the constructor (keep alphabetical order):
```cpp
void PEGTransformerFactory::RegisterCreateXxx() {
    REGISTER_TRANSFORM(TransformCreateXxxStmt);
    // ... all sub-rules
}
```
2. Add new enum mappings to `RegisterEnums()`.

In `extension/autocomplete/include/transformer/peg_transformer.hpp`:

1. Add `void RegisterCreateXxx();` with the other `RegisterCreate*` declarations.
2. Add a `static` declaration for each transform function.
3. If you have a custom intermediate struct, create it in `extension/autocomplete/include/ast/xxx_info.hpp` and include it from the header.

---

### A6 — Handle excluded rules

Rules used only as boolean flags (e.g. `ForEachRow  TransformDropXxxStmt(PEGTransformer &transformer, ParseResult &pr) {
    auto &list_pr = pr.Cast();
    // 'DROP' 'XXX' IfExists? QualifiedName
    //   [0]   [1]    [2]       [3]
    auto result = make_uniq();
    result->type = CatalogType::XXX_ENTRY;
    result->if_exists = list_pr.Child(2).HasResult();
    auto qname = transformer.Transform(list_pr.Child(3));
    result->name = qname.name;
    result->schema = qname.schema;
    return result;
}
```

See the **Transformer patterns** section below for handling other grammar constructs.

Add to `extension/autocomplete/transformer/CMakeLists.txt`:
```cmake
transform_drop_xxx.cpp
```

---

### B3 — Register the transformer

In `extension/autocomplete/transformer/peg_transformer_factory.cpp`:

1. Add a `RegisterDropXxx()` function and call it from the constructor (keep alphabetical order):
```cpp
void PEGTransformerFactory::RegisterDropXxx() {
    REGISTER_TRANSFORM(TransformDropXxxStmt);
    // ... all sub-rules
}
```

In `extension/autocomplete/include/transformer/peg_transformer.hpp`:

1. Add `void RegisterDropXxx();` with the other `RegisterDrop*` declarations.
2. Add a `static` declaration for each transform function.

---

### B4 — Handle excluded rules

Same as A6 — add boolean-flag-only rules to `EXCLUDED_RULES` in `scripts/generate_peg_transformer.py`.

---

### B5 — Add binder stub

In `src/planner/binder/statement/bind_drop.cpp`, add before the `default` throw:

```cpp
case CatalogType::XXX_ENTRY:
    throw NotImplementedException("DROP XXX is not yet supported");
```

---

### B6 — Write tests

Create `test/sql/xxx/drop_xxx_parse.test`. Required boilerplate:

```sql
require autocomplete

statement ok
call enable_peg_parser();
```

Syntax error tests must match a specific error message (see A8 for the rationale and pattern).

To find the exact error message:
```bash
echo "call enable_peg_parser(); DROP XXX bad syntax;" | build/debug/duckdb
```

---

### B7 — Verify coverage and format

```bash
# All rules must be FOUND, ENUM, or EXCLUDED — no MISSING
python3 scripts/generate_peg_transformer.py | grep -A30 "File: drop_xxx"

# Reformat changed files
make format-main
```

---

## Grammar reference

Key grammar syntax:
- `'KEYWORD'` — case-insensitive literal
- `Rule1 / Rule2` — ordered choice (first match wins)
- `Rule?` — optional, `Rule*` / `Rule+` — repeat
- `List(D)` — comma-separated list (defined in `common.gram`)
- `Parens(D)` — `D` wrapped in parentheses
- `Statement` — any full DuckDB SQL statement
- `QualifiedName` — `[catalog.]schema.name` identifier
- `IfNotExists` — already defined, no transformer needed
- `IfExists` — already defined, no transformer needed

**Critical**: never use `List(...)` directly inline in a rule — it has no transformer and will crash at runtime. Always wrap it in a named rule:

```
# WRONG:
MyRule (list_pr.Child(0).result);
```

**Optionals** (`?`): use `OptionalParseResult::HasResult()`:
```cpp
bool if_not_exists = list_pr.Child(1).HasResult();
```

**Lists**: use `ExtractParseResultsFromList` then loop:
```cpp
auto items = ExtractParseResultsFromList(list_pr.Child(0));
for (auto &item : items) {
    result.push_back(transformer.Transform(item));
}
```

**Enums**: register in `RegisterEnums()`, then use `TransformEnum`:
```cpp
// registration:
RegisterEnum("RuleName", MyEnum::VALUE);
// transformer:
return transformer.TransformEnum(list_pr.Child(0).result);
```

**Nested statement**:
```cpp
auto body = transformer.Transform>(list_pr.Child(N));
```

---

## Reference implementations

- **CreateView** — simplest CREATE-form: `create_view.gram` + `transform_create_view.cpp`
- **CreateSequence** — enum options + repeated sub-rules: `create_sequence.gram` + `transform_create_sequence.cpp`
- **CreateTrigger** — choices, column list, nested statement body: `create_trigger.gram` + `transform_create_trigger.cpp`

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [mondaycom](https://github.com/mondaycom)
- **Source:** [mondaycom/duckdb-claude](https://github.com/mondaycom/duckdb-claude)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-mondaycom-duckdb-claude-peg-parser-new-statement
- Seller: https://agentstack.voostack.com/s/mondaycom
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
