Skip to content

Working with Different Databases

This tutorial explores General SQL Parser .NET's support for the 15 built-in dialects and how to handle vendor-specific SQL.

Objectives

  • Configure GSP for each of the 15 supported vendors
  • Handle vendor-specific SQL features and extensions
  • Parse Oracle PL/SQL blocks
  • Work with SQL Server T-SQL specifics
  • Manage PostgreSQL and MySQL syntax differences
  • Switch dialect context effectively

Prerequisites

  • Completed Basic SQL Parsing
  • Familiarity with SQL differences across database systems

Time required

About 60 minutes.

Supported vendors

The .NET library ships with 15 dialects baked into the prebuilt NuGet package. Each maps to a member of the EDbVendor enum:

Vendor Constant Notes
IBM DB2 EDbVendor.dbvdb2 DB2 LUW + iSeries
Greenplum EDbVendor.dbvgreenplum PostgreSQL fork
Apache Hive EDbVendor.dbvhive HiveQL
Apache Impala EDbVendor.dbvimpala Impala SQL
IBM Informix EDbVendor.dbvinformix
MDX EDbVendor.dbvmdx OLAP
Microsoft SQL Server EDbVendor.dbvmssql Alias dbvaccess for MS Access
MySQL EDbVendor.dbvmysql Plus MariaDB
IBM Netezza EDbVendor.dbvnetezza
Oracle EDbVendor.dbvoracle Includes PL/SQL
PostgreSQL EDbVendor.dbvpostgresql
Amazon Redshift EDbVendor.dbvredshift PostgreSQL-derived
Snowflake EDbVendor.dbvsnowflake
Sybase ASE EDbVendor.dbvsybase T-SQL family
Teradata EDbVendor.dbvteradata Includes BTEQ + SPL

If you build the library from source you can drop unused dialects with /p:includeXxx=false flags.

Step-by-step guide

1. Switching vendors

The vendor is selected at construction time and embedded in the parser:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
using gudusoft.gsqlparser;

var oracle = new TGSqlParser(EDbVendor.dbvoracle);
var mssql  = new TGSqlParser(EDbVendor.dbvmssql);
var pg     = new TGSqlParser(EDbVendor.dbvpostgresql);

oracle.sqltext = "SELECT * FROM dual WHERE ROWNUM = 1";
mssql.sqltext  = "SELECT TOP 10 * FROM employees";
pg.sqltext     = "SELECT * FROM employees LIMIT 10 OFFSET 5";

foreach (var p in new[] { oracle, mssql, pg })
    Console.WriteLine($"{p.DbVendor,-20} -> {(p.parse() == 0 ? "ok" : p.Errormessage)}");

You cannot change vendor on an existing TGSqlParser. To analyse the same SQL against multiple dialects, construct one parser per vendor.

2. Oracle PL/SQL

Oracle is the only built-in vendor with a separate PL/SQL parser. TGSqlParser instantiates it automatically when it sees a BEGIN ... END; block, a CREATE PROCEDURE/FUNCTION/PACKAGE, or an anonymous block.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var parser = new TGSqlParser(EDbVendor.dbvoracle);
parser.sqltext = """
    CREATE OR REPLACE PROCEDURE raise_salary (
        emp_id      IN NUMBER,
        increment   IN NUMBER
    ) AS
    BEGIN
        UPDATE employees
           SET salary = salary + increment
         WHERE employee_id = emp_id;
    END raise_salary;
    """;

if (parser.parse() == 0)
    Console.WriteLine($"Parsed: {parser.sqlstatements.get(0).sqlstatementtype}");

See Parse Oracle PL/SQL for the deep dive.

3. SQL Server T-SQL

The MSSQL vendor handles full T-SQL — variables, control-of-flow, OUTPUT clauses, MERGE, CTEs, OPENJSON, etc.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var parser = new TGSqlParser(EDbVendor.dbvmssql);
parser.sqltext = """
    DECLARE @threshold INT = 1000;
    MERGE INTO target_table AS t
    USING source_table AS s ON t.id = s.id
    WHEN MATCHED AND s.amount > @threshold THEN
        UPDATE SET t.amount = s.amount
    WHEN NOT MATCHED BY TARGET THEN
        INSERT (id, amount) VALUES (s.id, s.amount)
    OUTPUT $action, inserted.id, deleted.amount;
    """;

