Skip to content

Quick Start

Get up and running with General SQL Parser in just a few minutes! This guide walks you through installation, basic setup, and your first SQL parsing example — for both the Java and the .NET / C# edition.

Pick your language once

Every example below is a Java / C# tab pair. Select one and every tab on the page switches with it, and the choice follows you to the other pages on this site.

The two editions are API-compatible by design: the same class names (TGSqlParser, TSelectSqlStatement, TTable), the same vendor enum, the same AST. Java getters generally become C# properties — the full mapping table is on the .NET / C# overview.

Prerequisites

  • Java 8 or higher (Java 11+ recommended)
  • Maven or Gradle for dependency management
  • IDE (IntelliJ IDEA, Eclipse, or VS Code recommended)
  • A .NET SDK. Any currently supported version works. On Ubuntu 24.04: sudo apt-get install -y dotnet-sdk-10.0; on Windows and macOS use the installer from Microsoft. Confirm with dotnet --info.
  • Nothing else. No IDE is required — the commands below are the whole toolchain. If you prefer one, Visual Studio, Rider, and VS Code with the C# Dev Kit all work.

The package multi-targets net10.0 and netstandard2.0, so it also runs on .NET Framework 4.6.2+ — see Framework compatibility.

Installation

Both editions install from a public package repository. There is nothing to download, install, or configure locally, and no license file to place.

Add the dependency

General SQL Parser is published to Gudu Software's public Maven repository at https://www.sqlparser.com/maven/. Add the repository and a single dependency to your build.

A complete, minimal pom.xml — copy it into an empty directory and it builds on Java 8 through the latest LTS:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>gsp-quickstart</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <properties>
        <!-- The parser JAR is Java 8 bytecode. Pin the compiler level so a
             modern JDK does not fall back to an unsupported default. -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <repositories>
        <repository>
            <id>gudu-public-releases</id>
            <url>https://www.sqlparser.com/maven/</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.gudusoft</groupId>
            <artifactId>gsqlparser</artifactId>
            <version>4.1.9</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <mainClass>QuickStartExample</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Create your class at src/main/java/QuickStartExample.java (see Your First SQL Parser below), then compile and run in one step:

1
mvn clean compile exec:java

That's it — Maven downloads gsqlparser-4.1.9.jar from https://www.sqlparser.com/maven/com/gudusoft/gsqlparser/4.1.9/ into your local ~/.m2/ cache on first build.

Data lineage on Java 11+

The DataFlowAnalyzer (data-lineage) APIs generate XML through JAXB, which was removed from the JDK in Java 11. As of 4.1.6 the published POM declares the JAXB runtime, so lineage works on Java 11+ with only the GSP dependency — no extra setup. On Java 8 the JDK-bundled JAXB is used.

A complete build.gradle.kts (Kotlin DSL). The application plugin supplies the implementation configuration and a run task:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
plugins {
    application
}

repositories {
    // Gradle has no built-in repositories: mavenCentral() is required so
    // GSP's transitive JAXB dependencies resolve (they live on Maven Central,
    // not the Gudu repository).
    mavenCentral()
    maven { url = uri("https://www.sqlparser.com/maven/") }
}

