Edit on GitHub

## Dialects

While there is a SQL standard, most SQL engines support a variation of that standard. This makes it difficult to write portable SQL code. SQLGlot bridges all the different variations, called "dialects", with an extensible SQL transpilation framework.

The base `sqlglot.dialects.dialect.Dialect` class implements a generic dialect that aims to be as universal as possible.

Each SQL variation has its own `Dialect` subclass, extending the corresponding `Tokenizer`, `Parser` and `Generator` classes as needed.

### Implementing a custom Dialect

Creating a new SQL dialect may seem complicated at first, but it is actually quite simple in SQLGlot:

    from sqlglot import exp
    from sqlglot.dialects.dialect import Dialect
    from sqlglot.generator import Generator
    from sqlglot.tokens import Tokenizer, TokenType

    class Custom(Dialect):
        class Tokenizer(Tokenizer):
            QUOTES = ["'", '"']  # Strings can be delimited by either single or double quotes
            IDENTIFIERS = ["`"]  # Identifiers can be delimited by backticks

            # Associates certain meaningful words with tokens that capture their intent
            KEYWORDS = {
                **Tokenizer.KEYWORDS,
                "INT64": TokenType.BIGINT,
                "FLOAT64": TokenType.DOUBLE,
            }

        class Generator(Generator):
            # Specifies how AST nodes, i.e. subclasses of exp.Expression, should be converted into SQL
            TRANSFORMS = {
                exp.Array: lambda self, e: f"[{self.expressions(e)}]",
            }

            # Specifies how AST nodes representing data types should be converted into SQL
            TYPE_MAPPING = {
                exp.DataType.Type.TINYINT: "INT64",
                exp.DataType.Type.SMALLINT: "INT64",
                exp.DataType.Type.INT: "INT64",
                exp.DataType.Type.BIGINT: "INT64",
                exp.DataType.Type.DECIMAL: "NUMERIC",
                exp.DataType.Type.FLOAT: "FLOAT64",
                exp.DataType.Type.DOUBLE: "FLOAT64",
                exp.DataType.Type.BOOLEAN: "BOOL",
                exp.DataType.Type.TEXT: "STRING",
            }

The above example demonstrates how certain parts of the base `Dialect` class can be overridden to match a different specification. Even though it is a fairly realistic starting point, we strongly encourage the reader to study existing dialect implementations in order to understand how their various components can be modified, depending on the use-case.