if (parser.parse() == 0)
    Console.WriteLine($"Parsed {parser.sqlstatements.size()} statement(s).");

Sybase ASE shares a lot of grammar with MSSQL — use EDbVendor.dbvsybase for ASE-specific syntax (raiserror, sp_* extensions).

4. PostgreSQL & Greenplum & Redshift

PostgreSQL, Greenplum and Redshift share grammar ancestry. If your SQL targets a fork, pick the matching vendor — they recognise different reserved-word sets and dialect extensions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// PostgreSQL — RETURNING clause and CTE-driven INSERT
var pg = new TGSqlParser(EDbVendor.dbvpostgresql);
pg.sqltext = """
    WITH upd AS (
      UPDATE employees SET sales_count = sales_count + 1
      WHERE id = (SELECT sales_person FROM accounts WHERE name = 'Acme')
      RETURNING *
    )
    INSERT INTO employees_log SELECT *, current_timestamp FROM upd;
    """;
pg.parse();

// Redshift — SUPER columns and DISTKEY
var rs = new TGSqlParser(EDbVendor.dbvredshift);
rs.sqltext = """
    CREATE TABLE events (
        id   BIGINT IDENTITY(1,1),
        body SUPER
    ) DISTKEY(id) SORTKEY(id);
    """;
rs.parse();

5. MySQL specifics

1
2
3
4
5
6
7
8
9
var mysql = new TGSqlParser(EDbVendor.dbvmysql);
mysql.sqltext = """
    SELECT *
    FROM   employees
    LIMIT  5, 10;                       -- MySQL OFFSET, LIMIT
    """;
mysql.parse();

// Backtick-quoted identifiers, FORCE INDEX hints, etc. all parse via dbvmysql.

6. Snowflake

1
2
3
4
5
6
7
8
var sf = new TGSqlParser(EDbVendor.dbvsnowflake);
sf.sqltext = """
    SELECT employee_id,
           AVG(salary) OVER (PARTITION BY dept) AS dept_avg
    FROM   employees
    QUALIFY ROW_NUMBER() OVER (ORDER BY hire_date DESC) <= 10;
    """;
sf.parse();

7. Teradata

Teradata has its own SPL (stored procedure language) and BTEQ commands; both are handled.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var td = new TGSqlParser(EDbVendor.dbvteradata);
td.sqltext = """
    CREATE PROCEDURE sample_sp (IN inp INT, OUT outp INT)
    BEGIN
        DECLARE total INT;
        SELECT SUM(amount) INTO total FROM orders WHERE customer_id = inp;
        SET outp = total;
    END;
    """;
td.parse();

Building a vendor auto-detector

When you don't know the dialect ahead of time, try each vendor and pick the one that parses cleanly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public static EDbVendor? DetectVendor(string sql)
{
    EDbVendor[] candidates =
    {
        EDbVendor.dbvoracle, EDbVendor.dbvmssql, EDbVendor.dbvpostgresql,
        EDbVendor.dbvmysql,  EDbVendor.dbvsnowflake, EDbVendor.dbvteradata,
        EDbVendor.dbvdb2,    EDbVendor.dbvhive, EDbVendor.dbvredshift,
    };
    foreach (var v in candidates)
    {
        var parser = new TGSqlParser(v) { sqltext = sql };
        if (parser.parse() == 0) return v;
    }
    return null;
}

This is intentionally a sketch — for real workloads, weight the candidates by the actual mix of SQL you expect to see, and remember that simple SELECTs parse identically across most vendors so a "first match" wins.

Summary

You learned how to:

  • Pick the right EDbVendor for each dialect
  • Parse Oracle PL/SQL blocks via the same TGSqlParser entry point
  • Handle SQL Server T-SQL constructs (MERGE, OUTPUT, variables)
  • Distinguish between PostgreSQL, Greenplum, and Redshift
  • Recognise MySQL- and Snowflake-specific syntax
  • Build a simple vendor auto-detector

What's next?