dependencies {
    implementation("com.gudusoft:gsqlparser:4.1.9")
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

application {
    mainClass.set("QuickStartExample")
}

Create your class at src/main/java/QuickStartExample.java (see Your First SQL Parser below), then build and run with the installed Gradle (listed in the prerequisites):

1
gradle clean run

Using the Gradle wrapper

An empty project has no gradlew wrapper script yet. Generate one first with gradle wrapper, after which you can use ./gradlew clean run (gradlew.bat clean run on Windows) for a version-pinned, reproducible build.

The library is published to NuGet as gudusoft.gsqlparser.

Three commands take you from an empty directory to a working parser:

1
2
3
dotnet new console -o GspQuickStart
cd GspQuickStart
dotnet add package gudusoft.gsqlparser

Note the deliberate absence of a version number: dotnet add package resolves the newest published release and writes it into your project file, so this command stays correct as new versions ship.

Then paste the program from Your First SQL Parser into Program.cs and run it with dotnet run.

A complete, self-contained project file. Save it in an empty directory next to a Program.cs and run dotnet run:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <!-- Any supported TFM works; net8.0, net9.0 and net10.0 are all fine. -->
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <!-- "4.*" tracks the newest 4.x release automatically.
         Pin an exact version instead for reproducible builds. -->
    <PackageReference Include="gudusoft.gsqlparser" Version="4.*" />
  </ItemGroup>

</Project>

In the Visual Studio Package Manager console:

1
Install-Package gudusoft.gsqlparser

License setup: there is none. No license key to embed, no SetLicense call, no activation step — add the package and start parsing.

The public package is the trial build

The Maven artifact is the trial edition

The artifact at com.gudusoft:gsqlparser is the trial edition of General SQL Parser. It carries every dialect and covers every example on this page, with two limits that apply to the Java trial exactly as they do to the .NET one:

  • SQL over the 10,000 size limit is refused before parsing. parse() returns -1 and getErrormessage() reads, verbatim:
1
trial version can only process query with size of at most 10000 bytes, and expired after 90 days after first usage.
  • The build stops working 90 days after first use.

The boundary is exact: 10,000 passes, 10,001 is refused. What gets measured depends on how you hand over the SQL — a String (sqltext) is measured in characters, ignoring leading whitespace, while a file or stream is measured in raw bytes. For ASCII SQL the two agree; for non-ASCII text a file can be refused at fewer than 10,000 characters.

A -1 return is never a complaint about your SQL — it means the input was too long, or the trial expired. Handle it separately from a syntax error:

1
2
3
4
int ret = parser.parse();
if (ret == -1 && parser.getErrormessage().contains("trial version")) {
    System.err.println("Script exceeds the trial limit: " + parser.getErrormessage());
}

Evaluating long stored procedures or large scripts will hit this quickly, so request an unrestricted evaluation build up front rather than mid-test: send us a SQL sample or email info@sqlparser.com.

Trial versions differ from commercial ones

Commercial builds may carry newer fixes and use a more specific four-part version. See the licensing FAQ before production use. The public Maven version is a three-part number (for example 4.1.9) and does not necessarily match the four-part product version shown in the release notes.

The three distinct return values

parse() returns 0 on success, a positive count on syntax errors, and -1 when the trial limit refused the input. Treat -1 as "input too long or trial expired", not as "invalid SQL".

The NuGet package is the trial edition

gudusoft.gsqlparser on nuget.org is the trial build (the package title says so). It carries every dialect and behaves exactly like the full edition, with two limits: SQL longer than 10,000 characters is refused before parsing, and the build stops working 90 days after first use. parse() returns -1 and Errormessage reads, verbatim:

1
trial version can only process query with size less than 10000 characters, and expired after 90 days after first usage.

The boundary is exact, and worth knowing precisely because it sits one character off from what the message says: a sqltext of 10,000 characters parses fine, and 10,001 is refused. A -1 return is therefore never a complaint about your SQL — it means the input was too long. Handle it separately from a syntax error:

1
2
3
int ret = parser.parse();
if (ret == -1 && parser.Errormessage.Contains("trial version"))
    Console.Error.WriteLine("Script exceeds the 10,000-character trial limit.");

For unrestricted parsing use the full edition. See the licensing FAQ for editions and pricing.

The three distinct return values

parse() returns 0 on success, a positive count on syntax errors, and -1 when the trial size limit refused the input. Treat -1 as "input too long", not as "invalid SQL".

Running your program

The complete pom.xml above already includes the exec-maven-plugin, so once you've created QuickStartExample.java you can compile and run in one command:

1
mvn clean compile exec:java

To run a different class, change the plugin's <mainClass> (or override it on the command line with -Dexec.mainClass=YourClass).

1
dotnet run

That is the whole build-and-run step; the SDK restores, compiles, and executes.

Checking which version you have

Releases can land days apart, so this page does not name a current version in its prose. Ask the tooling instead.

Latest version

You can always check the latest published version by viewing maven-metadata.xml. Maven coordinates are write-once — once a version is published it never changes, so it's safe to pin any specific release.

1
2
3
dotnet list package              # which version my project resolved
dotnet list package --outdated   # whether a newer release exists
dotnet add package gudusoft.gsqlparser   # move to the newest release

dotnet list package --outdated prints a Requested / Resolved / Latest table, the fastest way to see whether you are behind. Choose your Version attribute to match how you want updates:

Version value Behaviour Use when
omitted (dotnet add package) Pins the newest version at the time you ran the command Default. Reproducible, and you upgrade deliberately.
4.* Floats to the newest 4.x on every restore You want fixes automatically, without risking a major-version jump.
* Floats to the newest version, including future major versions Rarely. A future 5.0 with breaking changes would land silently.
exact (4.1.0.7) Exact pin CI, air-gapped feeds, anywhere restore must be deterministic.

The assembly carries no version metadata

Do not try to read the version at runtime — the shipped DLL reports an AssemblyVersion of 0.0.0.0 and has no AssemblyInformationalVersion, so reflection tells you nothing. dotnet list package is the reliable answer.

Framework compatibility

The parser JAR is Java 8 bytecode, so it runs on Java 8 through the latest LTS. Pin maven.compiler.source/target to 1.8 as the pom.xml above does, so a modern JDK does not fall back to an unsupported default.

The package ships two builds and NuGet picks the right one for your project:

Your target Assembly used Extra dependencies
net10.0 lib/net10.0/ none
net8.0, net9.0, netstandard2.0 libraries lib/netstandard2.0/ System.Text.Json 8.0.5
.NET Framework 4.6.2+ lib/netstandard2.0/ System.Text.Json 8.0.5

On .NET Framework the real floor is 4.6.2, not 4.6.1

netstandard2.0 itself is consumable from .NET Framework 4.6.1, but the netstandard2.0 build depends on System.Text.Json 8.0.5, whose lowest .NET Framework asset is net462. Targeting net461 leaves that dependency unresolved. Use net462 or newer.

A netstandard2.0 class library referencing the package builds with zero warnings — there is no NU1701 fallback noise, because the package genuinely targets it.

Offline / air-gapped installs

If your build environment cannot reach the internet, you must transfer the complete dependency closure — not just the GSP JAR. Since 4.1.6 declares JAXB (which lives on Maven Central), installing only the GSP JAR and POM is not enough: Maven would still try to fetch jakarta.xml.bind-api, jaxb-runtime, and the build/exec plugins from a remote repository.

The reliable approach is to build a portable local repository on a connected machine and transfer it whole. Prime it by running the actual build commands once — this captures the exact plugin + dependency closure the build uses. (dependency:go-offline is not sufficient here: it misses some default-lifecycle plugin dependencies and the build still fails offline.)

On a machine with internet access — using the complete pom.xml and QuickStartExample.java from the sections above:

1
2
3
4
5
# Prime a self-contained repo by running the real build once
mvn -Dmaven.repo.local="$PWD/offline-m2" clean compile exec:java

# Confirm it is truly self-contained by re-running with networking off (-o)
mvn -o -Dmaven.repo.local="$PWD/offline-m2" clean compile exec:java

Transfer the project directory and the offline-m2/ folder to the air-gapped host, then run the same offline command there:

1
mvn -o -Dmaven.repo.local="$PWD/offline-m2" clean compile exec:java

Verifying artifact integrity

The published JAR checksum can be checked against the download:

1
2
3
BASE=https://www.sqlparser.com/maven/com/gudusoft/gsqlparser/4.1.9
curl -sO $BASE/gsqlparser-4.1.9.jar
echo "$(curl -s $BASE/gsqlparser-4.1.9.jar.sha1)  gsqlparser-4.1.9.jar" | sha1sum -c -

Releases published after 2026-07-31 also carry a CycloneDX SBOM next to the JAR, named gsqlparser-<version>-cyclonedx.json, for security review and dependency scanners. It lists the complete dependency closure a consumer resolves — the parser itself plus the JAXB chain, with licenses and digests — and carries the JAR's own SHA-256, so the document can be tied to the file you downloaded. Versions up to and including 4.1.9 predate it.

Transfer a folder feed. The GSP package has no dependencies on net10.0, so for a modern TFM the feed is a single 6.7 MB .nupkg. (Targeting netstandard2.0 or .NET Framework adds System.Text.Json and its transitive closure — restore on the connected machine with the same TFM you will build with, so the feed captures everything.)

On a machine with internet access, pin an exact version first: a floating 4.* cannot resolve against a feed that will never receive updates.

1
2
3
4
5
dotnet restore --packages ./offline-packages

# Flatten every .nupkg into one folder; this is what you transfer.
mkdir -p offline-feed
find ./offline-packages -name '*.nupkg' -exec cp {} offline-feed/ \;

Transfer the project directory together with offline-feed/, then on the air-gapped host add a nuget.config beside the .csproj:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="offline" value="./offline-feed" />
  </packageSources>
</configuration>
1
2
dotnet restore
dotnet run --no-restore

The <clear /> matters: without it NuGet keeps nuget.org in the source list and restore fails on a network timeout rather than reading your folder.

Your First SQL Parser

Let's create a simple example that parses a SQL statement:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import gudusoft.gsqlparser.TGSqlParser;
import gudusoft.gsqlparser.EDbVendor;

public class QuickStartExample {
    public static void main(String[] args) {
        // Create a parser instance for Oracle SQL
        TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvoracle);

        // Set the SQL text to parse
        sqlparser.sqltext = "SELECT employee_id, first_name, last_name " +
                           "FROM employees " +
                           "WHERE department_id = 10 " +
                           "ORDER BY last_name";

        // Parse the SQL
        int result = sqlparser.parse();

        if (result == 0) {
            System.out.println("✅ SQL parsed successfully!");

            // Get basic information about the parsed SQL
            System.out.println("SQL Type: " + sqlparser.sqlstatements.get(0).sqlstatementtype);
            System.out.println("Number of statements: " + sqlparser.sqlstatements.size());

        } else {
            System.out.println("❌ Parse failed!");
            System.out.println("Error: " + sqlparser.getErrormessage());
        }
    }
}

