Search by

k-kinzal / sql-parser

kinzal

Lossless LALR(1) SQL parsers for MySQL, PostgreSQL, and SQLite, built from the official grammars

dev-main 2026-09-28 02:33 UTC

This package is auto-updated.

Last update: 2026-09-28 02:33:19 UTC


README

Packagist Downloads PHP Version License: MIT Docs Ask DeepWiki

SQL Parser is a set of LALR(1) parsers for MySQL, PostgreSQL, and SQLite written in PHP. Each parser is generated from the official grammar of a server version (sql_yacc.yy for MySQL, gram.y for PostgreSQL, and parse.y for SQLite), and its lexer is a port of the server's own scanner, so text is tokenized and parsed the way the server does it. The syntax tree names the nonterminals of the upstream grammar, and parsing is lossless: a tree writes back the text it was parsed from, byte for byte, including comments and whitespace.

Requirements

  • PHP 8.1+ with the zlib extension

Support Syntax

The following grammar versions are bundled. Pass the version tag to the parser; omitting it uses the default for that database.

MySQL

Version Version tag Default
5.6.51 mysql-5.6.51
5.7.44 mysql-5.7.44
8.0.44 mysql-8.0.44
8.1.0 mysql-8.1.0
8.2.0 mysql-8.2.0
8.3.0 mysql-8.3.0
8.4.7 mysql-8.4.7 Yes
9.0.1 mysql-9.0.1
9.1.0 mysql-9.1.0

PostgreSQL

Version Version tag Default
16.6 pg-16.6
17.2 pg-17.2 Yes

SQLite

Version Version tag Default
3.47.2 sqlite-3.47.2 Yes

Installation

composer require k-kinzal/sql-parser

Usage

use SqlParser\MySql\MySqlParser;

$parser = new MySqlParser('mysql-8.4.7');
$sql = 'SELECT id, name FROM users u WHERE u.id = ? ORDER BY id LIMIT 10';
$tree = $parser->parse($sql);

$tree->name;                                     // 'start_entry', the grammar's start symbol
$tree->find('where_clause')[0]->text($sql);      // 'WHERE u.id = ?'
$tree->find('table_reference')[0]->text($sql);   // 'users u'
$tree->toString();                               // the statement again, byte for byte

A MySQL parser reads text under a sql_mode, since ANSI_QUOTES, PIPES_AS_CONCAT, HIGH_NOT_PRECEDENCE, NO_BACKSLASH_ESCAPES and IGNORE_SPACE change how text is tokenized. Pass the value a session reports:

use SqlParser\MySql\MySqlParser;
use SqlParser\MySql\SqlMode;

$parser = new MySqlParser('mysql-8.4.7', SqlMode::fromString('ANSI_QUOTES,NO_BACKSLASH_ESCAPES'));
$parser->tokenize('SELECT "x"')[1]->name;        // 'IDENT_QUOTED'

A named placeholder such as :id is not in the languages of MySQL and PostgreSQL, which read only their own markers. Their parsers read :name as a parameter under ParameterSyntax::Named, as a dialect extension; SQLite reads it natively.

use SqlParser\Lexer\ParameterSyntax;
use SqlParser\PostgreSql\PostgreSqlParser;

$parser = new PostgreSqlParser(parameters: ParameterSyntax::Named);
$parser->parse('SELECT id FROM users WHERE id = :id');

License

MIT License. See LICENSE for details.