A high-performance .NET library for parsing PostgreSQL queries using the official PostgreSQL parser via libpg_query.
- Query Validation & Utilities: Validate SQL and extract common query metadata
- Query Normalization: Standardize queries for comparison
- Query Fingerprinting: Generate unique identifiers for query patterns
- Query Tokenization: Analyze SQL tokens and keywords
- Statement Splitting: Split multi-statement SQL into individual statements
- PL/pgSQL Support: Parse PL/pgSQL functions and procedures
- Batch Processing: Process multiple queries efficiently
- Parse SQL to AST: Convert PostgreSQL queries to JSON or Protobuf AST
- AST Deparsing: Convert JSON or Protobuf ASTs back to SQL
- Async Operations: Full async/await support
- Cross-Platform: Works on Windows, Linux (macOS coming soon!)
Install Npgquery from NuGet with the .NET CLI:
dotnet add package NpgqueryOr with the NuGet Package Manager Console:
Install-Package NpgqueryThe package includes the native libpg_query runtime assets for supported platforms. Application users should not install or build native parser libraries separately.
Then import the namespace in your application:
using Npgquery;For simple one-off operations, use the static quick methods to parse PostgreSQL SQL into an abstract syntax tree (AST):
var result = Parser.QuickParse("SELECT * FROM users WHERE id = 1");
if (result.IsSuccess)
{
Console.WriteLine(result.ParseTree?.RootElement.ToString());
}
else
{
Console.WriteLine(result.Error);
}The quick methods are available for the core capabilities:
var parseResult = Parser.QuickParse("SELECT now()");
var normalized = Parser.QuickNormalize("SELECT * FROM users WHERE id = 42");
var fingerprint = Parser.QuickFingerprint("SELECT * FROM users WHERE id = 42");
var split = Parser.QuickSplit("SELECT 1; SELECT 2;");
var scan = Parser.QuickScan("SELECT COUNT(*) FROM users");For repeated parsing calls, advanced operations, or more granular lifecycle management, instantiate Parser directly and dispose it when finished:
using var parser = new Parser();
var first = parser.Parse("SELECT * FROM users WHERE id = 1");
var second = parser.Normalize("SELECT * FROM users WHERE id = 2");
var third = parser.Fingerprint("SELECT * FROM users WHERE id = 3");Normalize and fingerprint queries so structurally similar statements can be grouped even when literal values differ:
var normalized = Parser.QuickNormalize("SELECT * FROM users WHERE id = 42");
var first = Parser.QuickFingerprint("SELECT * FROM users WHERE id = 1");
var second = Parser.QuickFingerprint("SELECT * FROM users WHERE id = 2");
Console.WriteLine(normalized.NormalizedQuery);
Console.WriteLine(first.Fingerprint == second.Fingerprint); // True for the same query shapeSplit multi-statement SQL and inspect individual statements:
var split = Parser.QuickSplit("SELECT 1; INSERT INTO audit_log(action) VALUES ('login');");
foreach (var statement in split.Statements ?? Array.Empty<SqlStatement>())
{
Console.WriteLine(statement.Statement);
}Tokenize SQL for lightweight analysis of keywords, identifiers, and token positions:
var scan = Parser.QuickScan("SELECT COUNT(*) FROM users");
foreach (var token in scan.Tokens ?? Array.Empty<SqlToken>())
{
Console.WriteLine($"{token.TokenKind}: {token.Text}");
}Use async helpers when integrating with asynchronous application code:
var asyncResult = await ParserAsync.QuickParseAsync("SELECT * FROM orders WHERE created_at > now() - interval '1 day'");
Console.WriteLine(asyncResult.IsSuccess);Npgquery also exposes protobuf parsing/deparsing and PL/pgSQL parsing for advanced scenarios that need a managed representation of PostgreSQL parser output.
Visit the GitHub repository for complete documentation, examples, and API reference.
MIT License - see LICENSE file for details.
This library is built on libpg_query, which embeds the official PostgreSQL parser.