Expected output:

1
2
3
✅ SQL parsed successfully!
SQL Type: sstselect
Number of statements: 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using gudusoft.gsqlparser;

class QuickStart
{
    static void Main()
    {
        // Pick the dialect: dbvmssql = SQL Server / T-SQL
        var parser = new TGSqlParser(EDbVendor.dbvmssql);

        parser.sqltext = "SELECT TOP 10 id, name FROM dbo.employees WHERE dept_id = 5";

        int ret = parser.parse();   // 0 == success
        if (ret == 0)
        {
            Console.WriteLine("Parsed OK, statements: " + parser.sqlstatements.size());
            Console.WriteLine("First statement type: " + parser.sqlstatements.get(0).sqlstatementtype);
        }
        else
        {
            Console.WriteLine("Parse failed: " + parser.Errormessage);
        }
    }
}

Output:

1
2
Parsed OK, statements: 1
First statement type: sstselect

To parse a file instead of a string, set parser.sqlfilename = @"C:\scripts\schema.sql"; (it is a string property; setting one input clears the other).

Why the API mixes casing

The .NET edition is a port of the Java edition, and it keeps the Java member names where they were fields. That is deliberate, so Java examples elsewhere on this site translate mechanically — but it means casing is inconsistent by design:

  • Java-style lowercase: sqltext, sqlfilename, parse(), sqlstatements, sqlstatementtype, tables, sourcetokenlist
  • C# properties: Errormessage, ErrorCount, SyntaxErrors, WhereClause, ResultColumnList, Statements, DbVendor
  • Lists use size() and get(i) methods, not Count and indexers