View Source

      1# ruff: noqa: F401
      2"""
      3## Dialects
      4
      5While there is a SQL standard, most SQL engines support a variation of that standard. This makes it difficult
      6to write portable SQL code. SQLGlot bridges all the different variations, called "dialects", with an extensible
      7SQL transpilation framework.
      8
      9The base `sqlglot.dialects.dialect.Dialect` class implements a generic dialect that aims to be as universal as possible.
     10
     11Each SQL variation has its own `Dialect` subclass, extending the corresponding `Tokenizer`, `Parser` and `Generator`
     12classes as needed.
     13
     14### Implementing a custom Dialect
     15
     16Creating a new SQL dialect may seem complicated at first, but it is actually quite simple in SQLGlot:
     17
     18```python
     19from sqlglot import exp
     20from sqlglot.dialects.dialect import Dialect
     21from sqlglot.generator import Generator
     22from sqlglot.tokens import Tokenizer, TokenType
     23
     24
     25class Custom(Dialect):
     26    class Tokenizer(Tokenizer):
     27        QUOTES = ["'", '"']  # Strings can be delimited by either single or double quotes
     28        IDENTIFIERS = ["`"]  # Identifiers can be delimited by backticks
     29
     30        # Associates certain meaningful words with tokens that capture their intent
     31        KEYWORDS = {
     32            **Tokenizer.KEYWORDS,
     33            "INT64": TokenType.BIGINT,
     34            "FLOAT64": TokenType.DOUBLE,
     35        }
     36
     37    class Generator(Generator):
     38        # Specifies how AST nodes, i.e. subclasses of exp.Expression, should be converted into SQL
     39        TRANSFORMS = {
     40            exp.Array: lambda self, e: f"[{self.expressions(e)}]",
     41        }
     42
     43        # Specifies how AST nodes representing data types should be converted into SQL
     44        TYPE_MAPPING = {
     45            exp.DataType.Type.TINYINT: "INT64",
     46            exp.DataType.Type.SMALLINT: "INT64",
     47            exp.DataType.Type.INT: "INT64",
     48            exp.DataType.Type.BIGINT: "INT64",
     49            exp.DataType.Type.DECIMAL: "NUMERIC",
     50            exp.DataType.Type.FLOAT: "FLOAT64",
     51            exp.DataType.Type.DOUBLE: "FLOAT64",
     52            exp.DataType.Type.BOOLEAN: "BOOL",
     53            exp.DataType.Type.TEXT: "STRING",
     54        }
     55```
     56
     57The above example demonstrates how certain parts of the base `Dialect` class can be overridden to match a different
     58specification. Even though it is a fairly realistic starting point, we strongly encourage the reader to study existing
     59dialect implementations in order to understand how their various components can be modified, depending on the use-case.
     60
     61----
     62"""
     63
     64import importlib
     65import threading
     66
     67DIALECTS = [
     68    "Athena",
     69    "BigQuery",
     70    "ClickHouse",
     71    "Databricks",
     72    "Doris",
     73    "Dremio",
     74    "Drill",
     75    "Druid",
     76    "DuckDB",
     77    "Dune",
     78    "Fabric",
     79    "Hive",
     80    "Materialize",
     81    "MySQL",
     82    "Oracle",
     83    "Postgres",
     84    "Presto",
     85    "PRQL",
     86    "Redshift",
     87    "RisingWave",
     88    "Snowflake",
     89    "Spark",
     90    "Spark2",
     91    "SQLite",
     92    "StarRocks",
     93    "Tableau",
     94    "Teradata",
     95    "Trino",
     96    "TSQL",
     97    "Exasol",
     98]
     99
    100MODULE_BY_DIALECT = {name: name.lower() for name in DIALECTS}
    101DIALECT_MODULE_NAMES = MODULE_BY_DIALECT.values()
    102
    103MODULE_BY_ATTRIBUTE = {
    104    **MODULE_BY_DIALECT,
    105    "Dialect": "dialect",
    106    "Dialects": "dialect",
    107}
    108
    109__all__ = list(MODULE_BY_ATTRIBUTE)
    110
    111# We use a reentrant lock because a dialect may depend on (i.e., import) other dialects.
    112# Without it, the first dialect import would never be completed, because subsequent
    113# imports would be blocked on the lock held by the first import.
    114_import_lock = threading.RLock()
    115
    116
    117def __getattr__(name):
    118    module_name = MODULE_BY_ATTRIBUTE.get(name)
    119    if module_name:
    120        with _import_lock:
    121            module = importlib.import_module(f"sqlglot.dialects.{module_name}")
    122        return getattr(module, name)
    123
    124    raise AttributeError(f"module {__name__} has no attribute {name}")

Athena = <MagicMock id='139680721978080'>
BigQuery = <MagicMock id='139680721982976'>
ClickHouse = <MagicMock id='139680720582112'>
Databricks = <MagicMock id='139680707258224'>
Doris = <MagicMock id='139680707252080'>
Dremio = <MagicMock id='139680716951936'>
Drill = <MagicMock id='139680716949728'>
Druid = <MagicMock id='139680718254144'>
DuckDB = <MagicMock id='139680718250736'>
Dune = <MagicMock id='139680714461040'>
Fabric = <MagicMock id='139680714471504'>
Hive = <MagicMock id='139680713609456'>
Materialize = <MagicMock id='139680718392192'>
MySQL = <MagicMock id='139680713212544'>
Oracle = <MagicMock id='139680707907344'>
Postgres = <MagicMock id='139680718268320'>
Presto = <MagicMock id='139680722152480'>
PRQL = <MagicMock id='139680722152048'>
Redshift = <MagicMock id='139680712692480'>
RisingWave = <MagicMock id='139680716783824'>
Snowflake = <MagicMock id='139680716791792'>
Spark = <MagicMock id='139680714541616'>
Spark2 = <MagicMock id='139680720491408'>
SQLite = <MagicMock id='139680712063104'>
StarRocks = <MagicMock id='139680709348608'>
Tableau = <MagicMock id='139680709350432'>
Teradata = <MagicMock id='139680720058784'>
Trino = <MagicMock id='139680721298448'>
TSQL = <MagicMock id='139680711995072'>
Exasol = <MagicMock id='139680717963216'>
Dialect = <MagicMock id='139680717957216'>
Dialects = <MagicMock id='139680717658896'>