The full mapping table is on the .NET / C# overview.

Database Vendor Support

Pass a different EDbVendor to the constructor — the rest of your code is unchanged. Always match the vendor to the SQL's actual dialect: SELECT TOP 10 parses under dbvmssql and is a syntax error under dbvoracle.

The two editions do not cover the same vendor list

Java's EDbVendor declares 45 constants; the .NET build declares 23, and three of those throw. Java is a superset — do not assume a vendor available in one edition exists in the other. Each tab below lists only what that edition actually supports.

General SQL Parser for Java supports 40+ database vendors. Some common examples:

1
2
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
parser.sqltext = "SELECT * FROM dual WHERE ROWNUM = 1";
1
2
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvmssql);
parser.sqltext = "SELECT TOP 10 * FROM employees";
1
2
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvpostgresql);
parser.sqltext = "SELECT * FROM employees LIMIT 10";
1
2
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvmysql);
parser.sqltext = "SELECT * FROM employees LIMIT 10";
1
2
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvbigquery);
parser.sqltext = "SELECT * FROM `project.dataset.table` LIMIT 10";

The .NET build ships 15 dedicated dialect grammars: dbvdb2, dbvgreenplum, dbvhive, dbvimpala, dbvinformix, dbvmdx, dbvmssql, dbvmysql, dbvnetezza, dbvoracle, dbvpostgresql, dbvredshift, dbvsnowflake, dbvsybase, dbvteradata.

1
2
var parser = new TGSqlParser(EDbVendor.dbvmssql);
parser.sqltext = "SELECT TOP 10 * FROM employees";
1
2
var parser = new TGSqlParser(EDbVendor.dbvoracle);
parser.sqltext = "SELECT * FROM dual WHERE ROWNUM = 1";
1
2
var parser = new TGSqlParser(EDbVendor.dbvpostgresql);
parser.sqltext = "SELECT id::int FROM employees LIMIT 10";
1
2
var parser = new TGSqlParser(EDbVendor.dbvmysql);
parser.sqltext = "SELECT `id` FROM `employees` LIMIT 10";
1
2
var parser = new TGSqlParser(EDbVendor.dbvsnowflake);
parser.sqltext = "SELECT id FROM orders QUALIFY ROW_NUMBER() OVER (ORDER BY id) = 1";

The enum declares 23 constants, so the other eight need explaining:

Three constants throw, five are T-SQL in disguise

dbvbigquery, dbvhana, and dbvdax throw NotSupportedException from the TGSqlParser constructor. They exist for resolver / sqlenv vendor maps, not for parsing, and the exception message says so. Do not offer them in a dialect dropdown. Note that dbvbigquery does work in the Java edition — this is one of the places the two diverge.

dbvaccess, dbvansi, dbvgeneric, dbvodbc, and dbvfirebird resolve to the T-SQL grammar. Tested against seven dialect-specific probes, all five behave identically to dbvmssql in every case — they accept SELECT TOP 10 and reject MySQL backticks, PostgreSQL :: casts, Snowflake QUALIFY, and Firebird's own FIRST/SKIP. If you pick dbvansi expecting strict standard SQL, or dbvfirebird expecting Firebird, you get T-SQL behaviour instead. dbvaccess is a distinct enum value, not an alias of dbvmssql.

dbvmdx is a real grammar, but MDX is a different language: ordinary SQL such as SELECT a FROM t fails under it. Use it only for genuine MDX.

Per-dialect syntax coverage tables are in the SQL syntax support reference.

Common Use Cases

1. SQL Syntax Validation

parse() == 0 confirms the SQL is syntactically valid for the selected dialect. It does not check that the referenced tables/columns exist, that types are compatible, or that the statement would execute — catalog-aware validation requires metadata and the resolver APIs.

1
2
3
4
5
public boolean isSyntacticallyValidSQL(String sql, EDbVendor vendor) {
    TGSqlParser parser = new TGSqlParser(vendor);
    parser.sqltext = sql;
    return parser.parse() == 0;
}
1
2
3
4
5
public static bool IsSyntacticallyValid(string sql, EDbVendor vendor)
{
    var parser = new TGSqlParser(vendor) { sqltext = sql };
    return parser.parse() == 0;
}

2. Extract Table Names

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import gudusoft.gsqlparser.EDbVendor;
import gudusoft.gsqlparser.TGSqlParser;
import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
import gudusoft.gsqlparser.nodes.TTable;

public void extractTables(String sql) {
    TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
    parser.sqltext = sql;

    if (parser.parse() == 0
            && parser.sqlstatements.get(0) instanceof TSelectSqlStatement) {
        TSelectSqlStatement select = (TSelectSqlStatement) parser.sqlstatements.get(0);

        for (int i = 0; i < select.tables.size(); i++) {
            TTable table = select.tables.getTable(i);
            System.out.println("Table: " + table.getFullName());
        }
    }
}

TGSqlParser and EDbVendor live in the root gudusoft.gsqlparser package, while AST nodes like TTable live in gudusoft.gsqlparser.nodes and statements like TSelectSqlStatement in gudusoft.gsqlparser.stmt. Import all four or the snippet will not compile.

Pick the right accessor — this is a common trip-up:

Method Returns For FROM dbo.employees e
table.getFullName() String dbo.employees — schema-qualified. Use this for dependency graphs.
table.getName() String employees — bare name, no schema.
table.getAliasName() String e — the alias, or empty when there is none.
table.getTableName() TObjectName An AST node, not a String. It renders as dbo.employees via toString(), so it looks interchangeable with getFullName() inside string concatenation — but it is not.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using gudusoft.gsqlparser;
using gudusoft.gsqlparser.nodes;

class ExtractTables
{
    static void Main()
    {
        var parser = new TGSqlParser(EDbVendor.dbvmssql);
        parser.sqltext =
            "SELECT e.name, d.dept_name " +
            "FROM dbo.employees e " +
            "JOIN dbo.departments d ON e.dept_id = d.id " +
            "WHERE e.salary > 50000";

        if (parser.parse() != 0) { Console.WriteLine(parser.Errormessage); return; }

        TCustomSqlStatement stmt = parser.sqlstatements.get(0);
        for (int i = 0; i < stmt.tables.size(); i++)
        {
            TTable table = stmt.tables.getTable(i);
            Console.WriteLine($"{table.FullName}  (bare: {table.Name}, alias: {table.AliasName})");
        }
    }
}

Output:

1
2
dbo.employees  (bare: employees, alias: e)
dbo.departments  (bare: departments, alias: d)

Pick the right member for the job — this is a common trip-up:

Member Type Value above
table.FullName string dbo.employees — schema-qualified. Use this for dependency graphs.
table.Name string employees — bare name, no schema.
table.AliasName string e — the alias, or empty when there is none.
table.TableName TObjectName An AST node, not a string. It renders as dbo.employees through ToString(), so it looks interchangeable with FullName inside string interpolation — but it is not.

Statements nest — procedure bodies, BEGIN...END blocks, IF branches, and the SELECT inside an INSERT. A CREATE PROCEDURE reports tables=0 itself: the tables belong to the statements inside the body. Recurse through stmt.Statements to reach them, or a dependency inventory finds nothing:

1
2
3
4
5
6
7
8
9
static void Walk(TCustomSqlStatement stmt, int depth)
{
    string pad = new string(' ', depth * 2);
    Console.WriteLine($"{pad}{stmt.sqlstatementtype}  tables={stmt.tables.size()}");
    for (int i = 0; i < stmt.tables.size(); i++)
        Console.WriteLine($"{pad}  table: {stmt.tables.getTable(i).FullName}");
    for (int i = 0; i < stmt.Statements.size(); i++)
        Walk(stmt.Statements.get(i), depth + 1);
}

For a procedure that archives then deletes:

1
2
3
4
5
6
7
8
sstmssqlcreateprocedure  tables=0
  sstmssqlblock  tables=0
    sstinsert  tables=1
      table: dbo.orders_archive
      sstselect  tables=1
        table: dbo.orders
    sstdelete  tables=1
      table: dbo.orders

GO separators are statements, not whitespace

In a T-SQL script, three SQL statements plus two GO batch separators produce five entries in sqlstatements, with GO surfacing as sstmssqlgo. That is useful when round-tripping a script, but it will surprise you if you assumed the count matched your statements. Skip them when you only want real work:

1
if (stmt.sqlstatementtype == ESqlStatementType.sstmssqlgo) continue;

3. Format SQL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import gudusoft.gsqlparser.EDbVendor;
import gudusoft.gsqlparser.TGSqlParser;

import gudusoft.gsqlparser.pp.para.GFmtOptFactory;
import gudusoft.gsqlparser.pp.para.GFmtOpt;
import gudusoft.gsqlparser.pp.stmtformatter.FormatterFactory;


public class formatsql {

    public static void main(String args[])
     {

        TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvpostgresql);

        sqlparser.sqltext ="WITH upd AS (\n" +
                "  UPDATE employees SET sales_count = sales_count + 1 WHERE id =\n" +
                "    (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation')\n" +
                "    RETURNING *\n" +
                ")\n" +
                "INSERT INTO employees_log SELECT *, current_timestamp FROM upd;";



        int ret = sqlparser.parse();
        if (ret == 0){
            GFmtOpt option = GFmtOptFactory.newInstance();
            String result = FormatterFactory.pp(sqlparser, option);
            System.out.println(result);
        }else{
            System.out.println(sqlparser.getErrormessage());
        }
     }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using gudusoft.gsqlparser;
using gudusoft.gsqlparser.pp.para;
using gudusoft.gsqlparser.pp.stmtformatter;

class FormatSql
{
    static void Main()
    {
        var parser = new TGSqlParser(EDbVendor.dbvpostgresql);
        parser.sqltext = "select a,b from t where a=1 order by b";

        if (parser.parse() == 0)
        {
            GFmtOpt option = GFmtOptFactory.newInstance();
            Console.WriteLine(FormatterFactory.pp(parser, option));
        }
        else
        {
            Console.WriteLine(parser.Errormessage);
        }
    }
}

Output:

1
2
3
4
5
SELECT   a,
         b
FROM     t
WHERE    a = 1
ORDER BY b

Error Handling

Always handle parsing errors gracefully:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import gudusoft.gsqlparser.TGSqlParser;
import gudusoft.gsqlparser.EDbVendor;
import gudusoft.gsqlparser.TSyntaxError;

public class QuickStartExample {
    public static void main(String[] args) {
        TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
        parser.sqltext = "SELECT * FROM"; // Invalid SQL

        int result = parser.parse();
        if (result != 0) {
            System.err.println("Parse Error:");
            System.err.println("Message: " + parser.getErrormessage());
            for(TSyntaxError error : parser.getSyntaxErrors()) {
                System.err.println("Line: " + error.lineNo);
                System.err.println("Column: " + error.columnNo);
                System.err.println("Token: " + error.tokentext);
                System.err.println("Error type: " + error.errortype);
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using gudusoft.gsqlparser;

class CheckSyntax
{
    static void Main()
    {
        var parser = new TGSqlParser(EDbVendor.dbvmssql);
        parser.sqltext = "SELECT id, FROM orders WHERE;";   // broken on purpose

        if (parser.parse() != 0)
        {
            Console.WriteLine($"{parser.ErrorCount} error(s): {parser.Errormessage}");
            foreach (TSyntaxError e in parser.SyntaxErrors)
            {
                Console.WriteLine(
                    $"line {e.lineNo}, column {e.columnNo}, near '{e.tokentext}' " +
                    $"[{e.errortype}]: {e.hint}");
            }
        }
    }
}

Output:

1
2
1 error(s): syntax error, state:2398(10101) near: ;(1,29)
line 1, column 29, near ';' [spfatalerror]: syntax error, state:2398

TSyntaxError exposes lineNo, columnNo (both long), tokentext, hint, errortype, and errorno — enough for an editor plugin or CI gate to underline the offending token. Note that hint is a short restatement of the parser state rather than a human-friendly suggestion; lineNo, columnNo and tokentext are the fields worth surfacing to users.

checkSyntax() is an alias of parse() with the same return contract, if you prefer the intent-revealing name for validation-only code paths.

Next Steps

Now that you have General SQL Parser running, explore these areas:

Continue Learning

Troubleshooting

Common Issues

Parse Error: Unexpected token

Solution: Check that you're using the correct database vendor. SQL syntax varies between databases.

1
2
3
4
5
6
7
// Wrong
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
parser.sqltext = "SELECT TOP 10 * FROM table"; // SQL Server syntax

// Correct
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvmssql);
parser.sqltext = "SELECT TOP 10 * FROM table";
1
2
3
4
5
6
7
// Wrong — the Oracle grammar has no TOP
var parser = new TGSqlParser(EDbVendor.dbvoracle);
parser.sqltext = "SELECT TOP 10 * FROM t";

// Correct
var parser = new TGSqlParser(EDbVendor.dbvmssql);
parser.sqltext = "SELECT TOP 10 * FROM t";

OutOfMemoryError / OutOfMemoryException

Solution: For large SQL files, parse statements individually rather than loading a multi-megabyte file as one string.

Increase the JVM heap size, or split the input. See the performance optimization guide.

Split the input. See the performance optimization guide.

Class or type not found at runtime

ClassNotFoundException — ensure the GSQLParser JAR is on your classpath and all dependencies are included.

TypeLoadException / FileNotFoundException — check your target framework. Use net462 or newer on .NET Framework, not net461; see Framework compatibility. On .NET Core, net5.0 and older netcoreapp* targets are EOL; upgrade.

parse() returned -1

Your input is over the 10,000 size limit, or the trial expired 90 days after first use. That is the trial limit, not a problem with your SQL. This applies to the Java trial and the .NET trial alike — both public packages are trial builds. Read the exact message from getErrormessage() (Java) or Errormessage (C#) to tell the two causes apart. Split the script, or use the full edition. See The public package is the trial build.

C# only: NotSupportedException from the constructor

You passed dbvbigquery, dbvhana, or dbvdax. These have no parser grammar in the .NET build, though dbvbigquery works in Java. See Database Vendor Support.

C# only: NU1701 warning, or dbvsnowflake does not exist

You are on a pre-4.x NuGet package. Versions up to 3.3.0.4 were .NET Framework 4.5 builds that restored through AssetTargetFallback and predate several dialects. Run dotnet add package gudusoft.gsqlparser to move to the current release.

Getting Help

  • 📖 Check our FAQ for common questions
  • 💬 Visit our Support page for community help
  • 📧 Contact technical support for commercial licenses

Ready for more advanced features? Continue with our comprehensive tutorials or explore specific how-to guides.