1
0
Fork 0

Merging upstream version 17.12.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 20:55:29 +01:00
parent aa315e6009
commit aae08e0bb3
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
64 changed files with 12465 additions and 11885 deletions

View file

@ -1,6 +1,6 @@
![SQLGlot logo](sqlglot.svg) ![SQLGlot logo](sqlglot.svg)
SQLGlot is a no-dependency SQL parser, transpiler, optimizer, and engine. It can be used to format SQL or translate between [19 different dialects](https://github.com/tobymao/sqlglot/blob/main/sqlglot/dialects/__init__.py) like [DuckDB](https://duckdb.org/), [Presto](https://prestodb.io/), [Spark](https://spark.apache.org/), [Snowflake](https://www.snowflake.com/en/), and [BigQuery](https://cloud.google.com/bigquery/). It aims to read a wide variety of SQL inputs and output syntactically and semantically correct SQL in the targeted dialects. SQLGlot is a no-dependency SQL parser, transpiler, optimizer, and engine. It can be used to format SQL or translate between [20 different dialects](https://github.com/tobymao/sqlglot/blob/main/sqlglot/dialects/__init__.py) like [DuckDB](https://duckdb.org/), [Presto](https://prestodb.io/), [Spark](https://spark.apache.org/), [Snowflake](https://www.snowflake.com/en/), and [BigQuery](https://cloud.google.com/bigquery/). It aims to read a wide variety of SQL inputs and output syntactically and semantically correct SQL in the targeted dialects.
It is a very comprehensive generic SQL parser with a robust [test suite](https://github.com/tobymao/sqlglot/blob/main/tests/). It is also quite [performant](#benchmarks), while being written purely in Python. It is a very comprehensive generic SQL parser with a robust [test suite](https://github.com/tobymao/sqlglot/blob/main/tests/). It is also quite [performant](#benchmarks), while being written purely in Python.

File diff suppressed because one or more lines are too long

View file

@ -51,8 +51,8 @@
<div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">1</span></a><span class="c1"># file generated by setuptools_scm</span> <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">1</span></a><span class="c1"># file generated by setuptools_scm</span>
</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="c1"># don&#39;t change, don&#39;t track in version control</span> </span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="c1"># don&#39;t change, don&#39;t track in version control</span>
</span><span id="L-3"><a href="#L-3"><span class="linenos">3</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;17.10.2&#39;</span> </span><span id="L-3"><a href="#L-3"><span class="linenos">3</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;17.11.0&#39;</span>
</span><span id="L-4"><a href="#L-4"><span class="linenos">4</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">17</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> </span><span id="L-4"><a href="#L-4"><span class="linenos">4</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">17</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></pre></div> </span></pre></div>

View file

@ -777,7 +777,7 @@
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">createDataFrame</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">data</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433399883728&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433399883728&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="n">Tuple</span><span class="p">]]</span>,</span><span class="param"> <span class="n">schema</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397876336&#39;</span><span class="o">&gt;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">samplingRatio</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">verifySchema</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span> <span class="name">createDataFrame</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">data</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247752106064&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247752106064&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="n">Tuple</span><span class="p">]]</span>,</span><span class="param"> <span class="n">schema</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751758304&#39;</span><span class="o">&gt;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">samplingRatio</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">verifySchema</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span>
<label class="view-source-button" for="SparkSession.createDataFrame-view-source"><span>View Source</span></label> <label class="view-source-button" for="SparkSession.createDataFrame-view-source"><span>View Source</span></label>
@ -1681,7 +1681,7 @@
<input id="DataFrame.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DataFrame.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr function"> <div class="attr function">
<span class="name">DataFrame</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">spark</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433402406240&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">expression</span><span class="p">:</span> <span class="n"><a href="../expressions.html#Select">sqlglot.expressions.Select</a></span>,</span><span class="param"> <span class="n">branch_id</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">sequence_id</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">last_op</span><span class="p">:</span> <span class="n">sqlglot</span><span class="o">.</span><span class="n">dataframe</span><span class="o">.</span><span class="n">sql</span><span class="o">.</span><span class="n">operations</span><span class="o">.</span><span class="n">Operation</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">Operation</span><span class="o">.</span><span class="n">INIT</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">pending_hints</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">output_expression_container</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433402588384&#39;</span><span class="o">&gt;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span>)</span> <span class="name">DataFrame</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">spark</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247754743024&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">expression</span><span class="p">:</span> <span class="n"><a href="../expressions.html#Select">sqlglot.expressions.Select</a></span>,</span><span class="param"> <span class="n">branch_id</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">sequence_id</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">last_op</span><span class="p">:</span> <span class="n">sqlglot</span><span class="o">.</span><span class="n">dataframe</span><span class="o">.</span><span class="n">sql</span><span class="o">.</span><span class="n">operations</span><span class="o">.</span><span class="n">Operation</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">Operation</span><span class="o">.</span><span class="n">INIT</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">pending_hints</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">output_expression_container</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247754780976&#39;</span><span class="o">&gt;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span>)</span>
<label class="view-source-button" for="DataFrame.__init__-view-source"><span>View Source</span></label> <label class="view-source-button" for="DataFrame.__init__-view-source"><span>View Source</span></label>
@ -2611,7 +2611,7 @@ is unlikely to come up.</p>
<div class="decorator">@operation(Operation.FROM)</div> <div class="decorator">@operation(Operation.FROM)</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">fillna</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433398158848&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">subset</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span> <span class="name">fillna</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750367872&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">subset</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span>
<label class="view-source-button" for="DataFrame.fillna-view-source"><span>View Source</span></label> <label class="view-source-button" for="DataFrame.fillna-view-source"><span>View Source</span></label>
@ -2680,7 +2680,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@operation(Operation.FROM)</div> <div class="decorator">@operation(Operation.FROM)</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">replace</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">to_replace</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">]</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">subset</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">Collection</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433398619760&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433398619760&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span> <span class="name">replace</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">to_replace</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">]</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>,</span><span class="param"> <span class="n">subset</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">Collection</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750893600&#39;</span><span class="o">&gt;</span><span class="p">],</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750893600&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span>
<label class="view-source-button" for="DataFrame.replace-view-source"><span>View Source</span></label> <label class="view-source-button" for="DataFrame.replace-view-source"><span>View Source</span></label>
@ -2885,7 +2885,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@operation(Operation.NO_OP)</div> <div class="decorator">@operation(Operation.NO_OP)</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">repartition</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">numPartitions</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433398667856&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433398849232&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span> <span class="name">repartition</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">numPartitions</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750971488&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751075264&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#DataFrame">sqlglot.dataframe.sql.DataFrame</a></span>:</span></span>
<label class="view-source-button" for="DataFrame.repartition-view-source"><span>View Source</span></label> <label class="view-source-button" for="DataFrame.repartition-view-source"><span>View Source</span></label>
@ -3590,7 +3590,7 @@ and check if it matches the type of the value provided. If not then make it null
<input id="Column.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="Column.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr function"> <div class="attr function">
<span class="name">Column</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">expression</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433400603568&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span></span>)</span> <span class="name">Column</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">expression</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247752861744&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span></span>)</span>
<label class="view-source-button" for="Column.__init__-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.__init__-view-source"><span>View Source</span></label>
@ -3633,7 +3633,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">ensure_col</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433396832032&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">ensure_col</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751170832&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.ensure_col-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.ensure_col-view-source"><span>View Source</span></label>
@ -3654,7 +3654,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">ensure_cols</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397055744&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n">List</span><span class="p">[</span><span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span><span class="p">]</span>:</span></span> <span class="name">ensure_cols</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751312000&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n"><a href="../expressions.html#Expression">sqlglot.expressions.Expression</a></span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n">List</span><span class="p">[</span><span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span><span class="p">]</span>:</span></span>
<label class="view-source-button" for="Column.ensure_cols-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.ensure_cols-view-source"><span>View Source</span></label>
@ -3675,7 +3675,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">invoke_anonymous_function</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">column</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397021856&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="n">func_name</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param"> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397029168&#39;</span><span class="o">&gt;</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">invoke_anonymous_function</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">column</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751388768&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="n">func_name</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param"> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247751253904&#39;</span><span class="o">&gt;</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.invoke_anonymous_function-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.invoke_anonymous_function-view-source"><span>View Source</span></label>
@ -3702,7 +3702,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">invoke_expression_over_column</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">column</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397176624&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="n">callable_expression</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">invoke_expression_over_column</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="n">column</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749317376&#39;</span><span class="o">&gt;</span><span class="p">]</span>,</span><span class="param"> <span class="n">callable_expression</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.invoke_expression_over_column-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.invoke_expression_over_column-view-source"><span>View Source</span></label>
@ -3739,7 +3739,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">binary_op</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">klass</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="n">other</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397200016&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">binary_op</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">klass</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="n">other</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749362688&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.binary_op-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.binary_op-view-source"><span>View Source</span></label>
@ -3760,7 +3760,7 @@ and check if it matches the type of the value provided. If not then make it null
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">inverse_binary_op</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">klass</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="n">other</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397228416&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">inverse_binary_op</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">klass</span><span class="p">:</span> <span class="n">Callable</span>,</span><span class="param"> <span class="n">other</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749371856&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.inverse_binary_op-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.inverse_binary_op-view-source"><span>View Source</span></label>
@ -4314,7 +4314,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">isin</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397436752&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Iterable</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397436752&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">):</span></span> <span class="name">isin</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749611664&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Iterable</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749611664&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">):</span></span>
<label class="view-source-button" for="Column.isin-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.isin-view-source"><span>View Source</span></label>
@ -4335,7 +4335,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">between</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">lowerBound</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397493824&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">upperBound</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397553648&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">between</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">lowerBound</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749668688&#39;</span><span class="o">&gt;</span>,</span><span class="param"> <span class="n">upperBound</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749746240&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.between-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.between-view-source"><span>View Source</span></label>
@ -4370,7 +4370,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">over</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">window</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397613424&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span> <span class="name">over</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="n">window</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749805200&#39;</span><span class="o">&gt;</span></span><span class="return-annotation">) -> <span class="n"><a href="#Column">sqlglot.dataframe.sql.Column</a></span>:</span></span>
<label class="view-source-button" for="Column.over-view-source"><span>View Source</span></label> <label class="view-source-button" for="Column.over-view-source"><span>View Source</span></label>
@ -4615,7 +4615,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">partitionBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397803296&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397803296&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span> <span class="name">partitionBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750117552&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750117552&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span>
<label class="view-source-button" for="Window.partitionBy-view-source"><span>View Source</span></label> <label class="view-source-button" for="Window.partitionBy-view-source"><span>View Source</span></label>
@ -4636,7 +4636,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="decorator">@classmethod</div> <div class="decorator">@classmethod</div>
<span class="def">def</span> <span class="def">def</span>
<span class="name">orderBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397707584&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433397707584&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span> <span class="name">orderBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">cls</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750312768&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750312768&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span>
<label class="view-source-button" for="Window.orderBy-view-source"><span>View Source</span></label> <label class="view-source-button" for="Window.orderBy-view-source"><span>View Source</span></label>
@ -4872,7 +4872,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">partitionBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433395835296&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433395835296&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span> <span class="name">partitionBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749874528&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247749874528&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span>
<label class="view-source-button" for="WindowSpec.partitionBy-view-source"><span>View Source</span></label> <label class="view-source-button" for="WindowSpec.partitionBy-view-source"><span>View Source</span></label>
@ -4899,7 +4899,7 @@ Sqlglot doesn't currently replicate this class so it only accepts a string</p>
<div class="attr function"> <div class="attr function">
<span class="def">def</span> <span class="def">def</span>
<span class="name">orderBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433395968336&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140433395968336&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span> <span class="name">orderBy</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="bp">self</span>,</span><span class="param"> <span class="o">*</span><span class="n">cols</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750159776&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="o">&lt;</span><span class="n">MagicMock</span> <span class="nb">id</span><span class="o">=</span><span class="s1">&#39;140247750159776&#39;</span><span class="o">&gt;</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="n"><a href="#WindowSpec">sqlglot.dataframe.sql.WindowSpec</a></span>:</span></span>
<label class="view-source-button" for="WindowSpec.orderBy-view-source"><span>View Source</span></label> <label class="view-source-button" for="WindowSpec.orderBy-view-source"><span>View Source</span></label>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -741,7 +741,6 @@ Default: 3</li>
<dd id="Databricks.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd> <dd id="Databricks.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd>
<dd id="Databricks.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd> <dd id="Databricks.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd>
<dd id="Databricks.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd> <dd id="Databricks.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd>
<dd id="Databricks.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="../parser.html#Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Databricks.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd> <dd id="Databricks.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd>
<dd id="Databricks.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd> <dd id="Databricks.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd>
<dd id="Databricks.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd> <dd id="Databricks.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd>
@ -789,6 +788,7 @@ Default: 3</li>
</div> </div>
<div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt> <div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt>
<dd id="Databricks.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd> <dd id="Databricks.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd>
<dd id="Databricks.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="hive.html#Hive.Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Databricks.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd> <dd id="Databricks.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd>
<dd id="Databricks.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd> <dd id="Databricks.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd>
<dd id="Databricks.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd> <dd id="Databricks.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -706,7 +706,6 @@ Default: 3</li>
<dd id="Spark.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd> <dd id="Spark.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd>
<dd id="Spark.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd> <dd id="Spark.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd>
<dd id="Spark.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd> <dd id="Spark.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd>
<dd id="Spark.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="../parser.html#Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Spark.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd> <dd id="Spark.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd>
<dd id="Spark.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd> <dd id="Spark.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd>
<dd id="Spark.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd> <dd id="Spark.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd>
@ -755,6 +754,7 @@ Default: 3</li>
<div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt> <div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt>
<dd id="Spark.Parser.LOG_DEFAULTS_TO_LN" class="variable"><a href="hive.html#Hive.Parser.LOG_DEFAULTS_TO_LN">LOG_DEFAULTS_TO_LN</a></dd> <dd id="Spark.Parser.LOG_DEFAULTS_TO_LN" class="variable"><a href="hive.html#Hive.Parser.LOG_DEFAULTS_TO_LN">LOG_DEFAULTS_TO_LN</a></dd>
<dd id="Spark.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd> <dd id="Spark.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd>
<dd id="Spark.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="hive.html#Hive.Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Spark.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd> <dd id="Spark.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd>
<dd id="Spark.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd> <dd id="Spark.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd>
<dd id="Spark.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd> <dd id="Spark.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd>

View file

@ -988,7 +988,7 @@ Default: 3</li>
<div class="attr variable"> <div class="attr variable">
<span class="name">FUNCTION_PARSERS</span> = <span class="name">FUNCTION_PARSERS</span> =
<input id="Spark2.Parser.FUNCTION_PARSERS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="Spark2.Parser.FUNCTION_PARSERS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="Spark2.Parser.FUNCTION_PARSERS-view-value"></label><span class="default_value">{&#39;ANY_VALUE&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CONCAT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CONVERT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;DECODE&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;EXTRACT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;JSON_OBJECT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;LOG&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;MATCH&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;OPENJSON&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;POSITION&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;SAFE_CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;STRING_AGG&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;SUBSTRING&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRIM&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRY_CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRY_CONVERT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRANSFORM&#39;: &lt;function Hive.Parser.&lt;lambda&gt;&gt;, &#39;BROADCAST&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;BROADCASTJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MAPJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MERGE&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLEMERGE&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MERGEJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLE_HASH&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLE_REPLICATE_NL&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;}</span> <label class="view-value-button pdoc-button" for="Spark2.Parser.FUNCTION_PARSERS-view-value"></label><span class="default_value">{&#39;ANY_VALUE&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CONCAT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;CONVERT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;DECODE&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;EXTRACT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;JSON_OBJECT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;LOG&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;MATCH&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;OPENJSON&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;POSITION&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;SAFE_CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;STRING_AGG&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;SUBSTRING&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRIM&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRY_CAST&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;TRY_CONVERT&#39;: &lt;function Parser.&lt;lambda&gt;&gt;, &#39;BROADCAST&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;BROADCASTJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MAPJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MERGE&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLEMERGE&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;MERGEJOIN&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLE_HASH&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;, &#39;SHUFFLE_REPLICATE_NL&#39;: &lt;function <a href="#Spark2.Parser">Spark2.Parser</a>.&lt;lambda&gt;&gt;}</span>
</div> </div>
@ -1090,7 +1090,6 @@ Default: 3</li>
<dd id="Spark2.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd> <dd id="Spark2.Parser.CONSTRAINT_PARSERS" class="variable"><a href="../parser.html#Parser.CONSTRAINT_PARSERS">CONSTRAINT_PARSERS</a></dd>
<dd id="Spark2.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd> <dd id="Spark2.Parser.ALTER_PARSERS" class="variable"><a href="../parser.html#Parser.ALTER_PARSERS">ALTER_PARSERS</a></dd>
<dd id="Spark2.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd> <dd id="Spark2.Parser.SCHEMA_UNNAMED_CONSTRAINTS" class="variable"><a href="../parser.html#Parser.SCHEMA_UNNAMED_CONSTRAINTS">SCHEMA_UNNAMED_CONSTRAINTS</a></dd>
<dd id="Spark2.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="../parser.html#Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Spark2.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd> <dd id="Spark2.Parser.FUNCTIONS_WITH_ALIASED_ARGS" class="variable"><a href="../parser.html#Parser.FUNCTIONS_WITH_ALIASED_ARGS">FUNCTIONS_WITH_ALIASED_ARGS</a></dd>
<dd id="Spark2.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd> <dd id="Spark2.Parser.QUERY_MODIFIER_PARSERS" class="variable"><a href="../parser.html#Parser.QUERY_MODIFIER_PARSERS">QUERY_MODIFIER_PARSERS</a></dd>
<dd id="Spark2.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd> <dd id="Spark2.Parser.SET_PARSERS" class="variable"><a href="../parser.html#Parser.SET_PARSERS">SET_PARSERS</a></dd>
@ -1135,6 +1134,7 @@ Default: 3</li>
<div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt> <div><dt><a href="hive.html#Hive.Parser">sqlglot.dialects.hive.Hive.Parser</a></dt>
<dd id="Spark2.Parser.LOG_DEFAULTS_TO_LN" class="variable"><a href="hive.html#Hive.Parser.LOG_DEFAULTS_TO_LN">LOG_DEFAULTS_TO_LN</a></dd> <dd id="Spark2.Parser.LOG_DEFAULTS_TO_LN" class="variable"><a href="hive.html#Hive.Parser.LOG_DEFAULTS_TO_LN">LOG_DEFAULTS_TO_LN</a></dd>
<dd id="Spark2.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd> <dd id="Spark2.Parser.STRICT_CAST" class="variable"><a href="hive.html#Hive.Parser.STRICT_CAST">STRICT_CAST</a></dd>
<dd id="Spark2.Parser.NO_PAREN_FUNCTION_PARSERS" class="variable"><a href="hive.html#Hive.Parser.NO_PAREN_FUNCTION_PARSERS">NO_PAREN_FUNCTION_PARSERS</a></dd>
<dd id="Spark2.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd> <dd id="Spark2.Parser.PROPERTY_PARSERS" class="variable"><a href="hive.html#Hive.Parser.PROPERTY_PARSERS">PROPERTY_PARSERS</a></dd>
<dd id="Spark2.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd> <dd id="Spark2.Parser.ALIAS_POST_TABLESAMPLE" class="variable"><a href="hive.html#Hive.Parser.ALIAS_POST_TABLESAMPLE">ALIAS_POST_TABLESAMPLE</a></dd>
<dd id="Spark2.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd> <dd id="Spark2.Parser.TIME_MAPPING" class="variable"><a href="hive.html#Hive.Parser.TIME_MAPPING">TIME_MAPPING</a></dd>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -37818,7 +37818,7 @@ If an <code><a href="#Expression">Expression</a></code> instance is passed, it w
<div class="attr variable"> <div class="attr variable">
<span class="name">TEXT_TYPES</span> = <span class="name">TEXT_TYPES</span> =
<input id="DataType.TEXT_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DataType.TEXT_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DataType.TEXT_TYPES-view-value"></label><span class="default_value">{&lt;Type.VARCHAR: &#39;VARCHAR&#39;&gt;, &lt;Type.CHAR: &#39;CHAR&#39;&gt;, &lt;Type.TEXT: &#39;TEXT&#39;&gt;, &lt;Type.NVARCHAR: &#39;NVARCHAR&#39;&gt;, &lt;Type.NCHAR: &#39;NCHAR&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="DataType.TEXT_TYPES-view-value"></label><span class="default_value">{&lt;Type.NCHAR: &#39;NCHAR&#39;&gt;, &lt;Type.NVARCHAR: &#39;NVARCHAR&#39;&gt;, &lt;Type.CHAR: &#39;CHAR&#39;&gt;, &lt;Type.VARCHAR: &#39;VARCHAR&#39;&gt;, &lt;Type.TEXT: &#39;TEXT&#39;&gt;}</span>
</div> </div>
@ -37831,7 +37831,7 @@ If an <code><a href="#Expression">Expression</a></code> instance is passed, it w
<div class="attr variable"> <div class="attr variable">
<span class="name">INTEGER_TYPES</span> = <span class="name">INTEGER_TYPES</span> =
<input id="DataType.INTEGER_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DataType.INTEGER_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DataType.INTEGER_TYPES-view-value"></label><span class="default_value">{&lt;Type.SMALLINT: &#39;SMALLINT&#39;&gt;, &lt;Type.INT128: &#39;INT128&#39;&gt;, &lt;Type.INT256: &#39;INT256&#39;&gt;, &lt;Type.INT: &#39;INT&#39;&gt;, &lt;Type.BIGINT: &#39;BIGINT&#39;&gt;, &lt;Type.TINYINT: &#39;TINYINT&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="DataType.INTEGER_TYPES-view-value"></label><span class="default_value">{&lt;Type.BIGINT: &#39;BIGINT&#39;&gt;, &lt;Type.INT256: &#39;INT256&#39;&gt;, &lt;Type.INT128: &#39;INT128&#39;&gt;, &lt;Type.INT: &#39;INT&#39;&gt;, &lt;Type.SMALLINT: &#39;SMALLINT&#39;&gt;, &lt;Type.TINYINT: &#39;TINYINT&#39;&gt;}</span>
</div> </div>
@ -37843,7 +37843,7 @@ If an <code><a href="#Expression">Expression</a></code> instance is passed, it w
<div id="DataType.FLOAT_TYPES" class="classattr"> <div id="DataType.FLOAT_TYPES" class="classattr">
<div class="attr variable"> <div class="attr variable">
<span class="name">FLOAT_TYPES</span> = <span class="name">FLOAT_TYPES</span> =
<span class="default_value">{&lt;Type.FLOAT: &#39;FLOAT&#39;&gt;, &lt;Type.DOUBLE: &#39;DOUBLE&#39;&gt;}</span> <span class="default_value">{&lt;Type.DOUBLE: &#39;DOUBLE&#39;&gt;, &lt;Type.FLOAT: &#39;FLOAT&#39;&gt;}</span>
</div> </div>
@ -37856,7 +37856,7 @@ If an <code><a href="#Expression">Expression</a></code> instance is passed, it w
<div class="attr variable"> <div class="attr variable">
<span class="name">NUMERIC_TYPES</span> = <span class="name">NUMERIC_TYPES</span> =
<input id="DataType.NUMERIC_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DataType.NUMERIC_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DataType.NUMERIC_TYPES-view-value"></label><span class="default_value">{&lt;Type.FLOAT: &#39;FLOAT&#39;&gt;, &lt;Type.INT: &#39;INT&#39;&gt;, &lt;Type.DOUBLE: &#39;DOUBLE&#39;&gt;, &lt;Type.SMALLINT: &#39;SMALLINT&#39;&gt;, &lt;Type.INT256: &#39;INT256&#39;&gt;, &lt;Type.INT128: &#39;INT128&#39;&gt;, &lt;Type.BIGINT: &#39;BIGINT&#39;&gt;, &lt;Type.TINYINT: &#39;TINYINT&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="DataType.NUMERIC_TYPES-view-value"></label><span class="default_value">{&lt;Type.TINYINT: &#39;TINYINT&#39;&gt;, &lt;Type.INT: &#39;INT&#39;&gt;, &lt;Type.BIGINT: &#39;BIGINT&#39;&gt;, &lt;Type.SMALLINT: &#39;SMALLINT&#39;&gt;, &lt;Type.FLOAT: &#39;FLOAT&#39;&gt;, &lt;Type.INT256: &#39;INT256&#39;&gt;, &lt;Type.INT128: &#39;INT128&#39;&gt;, &lt;Type.DOUBLE: &#39;DOUBLE&#39;&gt;}</span>
</div> </div>
@ -37869,7 +37869,7 @@ If an <code><a href="#Expression">Expression</a></code> instance is passed, it w
<div class="attr variable"> <div class="attr variable">
<span class="name">TEMPORAL_TYPES</span> = <span class="name">TEMPORAL_TYPES</span> =
<input id="DataType.TEMPORAL_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DataType.TEMPORAL_TYPES-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DataType.TEMPORAL_TYPES-view-value"></label><span class="default_value">{&lt;Type.TIMESTAMPTZ: &#39;TIMESTAMPTZ&#39;&gt;, &lt;Type.TIMESTAMPLTZ: &#39;TIMESTAMPLTZ&#39;&gt;, &lt;Type.TIME: &#39;TIME&#39;&gt;, &lt;Type.DATETIME64: &#39;DATETIME64&#39;&gt;, &lt;Type.DATE: &#39;DATE&#39;&gt;, &lt;Type.DATETIME: &#39;DATETIME&#39;&gt;, &lt;Type.TIMESTAMP: &#39;TIMESTAMP&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="DataType.TEMPORAL_TYPES-view-value"></label><span class="default_value">{&lt;Type.DATE: &#39;DATE&#39;&gt;, &lt;Type.TIME: &#39;TIME&#39;&gt;, &lt;Type.DATETIME: &#39;DATETIME&#39;&gt;, &lt;Type.TIMESTAMPLTZ: &#39;TIMESTAMPLTZ&#39;&gt;, &lt;Type.DATETIME64: &#39;DATETIME64&#39;&gt;, &lt;Type.TIMESTAMPTZ: &#39;TIMESTAMPTZ&#39;&gt;, &lt;Type.TIMESTAMP: &#39;TIMESTAMP&#39;&gt;}</span>
</div> </div>

File diff suppressed because one or more lines are too long

View file

@ -568,7 +568,7 @@ queries if it would result in multiple table selects in a single query:</p>
<div class="attr variable"> <div class="attr variable">
<span class="name">UNMERGABLE_ARGS</span> = <span class="name">UNMERGABLE_ARGS</span> =
<input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;group&#39;, &#39;sample&#39;, &#39;sort&#39;, &#39;pivots&#39;, &#39;with&#39;, &#39;into&#39;, &#39;format&#39;, &#39;offset&#39;, &#39;settings&#39;, &#39;distribute&#39;, &#39;having&#39;, &#39;windows&#39;, &#39;cluster&#39;, &#39;distinct&#39;, &#39;match&#39;, &#39;locks&#39;, &#39;limit&#39;, &#39;kind&#39;, &#39;laterals&#39;, &#39;qualify&#39;}</span> <label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;sample&#39;, &#39;distribute&#39;, &#39;group&#39;, &#39;into&#39;, &#39;kind&#39;, &#39;settings&#39;, &#39;format&#39;, &#39;offset&#39;, &#39;windows&#39;, &#39;pivots&#39;, &#39;qualify&#39;, &#39;having&#39;, &#39;distinct&#39;, &#39;with&#39;, &#39;limit&#39;, &#39;locks&#39;, &#39;laterals&#39;, &#39;cluster&#39;, &#39;sort&#39;, &#39;match&#39;}</span>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -60,6 +60,7 @@ from sqlglot.dialects.bigquery import BigQuery
from sqlglot.dialects.clickhouse import ClickHouse from sqlglot.dialects.clickhouse import ClickHouse
from sqlglot.dialects.databricks import Databricks from sqlglot.dialects.databricks import Databricks
from sqlglot.dialects.dialect import Dialect, Dialects from sqlglot.dialects.dialect import Dialect, Dialects
from sqlglot.dialects.doris import Doris
from sqlglot.dialects.drill import Drill from sqlglot.dialects.drill import Drill
from sqlglot.dialects.duckdb import DuckDB from sqlglot.dialects.duckdb import DuckDB
from sqlglot.dialects.hive import Hive from sqlglot.dialects.hive import Hive

View file

@ -37,17 +37,22 @@ class ClickHouse(Dialect):
"ATTACH": TokenType.COMMAND, "ATTACH": TokenType.COMMAND,
"DATETIME64": TokenType.DATETIME64, "DATETIME64": TokenType.DATETIME64,
"DICTIONARY": TokenType.DICTIONARY, "DICTIONARY": TokenType.DICTIONARY,
"ENUM": TokenType.ENUM,
"ENUM8": TokenType.ENUM8,
"ENUM16": TokenType.ENUM16,
"FINAL": TokenType.FINAL, "FINAL": TokenType.FINAL,
"FIXEDSTRING": TokenType.FIXEDSTRING,
"FLOAT32": TokenType.FLOAT, "FLOAT32": TokenType.FLOAT,
"FLOAT64": TokenType.DOUBLE, "FLOAT64": TokenType.DOUBLE,
"GLOBAL": TokenType.GLOBAL, "GLOBAL": TokenType.GLOBAL,
"INT128": TokenType.INT128,
"INT16": TokenType.SMALLINT, "INT16": TokenType.SMALLINT,
"INT256": TokenType.INT256, "INT256": TokenType.INT256,
"INT32": TokenType.INT, "INT32": TokenType.INT,
"INT64": TokenType.BIGINT, "INT64": TokenType.BIGINT,
"INT8": TokenType.TINYINT, "INT8": TokenType.TINYINT,
"LOWCARDINALITY": TokenType.LOWCARDINALITY,
"MAP": TokenType.MAP, "MAP": TokenType.MAP,
"NESTED": TokenType.NESTED,
"TUPLE": TokenType.STRUCT, "TUPLE": TokenType.STRUCT,
"UINT128": TokenType.UINT128, "UINT128": TokenType.UINT128,
"UINT16": TokenType.USMALLINT, "UINT16": TokenType.USMALLINT,
@ -294,11 +299,17 @@ class ClickHouse(Dialect):
exp.DataType.Type.BIGINT: "Int64", exp.DataType.Type.BIGINT: "Int64",
exp.DataType.Type.DATETIME64: "DateTime64", exp.DataType.Type.DATETIME64: "DateTime64",
exp.DataType.Type.DOUBLE: "Float64", exp.DataType.Type.DOUBLE: "Float64",
exp.DataType.Type.ENUM: "Enum",
exp.DataType.Type.ENUM8: "Enum8",
exp.DataType.Type.ENUM16: "Enum16",
exp.DataType.Type.FIXEDSTRING: "FixedString",
exp.DataType.Type.FLOAT: "Float32", exp.DataType.Type.FLOAT: "Float32",
exp.DataType.Type.INT: "Int32", exp.DataType.Type.INT: "Int32",
exp.DataType.Type.INT128: "Int128", exp.DataType.Type.INT128: "Int128",
exp.DataType.Type.INT256: "Int256", exp.DataType.Type.INT256: "Int256",
exp.DataType.Type.LOWCARDINALITY: "LowCardinality",
exp.DataType.Type.MAP: "Map", exp.DataType.Type.MAP: "Map",
exp.DataType.Type.NESTED: "Nested",
exp.DataType.Type.NULLABLE: "Nullable", exp.DataType.Type.NULLABLE: "Nullable",
exp.DataType.Type.SMALLINT: "Int16", exp.DataType.Type.SMALLINT: "Int16",
exp.DataType.Type.STRUCT: "Tuple", exp.DataType.Type.STRUCT: "Tuple",

View file

@ -39,6 +39,7 @@ class Dialects(str, Enum):
TERADATA = "teradata" TERADATA = "teradata"
TRINO = "trino" TRINO = "trino"
TSQL = "tsql" TSQL = "tsql"
Doris = "doris"
class _Dialect(type): class _Dialect(type):
@ -121,7 +122,7 @@ class _Dialect(type):
if hasattr(subclass, name): if hasattr(subclass, name):
setattr(subclass, name, value) setattr(subclass, name, value)
if not klass.STRICT_STRING_CONCAT: if not klass.STRICT_STRING_CONCAT and klass.DPIPE_IS_STRING_CONCAT:
klass.parser_class.BITWISE[TokenType.DPIPE] = exp.SafeDPipe klass.parser_class.BITWISE[TokenType.DPIPE] = exp.SafeDPipe
klass.generator_class.can_identify = klass.can_identify klass.generator_class.can_identify = klass.can_identify
@ -146,6 +147,9 @@ class Dialect(metaclass=_Dialect):
# Determines whether or not an unquoted identifier can start with a digit # Determines whether or not an unquoted identifier can start with a digit
IDENTIFIERS_CAN_START_WITH_DIGIT = False IDENTIFIERS_CAN_START_WITH_DIGIT = False
# Determines whether or not the DPIPE token ('||') is a string concatenation operator
DPIPE_IS_STRING_CONCAT = True
# Determines whether or not CONCAT's arguments must be strings # Determines whether or not CONCAT's arguments must be strings
STRICT_STRING_CONCAT = False STRICT_STRING_CONCAT = False
@ -460,6 +464,20 @@ def format_time_lambda(
return _format_time return _format_time
def time_format(
dialect: DialectType = None,
) -> t.Callable[[Generator, exp.UnixToStr | exp.StrToUnix], t.Optional[str]]:
def _time_format(self: Generator, expression: exp.UnixToStr | exp.StrToUnix) -> t.Optional[str]:
"""
Returns the time format for a given expression, unless it's equivalent
to the default time format of the dialect of interest.
"""
time_format = self.format_time(expression)
return time_format if time_format != Dialect.get_or_raise(dialect).TIME_FORMAT else None
return _time_format
def create_with_partitions_sql(self: Generator, expression: exp.Create) -> str: def create_with_partitions_sql(self: Generator, expression: exp.Create) -> str:
""" """
In Hive and Spark, the PARTITIONED BY property acts as an extension of a table's schema. When the In Hive and Spark, the PARTITIONED BY property acts as an extension of a table's schema. When the
@ -699,3 +717,8 @@ def simplify_literal(expression: E) -> E:
def binary_from_function(expr_type: t.Type[B]) -> t.Callable[[t.List], B]: def binary_from_function(expr_type: t.Type[B]) -> t.Callable[[t.List], B]:
return lambda args: expr_type(this=seq_get(args, 0), expression=seq_get(args, 1)) return lambda args: expr_type(this=seq_get(args, 0), expression=seq_get(args, 1))
# Used to represent DATE_TRUNC in Doris, Postgres and Starrocks dialects
def parse_timestamp_trunc(args: t.List) -> exp.TimestampTrunc:
return exp.TimestampTrunc(this=seq_get(args, 1), unit=seq_get(args, 0))

65
sqlglot/dialects/doris.py Normal file
View file

@ -0,0 +1,65 @@
from __future__ import annotations
from sqlglot import exp
from sqlglot.dialects.dialect import (
approx_count_distinct_sql,
arrow_json_extract_sql,
parse_timestamp_trunc,
rename_func,
time_format,
)
from sqlglot.dialects.mysql import MySQL
class Doris(MySQL):
DATE_FORMAT = "'yyyy-MM-dd'"
DATEINT_FORMAT = "'yyyyMMdd'"
TIME_FORMAT = "'yyyy-MM-dd HH:mm:ss'"
class Parser(MySQL.Parser):
FUNCTIONS = {
**MySQL.Parser.FUNCTIONS,
"DATE_TRUNC": parse_timestamp_trunc,
"REGEXP": exp.RegexpLike.from_arg_list,
}
class Generator(MySQL.Generator):
CAST_MAPPING = {}
TYPE_MAPPING = {
**MySQL.Generator.TYPE_MAPPING,
exp.DataType.Type.TEXT: "STRING",
exp.DataType.Type.TIMESTAMP: "DATETIME",
exp.DataType.Type.TIMESTAMPTZ: "DATETIME",
}
TRANSFORMS = {
**MySQL.Generator.TRANSFORMS,
exp.ApproxDistinct: approx_count_distinct_sql,
exp.ArrayAgg: rename_func("COLLECT_LIST"),
exp.Coalesce: rename_func("NVL"),
exp.CurrentTimestamp: lambda *_: "NOW()",
exp.DateTrunc: lambda self, e: self.func(
"DATE_TRUNC", e.this, "'" + e.text("unit") + "'"
),
exp.JSONExtractScalar: arrow_json_extract_sql,
exp.JSONExtract: arrow_json_extract_sql,
exp.RegexpLike: rename_func("REGEXP"),
exp.RegexpSplit: rename_func("SPLIT_BY_STRING"),
exp.SetAgg: rename_func("COLLECT_SET"),
exp.StrToUnix: lambda self, e: f"UNIX_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})",
exp.Split: rename_func("SPLIT_BY_STRING"),
exp.TimeStrToDate: rename_func("TO_DATE"),
exp.ToChar: lambda self, e: f"DATE_FORMAT({self.sql(e, 'this')}, {self.format_time(e)})",
exp.TsOrDsAdd: lambda self, e: f"DATE_ADD({self.sql(e, 'this')}, {self.sql(e, 'expression')})", # Only for day level
exp.TsOrDsToDate: lambda self, e: self.func("TO_DATE", e.this),
exp.TimeToUnix: rename_func("UNIX_TIMESTAMP"),
exp.TimestampTrunc: lambda self, e: self.func(
"DATE_TRUNC", e.this, "'" + e.text("unit") + "'"
),
exp.UnixToStr: lambda self, e: self.func(
"FROM_UNIXTIME", e.this, time_format("doris")(self, e)
),
exp.UnixToTime: rename_func("FROM_UNIXTIME"),
exp.Map: rename_func("ARRAY_MAP"),
}

View file

@ -89,6 +89,11 @@ def _struct_sql(self: generator.Generator, expression: exp.Struct) -> str:
def _datatype_sql(self: generator.Generator, expression: exp.DataType) -> str: def _datatype_sql(self: generator.Generator, expression: exp.DataType) -> str:
if expression.is_type("array"): if expression.is_type("array"):
return f"{self.expressions(expression, flat=True)}[]" return f"{self.expressions(expression, flat=True)}[]"
# Type TIMESTAMP / TIME WITH TIME ZONE does not support any modifiers
if expression.is_type("timestamptz", "timetz"):
return expression.this.value
return self.datatype_sql(expression) return self.datatype_sql(expression)
@ -110,14 +115,14 @@ class DuckDB(Dialect):
"//": TokenType.DIV, "//": TokenType.DIV,
"ATTACH": TokenType.COMMAND, "ATTACH": TokenType.COMMAND,
"BINARY": TokenType.VARBINARY, "BINARY": TokenType.VARBINARY,
"BPCHAR": TokenType.TEXT,
"BITSTRING": TokenType.BIT, "BITSTRING": TokenType.BIT,
"BPCHAR": TokenType.TEXT,
"CHAR": TokenType.TEXT, "CHAR": TokenType.TEXT,
"CHARACTER VARYING": TokenType.TEXT, "CHARACTER VARYING": TokenType.TEXT,
"EXCLUDE": TokenType.EXCEPT, "EXCLUDE": TokenType.EXCEPT,
"HUGEINT": TokenType.INT128,
"INT1": TokenType.TINYINT, "INT1": TokenType.TINYINT,
"LOGICAL": TokenType.BOOLEAN, "LOGICAL": TokenType.BOOLEAN,
"NUMERIC": TokenType.DOUBLE,
"PIVOT_WIDER": TokenType.PIVOT, "PIVOT_WIDER": TokenType.PIVOT,
"SIGNED": TokenType.INT, "SIGNED": TokenType.INT,
"STRING": TokenType.VARCHAR, "STRING": TokenType.VARCHAR,
@ -186,6 +191,22 @@ class DuckDB(Dialect):
TokenType.UTINYINT, TokenType.UTINYINT,
} }
def _parse_types(
self, check_func: bool = False, schema: bool = False
) -> t.Optional[exp.Expression]:
this = super()._parse_types(check_func=check_func, schema=schema)
# DuckDB treats NUMERIC and DECIMAL without precision as DECIMAL(18, 3)
# See: https://duckdb.org/docs/sql/data_types/numeric
if (
isinstance(this, exp.DataType)
and this.is_type("numeric", "decimal")
and not this.expressions
):
return exp.DataType.build("DECIMAL(18, 3)")
return this
def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]: def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
if len(aggregations) == 1: if len(aggregations) == 1:
return super()._pivot_column_names(aggregations) return super()._pivot_column_names(aggregations)
@ -231,6 +252,7 @@ class DuckDB(Dialect):
exp.Encode: lambda self, e: encode_decode_sql(self, e, "ENCODE", replace=False), exp.Encode: lambda self, e: encode_decode_sql(self, e, "ENCODE", replace=False),
exp.Explode: rename_func("UNNEST"), exp.Explode: rename_func("UNNEST"),
exp.IntDiv: lambda self, e: self.binary(e, "//"), exp.IntDiv: lambda self, e: self.binary(e, "//"),
exp.IsNan: rename_func("ISNAN"),
exp.JSONExtract: arrow_json_extract_sql, exp.JSONExtract: arrow_json_extract_sql,
exp.JSONExtractScalar: arrow_json_extract_scalar_sql, exp.JSONExtractScalar: arrow_json_extract_scalar_sql,
exp.JSONFormat: _json_format_sql, exp.JSONFormat: _json_format_sql,

View file

@ -23,6 +23,7 @@ from sqlglot.dialects.dialect import (
right_to_substring_sql, right_to_substring_sql,
strposition_to_locate_sql, strposition_to_locate_sql,
struct_extract_sql, struct_extract_sql,
time_format,
timestrtotime_sql, timestrtotime_sql,
var_map_sql, var_map_sql,
) )
@ -113,7 +114,7 @@ def _property_sql(self: generator.Generator, expression: exp.Property) -> str:
def _str_to_unix_sql(self: generator.Generator, expression: exp.StrToUnix) -> str: def _str_to_unix_sql(self: generator.Generator, expression: exp.StrToUnix) -> str:
return self.func("UNIX_TIMESTAMP", expression.this, _time_format(self, expression)) return self.func("UNIX_TIMESTAMP", expression.this, time_format("hive")(self, expression))
def _str_to_date_sql(self: generator.Generator, expression: exp.StrToDate) -> str: def _str_to_date_sql(self: generator.Generator, expression: exp.StrToDate) -> str:
@ -132,15 +133,6 @@ def _str_to_time_sql(self: generator.Generator, expression: exp.StrToTime) -> st
return f"CAST({this} AS TIMESTAMP)" return f"CAST({this} AS TIMESTAMP)"
def _time_format(
self: generator.Generator, expression: exp.UnixToStr | exp.StrToUnix
) -> t.Optional[str]:
time_format = self.format_time(expression)
if time_format == Hive.TIME_FORMAT:
return None
return time_format
def _time_to_str(self: generator.Generator, expression: exp.TimeToStr) -> str: def _time_to_str(self: generator.Generator, expression: exp.TimeToStr) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
time_format = self.format_time(expression) time_format = self.format_time(expression)
@ -439,7 +431,7 @@ class Hive(Dialect):
exp.TsOrDsToDate: _to_date_sql, exp.TsOrDsToDate: _to_date_sql,
exp.TryCast: no_trycast_sql, exp.TryCast: no_trycast_sql,
exp.UnixToStr: lambda self, e: self.func( exp.UnixToStr: lambda self, e: self.func(
"FROM_UNIXTIME", e.this, _time_format(self, e) "FROM_UNIXTIME", e.this, time_format("hive")(self, e)
), ),
exp.UnixToTime: rename_func("FROM_UNIXTIME"), exp.UnixToTime: rename_func("FROM_UNIXTIME"),
exp.UnixToTimeStr: rename_func("FROM_UNIXTIME"), exp.UnixToTimeStr: rename_func("FROM_UNIXTIME"),

View file

@ -94,6 +94,7 @@ def _date_add_sql(kind: str) -> t.Callable[[generator.Generator, exp.DateAdd | e
class MySQL(Dialect): class MySQL(Dialect):
TIME_FORMAT = "'%Y-%m-%d %T'" TIME_FORMAT = "'%Y-%m-%d %T'"
DPIPE_IS_STRING_CONCAT = False
# https://prestodb.io/docs/current/functions/datetime.html#mysql-date-functions # https://prestodb.io/docs/current/functions/datetime.html#mysql-date-functions
TIME_MAPPING = { TIME_MAPPING = {
@ -103,7 +104,6 @@ class MySQL(Dialect):
"%h": "%I", "%h": "%I",
"%i": "%M", "%i": "%M",
"%s": "%S", "%s": "%S",
"%S": "%S",
"%u": "%W", "%u": "%W",
"%k": "%-H", "%k": "%-H",
"%l": "%-I", "%l": "%-I",
@ -196,8 +196,14 @@ class MySQL(Dialect):
**parser.Parser.CONJUNCTION, **parser.Parser.CONJUNCTION,
TokenType.DAMP: exp.And, TokenType.DAMP: exp.And,
TokenType.XOR: exp.Xor, TokenType.XOR: exp.Xor,
TokenType.DPIPE: exp.Or,
} }
# MySQL uses || as a synonym to the logical OR operator
# https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_or
BITWISE = parser.Parser.BITWISE.copy()
BITWISE.pop(TokenType.DPIPE)
TABLE_ALIAS_TOKENS = ( TABLE_ALIAS_TOKENS = (
parser.Parser.TABLE_ALIAS_TOKENS - parser.Parser.TABLE_INDEX_HINT_TOKENS parser.Parser.TABLE_ALIAS_TOKENS - parser.Parser.TABLE_INDEX_HINT_TOKENS
) )

View file

@ -16,6 +16,7 @@ from sqlglot.dialects.dialect import (
no_pivot_sql, no_pivot_sql,
no_tablesample_sql, no_tablesample_sql,
no_trycast_sql, no_trycast_sql,
parse_timestamp_trunc,
rename_func, rename_func,
simplify_literal, simplify_literal,
str_position_sql, str_position_sql,
@ -286,9 +287,7 @@ class Postgres(Dialect):
FUNCTIONS = { FUNCTIONS = {
**parser.Parser.FUNCTIONS, **parser.Parser.FUNCTIONS,
"DATE_TRUNC": lambda args: exp.TimestampTrunc( "DATE_TRUNC": parse_timestamp_trunc,
this=seq_get(args, 1), unit=seq_get(args, 0)
),
"GENERATE_SERIES": _generate_series, "GENERATE_SERIES": _generate_series,
"NOW": exp.CurrentTimestamp.from_arg_list, "NOW": exp.CurrentTimestamp.from_arg_list,
"TO_CHAR": format_time_lambda(exp.TimeToStr, "postgres"), "TO_CHAR": format_time_lambda(exp.TimeToStr, "postgres"),

View file

@ -32,13 +32,6 @@ def _approx_distinct_sql(self: generator.Generator, expression: exp.ApproxDistin
return f"APPROX_DISTINCT({self.sql(expression, 'this')}{accuracy})" return f"APPROX_DISTINCT({self.sql(expression, 'this')}{accuracy})"
def _datatype_sql(self: generator.Generator, expression: exp.DataType) -> str:
sql = self.datatype_sql(expression)
if expression.is_type("timestamptz"):
sql = f"{sql} WITH TIME ZONE"
return sql
def _explode_to_unnest_sql(self: generator.Generator, expression: exp.Lateral) -> str: def _explode_to_unnest_sql(self: generator.Generator, expression: exp.Lateral) -> str:
if isinstance(expression.this, (exp.Explode, exp.Posexplode)): if isinstance(expression.this, (exp.Explode, exp.Posexplode)):
expression = expression.copy() expression = expression.copy()
@ -231,6 +224,7 @@ class Presto(Dialect):
TABLE_HINTS = False TABLE_HINTS = False
QUERY_HINTS = False QUERY_HINTS = False
IS_BOOL_ALLOWED = False IS_BOOL_ALLOWED = False
TZ_TO_WITH_TIME_ZONE = True
STRUCT_DELIMITER = ("(", ")") STRUCT_DELIMITER = ("(", ")")
PROPERTIES_LOCATION = { PROPERTIES_LOCATION = {
@ -245,6 +239,7 @@ class Presto(Dialect):
exp.DataType.Type.FLOAT: "REAL", exp.DataType.Type.FLOAT: "REAL",
exp.DataType.Type.BINARY: "VARBINARY", exp.DataType.Type.BINARY: "VARBINARY",
exp.DataType.Type.TEXT: "VARCHAR", exp.DataType.Type.TEXT: "VARCHAR",
exp.DataType.Type.TIMETZ: "TIME",
exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP", exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
exp.DataType.Type.STRUCT: "ROW", exp.DataType.Type.STRUCT: "ROW",
} }
@ -265,7 +260,6 @@ class Presto(Dialect):
exp.BitwiseXor: lambda self, e: f"BITWISE_XOR({self.sql(e, 'this')}, {self.sql(e, 'expression')})", exp.BitwiseXor: lambda self, e: f"BITWISE_XOR({self.sql(e, 'this')}, {self.sql(e, 'expression')})",
exp.Cast: transforms.preprocess([transforms.epoch_cast_to_ts]), exp.Cast: transforms.preprocess([transforms.epoch_cast_to_ts]),
exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP", exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP",
exp.DataType: _datatype_sql,
exp.DateAdd: lambda self, e: self.func( exp.DateAdd: lambda self, e: self.func(
"DATE_ADD", exp.Literal.string(e.text("unit") or "day"), e.expression, e.this "DATE_ADD", exp.Literal.string(e.text("unit") or "day"), e.expression, e.this
), ),

View file

@ -85,8 +85,6 @@ class Redshift(Postgres):
"HLLSKETCH": TokenType.HLLSKETCH, "HLLSKETCH": TokenType.HLLSKETCH,
"SUPER": TokenType.SUPER, "SUPER": TokenType.SUPER,
"SYSDATE": TokenType.CURRENT_TIMESTAMP, "SYSDATE": TokenType.CURRENT_TIMESTAMP,
"TIME": TokenType.TIMESTAMP,
"TIMETZ": TokenType.TIMESTAMPTZ,
"TOP": TokenType.TOP, "TOP": TokenType.TOP,
"UNLOAD": TokenType.COMMAND, "UNLOAD": TokenType.COMMAND,
"VARBYTE": TokenType.VARBINARY, "VARBYTE": TokenType.VARBINARY,
@ -101,12 +99,15 @@ class Redshift(Postgres):
RENAME_TABLE_WITH_DB = False RENAME_TABLE_WITH_DB = False
QUERY_HINTS = False QUERY_HINTS = False
VALUES_AS_TABLE = False VALUES_AS_TABLE = False
TZ_TO_WITH_TIME_ZONE = True
TYPE_MAPPING = { TYPE_MAPPING = {
**Postgres.Generator.TYPE_MAPPING, **Postgres.Generator.TYPE_MAPPING,
exp.DataType.Type.BINARY: "VARBYTE", exp.DataType.Type.BINARY: "VARBYTE",
exp.DataType.Type.VARBINARY: "VARBYTE",
exp.DataType.Type.INT: "INTEGER", exp.DataType.Type.INT: "INTEGER",
exp.DataType.Type.TIMETZ: "TIME",
exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
exp.DataType.Type.VARBINARY: "VARBYTE",
} }
PROPERTIES_LOCATION = { PROPERTIES_LOCATION = {

View file

@ -52,6 +52,9 @@ class Spark(Spark2):
TRANSFORMS = { TRANSFORMS = {
**Spark2.Generator.TRANSFORMS, **Spark2.Generator.TRANSFORMS,
exp.StartsWith: rename_func("STARTSWITH"), exp.StartsWith: rename_func("STARTSWITH"),
exp.TimestampAdd: lambda self, e: self.func(
"DATEADD", e.args.get("unit") or "DAY", e.expression, e.this
),
} }
TRANSFORMS.pop(exp.DateDiff) TRANSFORMS.pop(exp.DateDiff)
TRANSFORMS.pop(exp.Group) TRANSFORMS.pop(exp.Group)

View file

@ -4,6 +4,7 @@ from sqlglot import exp
from sqlglot.dialects.dialect import ( from sqlglot.dialects.dialect import (
approx_count_distinct_sql, approx_count_distinct_sql,
arrow_json_extract_sql, arrow_json_extract_sql,
parse_timestamp_trunc,
rename_func, rename_func,
) )
from sqlglot.dialects.mysql import MySQL from sqlglot.dialects.mysql import MySQL
@ -14,9 +15,7 @@ class StarRocks(MySQL):
class Parser(MySQL.Parser): class Parser(MySQL.Parser):
FUNCTIONS = { FUNCTIONS = {
**MySQL.Parser.FUNCTIONS, **MySQL.Parser.FUNCTIONS,
"DATE_TRUNC": lambda args: exp.TimestampTrunc( "DATE_TRUNC": parse_timestamp_trunc,
this=seq_get(args, 1), unit=seq_get(args, 0)
),
"DATEDIFF": lambda args: exp.DateDiff( "DATEDIFF": lambda args: exp.DateDiff(
this=seq_get(args, 0), expression=seq_get(args, 1), unit=exp.Literal.string("DAY") this=seq_get(args, 0), expression=seq_get(args, 1), unit=exp.Literal.string("DAY")
), ),

View file

@ -28,6 +28,11 @@ if t.TYPE_CHECKING:
from sqlglot.schema import Schema from sqlglot.schema import Schema
PYTHON_TYPE_TO_SQLGLOT = {
"dict": "MAP",
}
def execute( def execute(
sql: str | Expression, sql: str | Expression,
schema: t.Optional[t.Dict | Schema] = None, schema: t.Optional[t.Dict | Schema] = None,
@ -50,7 +55,7 @@ def execute(
Returns: Returns:
Simple columnar data structure. Simple columnar data structure.
""" """
tables_ = ensure_tables(tables) tables_ = ensure_tables(tables, dialect=read)
if not schema: if not schema:
schema = {} schema = {}
@ -61,7 +66,8 @@ def execute(
assert table is not None assert table is not None
for column in table.columns: for column in table.columns:
nested_set(schema, [*keys, column], type(table[0][column]).__name__) py_type = type(table[0][column]).__name__
nested_set(schema, [*keys, column], PYTHON_TYPE_TO_SQLGLOT.get(py_type) or py_type)
schema = ensure_schema(schema, dialect=read) schema = ensure_schema(schema, dialect=read)

View file

@ -2,8 +2,9 @@ from __future__ import annotations
import typing as t import typing as t
from sqlglot.dialects.dialect import DialectType
from sqlglot.helper import dict_depth from sqlglot.helper import dict_depth
from sqlglot.schema import AbstractMappingSchema from sqlglot.schema import AbstractMappingSchema, normalize_name
class Table: class Table:
@ -108,26 +109,37 @@ class Tables(AbstractMappingSchema[Table]):
pass pass
def ensure_tables(d: t.Optional[t.Dict]) -> Tables: def ensure_tables(d: t.Optional[t.Dict], dialect: DialectType = None) -> Tables:
return Tables(_ensure_tables(d)) return Tables(_ensure_tables(d, dialect=dialect))
def _ensure_tables(d: t.Optional[t.Dict]) -> t.Dict: def _ensure_tables(d: t.Optional[t.Dict], dialect: DialectType = None) -> t.Dict:
if not d: if not d:
return {} return {}
depth = dict_depth(d) depth = dict_depth(d)
if depth > 1: if depth > 1:
return {k: _ensure_tables(v) for k, v in d.items()} return {
normalize_name(k, dialect=dialect, is_table=True): _ensure_tables(v, dialect=dialect)
for k, v in d.items()
}
result = {} result = {}
for name, table in d.items(): for table_name, table in d.items():
table_name = normalize_name(table_name, dialect=dialect)
if isinstance(table, Table): if isinstance(table, Table):
result[name] = table result[table_name] = table
else: else:
columns = tuple(table[0]) if table else () table = [
rows = [tuple(row[c] for c in columns) for row in table] {
result[name] = Table(columns=columns, rows=rows) normalize_name(column_name, dialect=dialect): value
for column_name, value in row.items()
}
for row in table
]
column_names = tuple(column_name for column_name in table[0]) if table else ()
rows = [tuple(row[name] for name in column_names) for row in table]
result[table_name] = Table(columns=column_names, rows=rows)
return result return result

View file

@ -3309,6 +3309,7 @@ class Pivot(Expression):
"using": False, "using": False,
"group": False, "group": False,
"columns": False, "columns": False,
"include_nulls": False,
} }
@ -3397,23 +3398,16 @@ class DataType(Expression):
BOOLEAN = auto() BOOLEAN = auto()
CHAR = auto() CHAR = auto()
DATE = auto() DATE = auto()
DATEMULTIRANGE = auto()
DATERANGE = auto()
DATETIME = auto() DATETIME = auto()
DATETIME64 = auto() DATETIME64 = auto()
ENUM = auto()
INT4RANGE = auto()
INT4MULTIRANGE = auto()
INT8RANGE = auto()
INT8MULTIRANGE = auto()
NUMRANGE = auto()
NUMMULTIRANGE = auto()
TSRANGE = auto()
TSMULTIRANGE = auto()
TSTZRANGE = auto()
TSTZMULTIRANGE = auto()
DATERANGE = auto()
DATEMULTIRANGE = auto()
DECIMAL = auto() DECIMAL = auto()
DOUBLE = auto() DOUBLE = auto()
ENUM = auto()
ENUM8 = auto()
ENUM16 = auto()
FIXEDSTRING = auto()
FLOAT = auto() FLOAT = auto()
GEOGRAPHY = auto() GEOGRAPHY = auto()
GEOMETRY = auto() GEOMETRY = auto()
@ -3421,23 +3415,31 @@ class DataType(Expression):
HSTORE = auto() HSTORE = auto()
IMAGE = auto() IMAGE = auto()
INET = auto() INET = auto()
IPADDRESS = auto()
IPPREFIX = auto()
INT = auto() INT = auto()
INT128 = auto() INT128 = auto()
INT256 = auto() INT256 = auto()
INT4MULTIRANGE = auto()
INT4RANGE = auto()
INT8MULTIRANGE = auto()
INT8RANGE = auto()
INTERVAL = auto() INTERVAL = auto()
IPADDRESS = auto()
IPPREFIX = auto()
JSON = auto() JSON = auto()
JSONB = auto() JSONB = auto()
LONGBLOB = auto() LONGBLOB = auto()
LONGTEXT = auto() LONGTEXT = auto()
LOWCARDINALITY = auto()
MAP = auto() MAP = auto()
MEDIUMBLOB = auto() MEDIUMBLOB = auto()
MEDIUMTEXT = auto() MEDIUMTEXT = auto()
MONEY = auto() MONEY = auto()
NCHAR = auto() NCHAR = auto()
NESTED = auto()
NULL = auto() NULL = auto()
NULLABLE = auto() NULLABLE = auto()
NUMMULTIRANGE = auto()
NUMRANGE = auto()
NVARCHAR = auto() NVARCHAR = auto()
OBJECT = auto() OBJECT = auto()
ROWVERSION = auto() ROWVERSION = auto()
@ -3450,19 +3452,24 @@ class DataType(Expression):
SUPER = auto() SUPER = auto()
TEXT = auto() TEXT = auto()
TIME = auto() TIME = auto()
TIMETZ = auto()
TIMESTAMP = auto() TIMESTAMP = auto()
TIMESTAMPTZ = auto()
TIMESTAMPLTZ = auto() TIMESTAMPLTZ = auto()
TIMESTAMPTZ = auto()
TINYINT = auto() TINYINT = auto()
TSMULTIRANGE = auto()
TSRANGE = auto()
TSTZMULTIRANGE = auto()
TSTZRANGE = auto()
UBIGINT = auto() UBIGINT = auto()
UINT = auto() UINT = auto()
USMALLINT = auto()
UTINYINT = auto()
UNKNOWN = auto() # Sentinel value, useful for type annotation
UINT128 = auto() UINT128 = auto()
UINT256 = auto() UINT256 = auto()
UNIQUEIDENTIFIER = auto() UNIQUEIDENTIFIER = auto()
UNKNOWN = auto() # Sentinel value, useful for type annotation
USERDEFINED = "USER-DEFINED" USERDEFINED = "USER-DEFINED"
USMALLINT = auto()
UTINYINT = auto()
UUID = auto() UUID = auto()
VARBINARY = auto() VARBINARY = auto()
VARCHAR = auto() VARCHAR = auto()
@ -3495,6 +3502,7 @@ class DataType(Expression):
TEMPORAL_TYPES = { TEMPORAL_TYPES = {
Type.TIME, Type.TIME,
Type.TIMETZ,
Type.TIMESTAMP, Type.TIMESTAMP,
Type.TIMESTAMPTZ, Type.TIMESTAMPTZ,
Type.TIMESTAMPLTZ, Type.TIMESTAMPLTZ,
@ -3858,6 +3866,18 @@ class TimeUnit(Expression):
super().__init__(**args) super().__init__(**args)
# https://www.oracletutorial.com/oracle-basics/oracle-interval/
# https://trino.io/docs/current/language/types.html#interval-year-to-month
class IntervalYearToMonthSpan(Expression):
arg_types = {}
# https://www.oracletutorial.com/oracle-basics/oracle-interval/
# https://trino.io/docs/current/language/types.html#interval-day-to-second
class IntervalDayToSecondSpan(Expression):
arg_types = {}
class Interval(TimeUnit): class Interval(TimeUnit):
arg_types = {"this": False, "unit": False} arg_types = {"this": False, "unit": False}

View file

@ -71,6 +71,8 @@ class Generator:
exp.ExternalProperty: lambda self, e: "EXTERNAL", exp.ExternalProperty: lambda self, e: "EXTERNAL",
exp.HeapProperty: lambda self, e: "HEAP", exp.HeapProperty: lambda self, e: "HEAP",
exp.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}", exp.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}",
exp.IntervalDayToSecondSpan: "DAY TO SECOND",
exp.IntervalYearToMonthSpan: "YEAR TO MONTH",
exp.LanguageProperty: lambda self, e: self.naked_property(e), exp.LanguageProperty: lambda self, e: self.naked_property(e),
exp.LocationProperty: lambda self, e: self.naked_property(e), exp.LocationProperty: lambda self, e: self.naked_property(e),
exp.LogProperty: lambda self, e: f"{'NO ' if e.args.get('no') else ''}LOG", exp.LogProperty: lambda self, e: f"{'NO ' if e.args.get('no') else ''}LOG",
@ -166,6 +168,9 @@ class Generator:
# Whether or not to generate an unquoted value for EXTRACT's date part argument # Whether or not to generate an unquoted value for EXTRACT's date part argument
EXTRACT_ALLOWS_QUOTES = True EXTRACT_ALLOWS_QUOTES = True
# Whether or not TIMETZ / TIMESTAMPTZ will be generated using the "WITH TIME ZONE" syntax
TZ_TO_WITH_TIME_ZONE = False
# https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax
SELECT_KINDS: t.Tuple[str, ...] = ("STRUCT", "VALUE") SELECT_KINDS: t.Tuple[str, ...] = ("STRUCT", "VALUE")
@ -271,10 +276,12 @@ class Generator:
# Expressions whose comments are separated from them for better formatting # Expressions whose comments are separated from them for better formatting
WITH_SEPARATED_COMMENTS: t.Tuple[t.Type[exp.Expression], ...] = ( WITH_SEPARATED_COMMENTS: t.Tuple[t.Type[exp.Expression], ...] = (
exp.Create,
exp.Delete, exp.Delete,
exp.Drop, exp.Drop,
exp.From, exp.From,
exp.Insert, exp.Insert,
exp.Join,
exp.Select, exp.Select,
exp.Update, exp.Update,
exp.Where, exp.Where,
@ -831,14 +838,17 @@ class Generator:
def datatype_sql(self, expression: exp.DataType) -> str: def datatype_sql(self, expression: exp.DataType) -> str:
type_value = expression.this type_value = expression.this
type_sql = ( type_sql = (
self.TYPE_MAPPING.get(type_value, type_value.value) self.TYPE_MAPPING.get(type_value, type_value.value)
if isinstance(type_value, exp.DataType.Type) if isinstance(type_value, exp.DataType.Type)
else type_value else type_value
) )
nested = "" nested = ""
interior = self.expressions(expression, flat=True) interior = self.expressions(expression, flat=True)
values = "" values = ""
if interior: if interior:
if expression.args.get("nested"): if expression.args.get("nested"):
nested = f"{self.STRUCT_DELIMITER[0]}{interior}{self.STRUCT_DELIMITER[1]}" nested = f"{self.STRUCT_DELIMITER[0]}{interior}{self.STRUCT_DELIMITER[1]}"
@ -846,10 +856,19 @@ class Generator:
delimiters = ("[", "]") if type_value == exp.DataType.Type.ARRAY else ("(", ")") delimiters = ("[", "]") if type_value == exp.DataType.Type.ARRAY else ("(", ")")
values = self.expressions(expression, key="values", flat=True) values = self.expressions(expression, key="values", flat=True)
values = f"{delimiters[0]}{values}{delimiters[1]}" values = f"{delimiters[0]}{values}{delimiters[1]}"
elif type_value == exp.DataType.Type.INTERVAL:
nested = f" {interior}"
else: else:
nested = f"({interior})" nested = f"({interior})"
return f"{type_sql}{nested}{values}" type_sql = f"{type_sql}{nested}{values}"
if self.TZ_TO_WITH_TIME_ZONE and type_value in (
exp.DataType.Type.TIMETZ,
exp.DataType.Type.TIMESTAMPTZ,
):
type_sql = f"{type_sql} WITH TIME ZONE"
return type_sql
def directory_sql(self, expression: exp.Directory) -> str: def directory_sql(self, expression: exp.Directory) -> str:
local = "LOCAL " if expression.args.get("local") else "" local = "LOCAL " if expression.args.get("local") else ""
@ -1288,7 +1307,12 @@ class Generator:
unpivot = expression.args.get("unpivot") unpivot = expression.args.get("unpivot")
direction = "UNPIVOT" if unpivot else "PIVOT" direction = "UNPIVOT" if unpivot else "PIVOT"
field = self.sql(expression, "field") field = self.sql(expression, "field")
return f"{direction}({expressions} FOR {field}){alias}" include_nulls = expression.args.get("include_nulls")
if include_nulls is not None:
nulls = " INCLUDE NULLS " if include_nulls else " EXCLUDE NULLS "
else:
nulls = ""
return f"{direction}{nulls}({expressions} FOR {field}){alias}"
def tuple_sql(self, expression: exp.Tuple) -> str: def tuple_sql(self, expression: exp.Tuple) -> str:
return f"({self.expressions(expression, flat=True)})" return f"({self.expressions(expression, flat=True)})"

View file

@ -54,11 +54,17 @@ def simplify(expression):
def _simplify(expression, root=True): def _simplify(expression, root=True):
if expression.meta.get(FINAL): if expression.meta.get(FINAL):
return expression return expression
# Pre-order transformations
node = expression node = expression
node = rewrite_between(node) node = rewrite_between(node)
node = uniq_sort(node, generate, root) node = uniq_sort(node, generate, root)
node = absorb_and_eliminate(node, root) node = absorb_and_eliminate(node, root)
node = simplify_concat(node)
exp.replace_children(node, lambda e: _simplify(e, False)) exp.replace_children(node, lambda e: _simplify(e, False))
# Post-order transformations
node = simplify_not(node) node = simplify_not(node)
node = flatten(node) node = flatten(node)
node = simplify_connectors(node, root) node = simplify_connectors(node, root)
@ -66,8 +72,11 @@ def simplify(expression):
node.parent = expression.parent node.parent = expression.parent
node = simplify_literals(node, root) node = simplify_literals(node, root)
node = simplify_parens(node) node = simplify_parens(node)
node = simplify_coalesce(node)
if root: if root:
expression.replace(node) expression.replace(node)
return node return node
expression = while_changing(expression, _simplify) expression = while_changing(expression, _simplify)
@ -184,6 +193,7 @@ COMPARISONS = (
*GT_GTE, *GT_GTE,
exp.EQ, exp.EQ,
exp.NEQ, exp.NEQ,
exp.Is,
) )
INVERSE_COMPARISONS = { INVERSE_COMPARISONS = {
@ -430,6 +440,103 @@ def simplify_parens(expression):
return expression return expression
CONSTANTS = (
exp.Literal,
exp.Boolean,
exp.Null,
)
def simplify_coalesce(expression):
# COALESCE(x) -> x
if (
isinstance(expression, exp.Coalesce)
and not expression.expressions
# COALESCE is also used as a Spark partitioning hint
and not isinstance(expression.parent, exp.Hint)
):
return expression.this
if not isinstance(expression, COMPARISONS):
return expression
if isinstance(expression.left, exp.Coalesce):
coalesce = expression.left
other = expression.right
elif isinstance(expression.right, exp.Coalesce):
coalesce = expression.right
other = expression.left
else:
return expression
# This transformation is valid for non-constants,
# but it really only does anything if they are both constants.
if not isinstance(other, CONSTANTS):
return expression
# Find the first constant arg
for arg_index, arg in enumerate(coalesce.expressions):
if isinstance(arg, CONSTANTS):
break
else:
return expression
coalesce.set("expressions", coalesce.expressions[:arg_index])
# Remove the COALESCE function. This is an optimization, skipping a simplify iteration,
# since we already remove COALESCE at the top of this function.
coalesce = coalesce if coalesce.expressions else coalesce.this
# This expression is more complex than when we started, but it will get simplified further
return exp.or_(
exp.and_(
coalesce.is_(exp.null()).not_(copy=False),
expression.copy(),
copy=False,
),
exp.and_(
coalesce.is_(exp.null()),
type(expression)(this=arg.copy(), expression=other.copy()),
copy=False,
),
copy=False,
)
CONCATS = (exp.Concat, exp.DPipe)
SAFE_CONCATS = (exp.SafeConcat, exp.SafeDPipe)
def simplify_concat(expression):
"""Reduces all groups that contain string literals by concatenating them."""
if not isinstance(expression, CONCATS) or isinstance(expression, exp.ConcatWs):
return expression
new_args = []
for is_string_group, group in itertools.groupby(
expression.expressions or expression.flatten(), lambda e: e.is_string
):
if is_string_group:
new_args.append(exp.Literal.string("".join(string.name for string in group)))
else:
new_args.extend(group)
# Ensures we preserve the right concat type, i.e. whether it's "safe" or not
concat_type = exp.SafeConcat if isinstance(expression, SAFE_CONCATS) else exp.Concat
return new_args[0] if len(new_args) == 1 else concat_type(expressions=new_args)
# CROSS joins result in an empty table if the right table is empty.
# So we can only simplify certain types of joins to CROSS.
# Or in other words, LEFT JOIN x ON TRUE != CROSS JOIN x
JOINS = {
("", ""),
("", "INNER"),
("RIGHT", ""),
("RIGHT", "OUTER"),
}
def remove_where_true(expression): def remove_where_true(expression):
for where in expression.find_all(exp.Where): for where in expression.find_all(exp.Where):
if always_true(where.this): if always_true(where.this):
@ -439,6 +546,7 @@ def remove_where_true(expression):
always_true(join.args.get("on")) always_true(join.args.get("on"))
and not join.args.get("using") and not join.args.get("using")
and not join.args.get("method") and not join.args.get("method")
and (join.side, join.kind) in JOINS
): ):
join.set("on", None) join.set("on", None)
join.set("side", None) join.set("side", None)

View file

@ -102,15 +102,23 @@ class Parser(metaclass=_Parser):
TokenType.CURRENT_USER: exp.CurrentUser, TokenType.CURRENT_USER: exp.CurrentUser,
} }
STRUCT_TYPE_TOKENS = {
TokenType.NESTED,
TokenType.STRUCT,
}
NESTED_TYPE_TOKENS = { NESTED_TYPE_TOKENS = {
TokenType.ARRAY, TokenType.ARRAY,
TokenType.LOWCARDINALITY,
TokenType.MAP, TokenType.MAP,
TokenType.NULLABLE, TokenType.NULLABLE,
TokenType.STRUCT, *STRUCT_TYPE_TOKENS,
} }
ENUM_TYPE_TOKENS = { ENUM_TYPE_TOKENS = {
TokenType.ENUM, TokenType.ENUM,
TokenType.ENUM8,
TokenType.ENUM16,
} }
TYPE_TOKENS = { TYPE_TOKENS = {
@ -128,6 +136,7 @@ class Parser(metaclass=_Parser):
TokenType.UINT128, TokenType.UINT128,
TokenType.INT256, TokenType.INT256,
TokenType.UINT256, TokenType.UINT256,
TokenType.FIXEDSTRING,
TokenType.FLOAT, TokenType.FLOAT,
TokenType.DOUBLE, TokenType.DOUBLE,
TokenType.CHAR, TokenType.CHAR,
@ -145,6 +154,7 @@ class Parser(metaclass=_Parser):
TokenType.JSONB, TokenType.JSONB,
TokenType.INTERVAL, TokenType.INTERVAL,
TokenType.TIME, TokenType.TIME,
TokenType.TIMETZ,
TokenType.TIMESTAMP, TokenType.TIMESTAMP,
TokenType.TIMESTAMPTZ, TokenType.TIMESTAMPTZ,
TokenType.TIMESTAMPLTZ, TokenType.TIMESTAMPLTZ,
@ -187,7 +197,7 @@ class Parser(metaclass=_Parser):
TokenType.INET, TokenType.INET,
TokenType.IPADDRESS, TokenType.IPADDRESS,
TokenType.IPPREFIX, TokenType.IPPREFIX,
TokenType.ENUM, *ENUM_TYPE_TOKENS,
*NESTED_TYPE_TOKENS, *NESTED_TYPE_TOKENS,
} }
@ -384,11 +394,16 @@ class Parser(metaclass=_Parser):
TokenType.STAR: exp.Mul, TokenType.STAR: exp.Mul,
} }
TIMESTAMPS = { TIMES = {
TokenType.TIME, TokenType.TIME,
TokenType.TIMETZ,
}
TIMESTAMPS = {
TokenType.TIMESTAMP, TokenType.TIMESTAMP,
TokenType.TIMESTAMPTZ, TokenType.TIMESTAMPTZ,
TokenType.TIMESTAMPLTZ, TokenType.TIMESTAMPLTZ,
*TIMES,
} }
SET_OPERATIONS = { SET_OPERATIONS = {
@ -1165,6 +1180,8 @@ class Parser(metaclass=_Parser):
def _parse_create(self) -> exp.Create | exp.Command: def _parse_create(self) -> exp.Create | exp.Command:
# Note: this can't be None because we've matched a statement parser # Note: this can't be None because we've matched a statement parser
start = self._prev start = self._prev
comments = self._prev_comments
replace = start.text.upper() == "REPLACE" or self._match_pair( replace = start.text.upper() == "REPLACE" or self._match_pair(
TokenType.OR, TokenType.REPLACE TokenType.OR, TokenType.REPLACE
) )
@ -1273,6 +1290,7 @@ class Parser(metaclass=_Parser):
return self.expression( return self.expression(
exp.Create, exp.Create,
comments=comments,
this=this, this=this,
kind=create_token.text, kind=create_token.text,
replace=replace, replace=replace,
@ -2338,7 +2356,8 @@ class Parser(metaclass=_Parser):
kwargs["this"].set("joins", joins) kwargs["this"].set("joins", joins)
return self.expression(exp.Join, **kwargs) comments = [c for token in (method, side, kind) if token for c in token.comments]
return self.expression(exp.Join, comments=comments, **kwargs)
def _parse_index( def _parse_index(
self, self,
@ -2619,11 +2638,18 @@ class Parser(metaclass=_Parser):
def _parse_pivot(self) -> t.Optional[exp.Pivot]: def _parse_pivot(self) -> t.Optional[exp.Pivot]:
index = self._index index = self._index
include_nulls = None
if self._match(TokenType.PIVOT): if self._match(TokenType.PIVOT):
unpivot = False unpivot = False
elif self._match(TokenType.UNPIVOT): elif self._match(TokenType.UNPIVOT):
unpivot = True unpivot = True
# https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
if self._match_text_seq("INCLUDE", "NULLS"):
include_nulls = True
elif self._match_text_seq("EXCLUDE", "NULLS"):
include_nulls = False
else: else:
return None return None
@ -2654,7 +2680,13 @@ class Parser(metaclass=_Parser):
self._match_r_paren() self._match_r_paren()
pivot = self.expression(exp.Pivot, expressions=expressions, field=field, unpivot=unpivot) pivot = self.expression(
exp.Pivot,
expressions=expressions,
field=field,
unpivot=unpivot,
include_nulls=include_nulls,
)
if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False): if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
pivot.set("alias", self._parse_table_alias()) pivot.set("alias", self._parse_table_alias())
@ -3096,7 +3128,7 @@ class Parser(metaclass=_Parser):
return self.expression(exp.PseudoType, this=self._prev.text) return self.expression(exp.PseudoType, this=self._prev.text)
nested = type_token in self.NESTED_TYPE_TOKENS nested = type_token in self.NESTED_TYPE_TOKENS
is_struct = type_token == TokenType.STRUCT is_struct = type_token in self.STRUCT_TYPE_TOKENS
expressions = None expressions = None
maybe_func = False maybe_func = False
@ -3108,7 +3140,7 @@ class Parser(metaclass=_Parser):
lambda: self._parse_types(check_func=check_func, schema=schema) lambda: self._parse_types(check_func=check_func, schema=schema)
) )
elif type_token in self.ENUM_TYPE_TOKENS: elif type_token in self.ENUM_TYPE_TOKENS:
expressions = self._parse_csv(self._parse_primary) expressions = self._parse_csv(self._parse_equality)
else: else:
expressions = self._parse_csv(self._parse_type_size) expressions = self._parse_csv(self._parse_type_size)
@ -3118,29 +3150,9 @@ class Parser(metaclass=_Parser):
maybe_func = True maybe_func = True
if self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET): this: t.Optional[exp.Expression] = None
this = exp.DataType(
this=exp.DataType.Type.ARRAY,
expressions=[
exp.DataType(
this=exp.DataType.Type[type_token.value],
expressions=expressions,
nested=nested,
)
],
nested=True,
)
while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
return this
if self._match(TokenType.L_BRACKET):
self._retreat(index)
return None
values: t.Optional[t.List[t.Optional[exp.Expression]]] = None values: t.Optional[t.List[t.Optional[exp.Expression]]] = None
if nested and self._match(TokenType.LT): if nested and self._match(TokenType.LT):
if is_struct: if is_struct:
expressions = self._parse_csv(self._parse_struct_types) expressions = self._parse_csv(self._parse_struct_types)
@ -3156,23 +3168,35 @@ class Parser(metaclass=_Parser):
values = self._parse_csv(self._parse_conjunction) values = self._parse_csv(self._parse_conjunction)
self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN)) self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
value: t.Optional[exp.Expression] = None
if type_token in self.TIMESTAMPS: if type_token in self.TIMESTAMPS:
if self._match_text_seq("WITH", "TIME", "ZONE"): if self._match_text_seq("WITH", "TIME", "ZONE"):
maybe_func = False maybe_func = False
value = exp.DataType(this=exp.DataType.Type.TIMESTAMPTZ, expressions=expressions) tz_type = (
exp.DataType.Type.TIMETZ
if type_token in self.TIMES
else exp.DataType.Type.TIMESTAMPTZ
)
this = exp.DataType(this=tz_type, expressions=expressions)
elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"): elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
maybe_func = False maybe_func = False
value = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions) this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
elif self._match_text_seq("WITHOUT", "TIME", "ZONE"): elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
maybe_func = False maybe_func = False
elif type_token == TokenType.INTERVAL: elif type_token == TokenType.INTERVAL:
unit = self._parse_var() if self._match_text_seq("YEAR", "TO", "MONTH"):
span: t.Optional[t.List[exp.Expression]] = [exp.IntervalYearToMonthSpan()]
if not unit: elif self._match_text_seq("DAY", "TO", "SECOND"):
value = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL) span = [exp.IntervalDayToSecondSpan()]
else: else:
value = self.expression(exp.Interval, unit=unit) span = None
unit = not span and self._parse_var()
if not unit:
this = self.expression(
exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
)
else:
this = self.expression(exp.Interval, unit=unit)
if maybe_func and check_func: if maybe_func and check_func:
index2 = self._index index2 = self._index
@ -3184,10 +3208,8 @@ class Parser(metaclass=_Parser):
self._retreat(index2) self._retreat(index2)
if value: if not this:
return value this = exp.DataType(
return exp.DataType(
this=exp.DataType.Type[type_token.value], this=exp.DataType.Type[type_token.value],
expressions=expressions, expressions=expressions,
nested=nested, nested=nested,
@ -3195,6 +3217,11 @@ class Parser(metaclass=_Parser):
prefix=prefix, prefix=prefix,
) )
while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
return this
def _parse_struct_types(self) -> t.Optional[exp.Expression]: def _parse_struct_types(self) -> t.Optional[exp.Expression]:
this = self._parse_type() or self._parse_id_var() this = self._parse_type() or self._parse_id_var()
self._match(TokenType.COLON) self._match(TokenType.COLON)
@ -3738,6 +3765,7 @@ class Parser(metaclass=_Parser):
ifs = [] ifs = []
default = None default = None
comments = self._prev_comments
expression = self._parse_conjunction() expression = self._parse_conjunction()
while self._match(TokenType.WHEN): while self._match(TokenType.WHEN):
@ -3753,7 +3781,7 @@ class Parser(metaclass=_Parser):
self.raise_error("Expected END after CASE", self._prev) self.raise_error("Expected END after CASE", self._prev)
return self._parse_window( return self._parse_window(
self.expression(exp.Case, this=expression, ifs=ifs, default=default) self.expression(exp.Case, comments=comments, this=expression, ifs=ifs, default=default)
) )
def _parse_if(self) -> t.Optional[exp.Expression]: def _parse_if(self) -> t.Optional[exp.Expression]:

View file

@ -372,21 +372,12 @@ class MappingSchema(AbstractMappingSchema[t.Dict[str, str]], Schema):
is_table: bool = False, is_table: bool = False,
normalize: t.Optional[bool] = None, normalize: t.Optional[bool] = None,
) -> str: ) -> str:
dialect = dialect or self.dialect return normalize_name(
normalize = self.normalize if normalize is None else normalize name,
dialect=dialect or self.dialect,
try: is_table=is_table,
identifier = sqlglot.maybe_parse(name, dialect=dialect, into=exp.Identifier) normalize=self.normalize if normalize is None else normalize,
except ParseError: )
return name if isinstance(name, str) else name.name
name = identifier.name
if not normalize:
return name
# This can be useful for normalize_identifier
identifier.meta["is_table"] = is_table
return Dialect.get_or_raise(dialect).normalize_identifier(identifier).name
def depth(self) -> int: def depth(self) -> int:
if not self.empty and not self._depth: if not self.empty and not self._depth:
@ -418,6 +409,26 @@ class MappingSchema(AbstractMappingSchema[t.Dict[str, str]], Schema):
return self._type_mapping_cache[schema_type] return self._type_mapping_cache[schema_type]
def normalize_name(
name: str | exp.Identifier,
dialect: DialectType = None,
is_table: bool = False,
normalize: t.Optional[bool] = True,
) -> str:
try:
identifier = sqlglot.maybe_parse(name, dialect=dialect, into=exp.Identifier)
except ParseError:
return name if isinstance(name, str) else name.name
name = identifier.name
if not normalize:
return name
# This can be useful for normalize_identifier
identifier.meta["is_table"] = is_table
return Dialect.get_or_raise(dialect).normalize_identifier(identifier).name
def ensure_schema(schema: Schema | t.Optional[t.Dict], **kwargs: t.Any) -> Schema: def ensure_schema(schema: Schema | t.Optional[t.Dict], **kwargs: t.Any) -> Schema:
if isinstance(schema, Schema): if isinstance(schema, Schema):
return schema return schema

View file

@ -110,6 +110,7 @@ class TokenType(AutoName):
JSON = auto() JSON = auto()
JSONB = auto() JSONB = auto()
TIME = auto() TIME = auto()
TIMETZ = auto()
TIMESTAMP = auto() TIMESTAMP = auto()
TIMESTAMPTZ = auto() TIMESTAMPTZ = auto()
TIMESTAMPLTZ = auto() TIMESTAMPLTZ = auto()
@ -151,6 +152,11 @@ class TokenType(AutoName):
IPADDRESS = auto() IPADDRESS = auto()
IPPREFIX = auto() IPPREFIX = auto()
ENUM = auto() ENUM = auto()
ENUM8 = auto()
ENUM16 = auto()
FIXEDSTRING = auto()
LOWCARDINALITY = auto()
NESTED = auto()
# keywords # keywords
ALIAS = auto() ALIAS = auto()
@ -659,6 +665,7 @@ class Tokenizer(metaclass=_Tokenizer):
"TINYINT": TokenType.TINYINT, "TINYINT": TokenType.TINYINT,
"SHORT": TokenType.SMALLINT, "SHORT": TokenType.SMALLINT,
"SMALLINT": TokenType.SMALLINT, "SMALLINT": TokenType.SMALLINT,
"INT128": TokenType.INT128,
"INT2": TokenType.SMALLINT, "INT2": TokenType.SMALLINT,
"INTEGER": TokenType.INT, "INTEGER": TokenType.INT,
"INT": TokenType.INT, "INT": TokenType.INT,
@ -699,6 +706,7 @@ class Tokenizer(metaclass=_Tokenizer):
"BYTEA": TokenType.VARBINARY, "BYTEA": TokenType.VARBINARY,
"VARBINARY": TokenType.VARBINARY, "VARBINARY": TokenType.VARBINARY,
"TIME": TokenType.TIME, "TIME": TokenType.TIME,
"TIMETZ": TokenType.TIMETZ,
"TIMESTAMP": TokenType.TIMESTAMP, "TIMESTAMP": TokenType.TIMESTAMP,
"TIMESTAMPTZ": TokenType.TIMESTAMPTZ, "TIMESTAMPTZ": TokenType.TIMESTAMPTZ,
"TIMESTAMPLTZ": TokenType.TIMESTAMPLTZ, "TIMESTAMPLTZ": TokenType.TIMESTAMPLTZ,
@ -879,6 +887,11 @@ class Tokenizer(metaclass=_Tokenizer):
def _add(self, token_type: TokenType, text: t.Optional[str] = None) -> None: def _add(self, token_type: TokenType, text: t.Optional[str] = None) -> None:
self._prev_token_line = self._line self._prev_token_line = self._line
if self._comments and token_type == TokenType.SEMICOLON and self.tokens:
self.tokens[-1].comments.extend(self._comments)
self._comments = []
self.tokens.append( self.tokens.append(
Token( Token(
token_type, token_type,

View file

@ -111,6 +111,14 @@ class TestBigQuery(Validator):
self.validate_all("CAST(x AS NVARCHAR)", write={"bigquery": "CAST(x AS STRING)"}) self.validate_all("CAST(x AS NVARCHAR)", write={"bigquery": "CAST(x AS STRING)"})
self.validate_all("CAST(x AS TIMESTAMPTZ)", write={"bigquery": "CAST(x AS TIMESTAMP)"}) self.validate_all("CAST(x AS TIMESTAMPTZ)", write={"bigquery": "CAST(x AS TIMESTAMP)"})
self.validate_all("CAST(x AS RECORD)", write={"bigquery": "CAST(x AS STRUCT)"}) self.validate_all("CAST(x AS RECORD)", write={"bigquery": "CAST(x AS STRUCT)"})
self.validate_all(
'SELECT TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE)',
write={
"bigquery": "SELECT TIMESTAMP_ADD(CAST('2008-12-25 15:30:00+00' AS TIMESTAMP), INTERVAL 10 MINUTE)",
"databricks": "SELECT DATEADD(MINUTE, 10, CAST('2008-12-25 15:30:00+00' AS TIMESTAMP))",
"spark": "SELECT DATEADD(MINUTE, 10, CAST('2008-12-25 15:30:00+00' AS TIMESTAMP))",
},
)
self.validate_all( self.validate_all(
"MD5(x)", "MD5(x)",
write={ write={

View file

@ -10,6 +10,13 @@ class TestClickhouse(Validator):
self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)") self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)")
self.assertIsNone(expr._meta) self.assertIsNone(expr._meta)
self.validate_identity("CAST(x AS Nested(ID UInt32, Serial UInt32, EventTime DATETIME))")
self.validate_identity("CAST(x AS Enum('hello' = 1, 'world' = 2))")
self.validate_identity("CAST(x AS Enum('hello', 'world'))")
self.validate_identity("CAST(x AS Enum('hello' = 1, 'world'))")
self.validate_identity("CAST(x AS Enum8('hello' = -123, 'world'))")
self.validate_identity("CAST(x AS FixedString(1))")
self.validate_identity("CAST(x AS LowCardinality(FixedString))")
self.validate_identity("SELECT isNaN(1.0)") self.validate_identity("SELECT isNaN(1.0)")
self.validate_identity("SELECT startsWith('Spider-Man', 'Spi')") self.validate_identity("SELECT startsWith('Spider-Man', 'Spi')")
self.validate_identity("SELECT xor(TRUE, FALSE)") self.validate_identity("SELECT xor(TRUE, FALSE)")

View file

@ -11,6 +11,12 @@ class TestDatabricks(Validator):
self.validate_identity("CREATE FUNCTION a AS b") self.validate_identity("CREATE FUNCTION a AS b")
self.validate_identity("SELECT ${x} FROM ${y} WHERE ${z} > 1") self.validate_identity("SELECT ${x} FROM ${y} WHERE ${z} > 1")
self.validate_identity("CREATE TABLE foo (x DATE GENERATED ALWAYS AS (CAST(y AS DATE)))") self.validate_identity("CREATE TABLE foo (x DATE GENERATED ALWAYS AS (CAST(y AS DATE)))")
self.validate_identity(
"SELECT * FROM sales UNPIVOT INCLUDE NULLS (sales FOR quarter IN (q1 AS `Jan-Mar`))"
)
self.validate_identity(
"SELECT * FROM sales UNPIVOT EXCLUDE NULLS (sales FOR quarter IN (q1 AS `Jan-Mar`))"
)
self.validate_all( self.validate_all(
"CREATE TABLE foo (x INT GENERATED ALWAYS AS (YEAR(y)))", "CREATE TABLE foo (x INT GENERATED ALWAYS AS (YEAR(y)))",

View file

@ -90,6 +90,7 @@ class TestDialect(Validator):
"snowflake": "CAST(a AS TEXT)", "snowflake": "CAST(a AS TEXT)",
"spark": "CAST(a AS STRING)", "spark": "CAST(a AS STRING)",
"starrocks": "CAST(a AS STRING)", "starrocks": "CAST(a AS STRING)",
"doris": "CAST(a AS STRING)",
}, },
) )
self.validate_all( self.validate_all(
@ -169,6 +170,7 @@ class TestDialect(Validator):
"snowflake": "CAST(a AS TEXT)", "snowflake": "CAST(a AS TEXT)",
"spark": "CAST(a AS STRING)", "spark": "CAST(a AS STRING)",
"starrocks": "CAST(a AS STRING)", "starrocks": "CAST(a AS STRING)",
"doris": "CAST(a AS STRING)",
}, },
) )
self.validate_all( self.validate_all(
@ -186,6 +188,7 @@ class TestDialect(Validator):
"snowflake": "CAST(a AS VARCHAR)", "snowflake": "CAST(a AS VARCHAR)",
"spark": "CAST(a AS STRING)", "spark": "CAST(a AS STRING)",
"starrocks": "CAST(a AS VARCHAR)", "starrocks": "CAST(a AS VARCHAR)",
"doris": "CAST(a AS VARCHAR)",
}, },
) )
self.validate_all( self.validate_all(
@ -203,6 +206,7 @@ class TestDialect(Validator):
"snowflake": "CAST(a AS VARCHAR(3))", "snowflake": "CAST(a AS VARCHAR(3))",
"spark": "CAST(a AS VARCHAR(3))", "spark": "CAST(a AS VARCHAR(3))",
"starrocks": "CAST(a AS VARCHAR(3))", "starrocks": "CAST(a AS VARCHAR(3))",
"doris": "CAST(a AS VARCHAR(3))",
}, },
) )
self.validate_all( self.validate_all(
@ -221,6 +225,7 @@ class TestDialect(Validator):
"spark": "CAST(a AS SMALLINT)", "spark": "CAST(a AS SMALLINT)",
"sqlite": "CAST(a AS INTEGER)", "sqlite": "CAST(a AS INTEGER)",
"starrocks": "CAST(a AS SMALLINT)", "starrocks": "CAST(a AS SMALLINT)",
"doris": "CAST(a AS SMALLINT)",
}, },
) )
self.validate_all( self.validate_all(
@ -234,6 +239,7 @@ class TestDialect(Validator):
"drill": "CAST(a AS DOUBLE)", "drill": "CAST(a AS DOUBLE)",
"postgres": "CAST(a AS DOUBLE PRECISION)", "postgres": "CAST(a AS DOUBLE PRECISION)",
"redshift": "CAST(a AS DOUBLE PRECISION)", "redshift": "CAST(a AS DOUBLE PRECISION)",
"doris": "CAST(a AS DOUBLE)",
}, },
) )
@ -267,13 +273,15 @@ class TestDialect(Validator):
write={ write={
"starrocks": "CAST(a AS DATETIME)", "starrocks": "CAST(a AS DATETIME)",
"redshift": "CAST(a AS TIMESTAMP)", "redshift": "CAST(a AS TIMESTAMP)",
"doris": "CAST(a AS DATETIME)",
}, },
) )
self.validate_all( self.validate_all(
"CAST(a AS TIMESTAMPTZ)", "CAST(a AS TIMESTAMPTZ)",
write={ write={
"starrocks": "CAST(a AS DATETIME)", "starrocks": "CAST(a AS DATETIME)",
"redshift": "CAST(a AS TIMESTAMPTZ)", "redshift": "CAST(a AS TIMESTAMP WITH TIME ZONE)",
"doris": "CAST(a AS DATETIME)",
}, },
) )
self.validate_all("CAST(a AS TINYINT)", write={"oracle": "CAST(a AS NUMBER)"}) self.validate_all("CAST(a AS TINYINT)", write={"oracle": "CAST(a AS NUMBER)"})
@ -402,12 +410,13 @@ class TestDialect(Validator):
}, },
) )
self.validate_all( self.validate_all(
"STR_TO_UNIX('2020-01-01', '%Y-%M-%d')", "STR_TO_UNIX('2020-01-01', '%Y-%m-%d')",
write={ write={
"duckdb": "EPOCH(STRPTIME('2020-01-01', '%Y-%M-%d'))", "duckdb": "EPOCH(STRPTIME('2020-01-01', '%Y-%m-%d'))",
"hive": "UNIX_TIMESTAMP('2020-01-01', 'yyyy-mm-dd')", "hive": "UNIX_TIMESTAMP('2020-01-01', 'yyyy-MM-dd')",
"presto": "TO_UNIXTIME(DATE_PARSE('2020-01-01', '%Y-%i-%d'))", "presto": "TO_UNIXTIME(DATE_PARSE('2020-01-01', '%Y-%m-%d'))",
"starrocks": "UNIX_TIMESTAMP('2020-01-01', '%Y-%i-%d')", "starrocks": "UNIX_TIMESTAMP('2020-01-01', '%Y-%m-%d')",
"doris": "UNIX_TIMESTAMP('2020-01-01', '%Y-%m-%d')",
}, },
) )
self.validate_all( self.validate_all(
@ -418,6 +427,7 @@ class TestDialect(Validator):
"hive": "TO_DATE('2020-01-01')", "hive": "TO_DATE('2020-01-01')",
"presto": "CAST('2020-01-01' AS TIMESTAMP)", "presto": "CAST('2020-01-01' AS TIMESTAMP)",
"starrocks": "TO_DATE('2020-01-01')", "starrocks": "TO_DATE('2020-01-01')",
"doris": "TO_DATE('2020-01-01')",
}, },
) )
self.validate_all( self.validate_all(
@ -428,6 +438,7 @@ class TestDialect(Validator):
"hive": "CAST('2020-01-01' AS TIMESTAMP)", "hive": "CAST('2020-01-01' AS TIMESTAMP)",
"presto": "CAST('2020-01-01' AS TIMESTAMP)", "presto": "CAST('2020-01-01' AS TIMESTAMP)",
"sqlite": "'2020-01-01'", "sqlite": "'2020-01-01'",
"doris": "CAST('2020-01-01' AS DATETIME)",
}, },
) )
self.validate_all( self.validate_all(
@ -437,6 +448,7 @@ class TestDialect(Validator):
"hive": "UNIX_TIMESTAMP('2020-01-01')", "hive": "UNIX_TIMESTAMP('2020-01-01')",
"mysql": "UNIX_TIMESTAMP('2020-01-01')", "mysql": "UNIX_TIMESTAMP('2020-01-01')",
"presto": "TO_UNIXTIME(DATE_PARSE('2020-01-01', '%Y-%m-%d %T'))", "presto": "TO_UNIXTIME(DATE_PARSE('2020-01-01', '%Y-%m-%d %T'))",
"doris": "UNIX_TIMESTAMP('2020-01-01')",
}, },
) )
self.validate_all( self.validate_all(
@ -449,6 +461,7 @@ class TestDialect(Validator):
"postgres": "TO_CHAR(x, 'YYYY-MM-DD')", "postgres": "TO_CHAR(x, 'YYYY-MM-DD')",
"presto": "DATE_FORMAT(x, '%Y-%m-%d')", "presto": "DATE_FORMAT(x, '%Y-%m-%d')",
"redshift": "TO_CHAR(x, 'YYYY-MM-DD')", "redshift": "TO_CHAR(x, 'YYYY-MM-DD')",
"doris": "DATE_FORMAT(x, '%Y-%m-%d')",
}, },
) )
self.validate_all( self.validate_all(
@ -459,6 +472,7 @@ class TestDialect(Validator):
"hive": "CAST(x AS STRING)", "hive": "CAST(x AS STRING)",
"presto": "CAST(x AS VARCHAR)", "presto": "CAST(x AS VARCHAR)",
"redshift": "CAST(x AS VARCHAR(MAX))", "redshift": "CAST(x AS VARCHAR(MAX))",
"doris": "CAST(x AS STRING)",
}, },
) )
self.validate_all( self.validate_all(
@ -468,6 +482,7 @@ class TestDialect(Validator):
"duckdb": "EPOCH(x)", "duckdb": "EPOCH(x)",
"hive": "UNIX_TIMESTAMP(x)", "hive": "UNIX_TIMESTAMP(x)",
"presto": "TO_UNIXTIME(x)", "presto": "TO_UNIXTIME(x)",
"doris": "UNIX_TIMESTAMP(x)",
}, },
) )
self.validate_all( self.validate_all(
@ -476,6 +491,7 @@ class TestDialect(Validator):
"duckdb": "SUBSTRING(CAST(x AS TEXT), 1, 10)", "duckdb": "SUBSTRING(CAST(x AS TEXT), 1, 10)",
"hive": "SUBSTRING(CAST(x AS STRING), 1, 10)", "hive": "SUBSTRING(CAST(x AS STRING), 1, 10)",
"presto": "SUBSTRING(CAST(x AS VARCHAR), 1, 10)", "presto": "SUBSTRING(CAST(x AS VARCHAR), 1, 10)",
"doris": "SUBSTRING(CAST(x AS STRING), 1, 10)",
}, },
) )
self.validate_all( self.validate_all(
@ -487,6 +503,7 @@ class TestDialect(Validator):
"postgres": "CAST(x AS DATE)", "postgres": "CAST(x AS DATE)",
"presto": "CAST(CAST(x AS TIMESTAMP) AS DATE)", "presto": "CAST(CAST(x AS TIMESTAMP) AS DATE)",
"snowflake": "CAST(x AS DATE)", "snowflake": "CAST(x AS DATE)",
"doris": "TO_DATE(x)",
}, },
) )
self.validate_all( self.validate_all(
@ -505,6 +522,7 @@ class TestDialect(Validator):
"hive": "FROM_UNIXTIME(x, y)", "hive": "FROM_UNIXTIME(x, y)",
"presto": "DATE_FORMAT(FROM_UNIXTIME(x), y)", "presto": "DATE_FORMAT(FROM_UNIXTIME(x), y)",
"starrocks": "FROM_UNIXTIME(x, y)", "starrocks": "FROM_UNIXTIME(x, y)",
"doris": "FROM_UNIXTIME(x, y)",
}, },
) )
self.validate_all( self.validate_all(
@ -516,6 +534,7 @@ class TestDialect(Validator):
"postgres": "TO_TIMESTAMP(x)", "postgres": "TO_TIMESTAMP(x)",
"presto": "FROM_UNIXTIME(x)", "presto": "FROM_UNIXTIME(x)",
"starrocks": "FROM_UNIXTIME(x)", "starrocks": "FROM_UNIXTIME(x)",
"doris": "FROM_UNIXTIME(x)",
}, },
) )
self.validate_all( self.validate_all(
@ -582,6 +601,7 @@ class TestDialect(Validator):
"sqlite": "DATE(x, '1 DAY')", "sqlite": "DATE(x, '1 DAY')",
"starrocks": "DATE_ADD(x, INTERVAL 1 DAY)", "starrocks": "DATE_ADD(x, INTERVAL 1 DAY)",
"tsql": "DATEADD(DAY, 1, x)", "tsql": "DATEADD(DAY, 1, x)",
"doris": "DATE_ADD(x, INTERVAL 1 DAY)",
}, },
) )
self.validate_all( self.validate_all(
@ -595,6 +615,7 @@ class TestDialect(Validator):
"presto": "DATE_ADD('day', 1, x)", "presto": "DATE_ADD('day', 1, x)",
"spark": "DATE_ADD(x, 1)", "spark": "DATE_ADD(x, 1)",
"starrocks": "DATE_ADD(x, INTERVAL 1 DAY)", "starrocks": "DATE_ADD(x, INTERVAL 1 DAY)",
"doris": "DATE_ADD(x, INTERVAL 1 DAY)",
}, },
) )
self.validate_all( self.validate_all(
@ -612,6 +633,7 @@ class TestDialect(Validator):
"snowflake": "DATE_TRUNC('day', x)", "snowflake": "DATE_TRUNC('day', x)",
"starrocks": "DATE_TRUNC('day', x)", "starrocks": "DATE_TRUNC('day', x)",
"spark": "TRUNC(x, 'day')", "spark": "TRUNC(x, 'day')",
"doris": "DATE_TRUNC(x, 'day')",
}, },
) )
self.validate_all( self.validate_all(
@ -624,6 +646,7 @@ class TestDialect(Validator):
"snowflake": "DATE_TRUNC('day', x)", "snowflake": "DATE_TRUNC('day', x)",
"starrocks": "DATE_TRUNC('day', x)", "starrocks": "DATE_TRUNC('day', x)",
"spark": "DATE_TRUNC('day', x)", "spark": "DATE_TRUNC('day', x)",
"doris": "DATE_TRUNC('day', x)",
}, },
) )
self.validate_all( self.validate_all(
@ -684,6 +707,7 @@ class TestDialect(Validator):
"snowflake": "DATE_TRUNC('year', x)", "snowflake": "DATE_TRUNC('year', x)",
"starrocks": "DATE_TRUNC('year', x)", "starrocks": "DATE_TRUNC('year', x)",
"spark": "TRUNC(x, 'year')", "spark": "TRUNC(x, 'year')",
"doris": "DATE_TRUNC(x, 'year')",
}, },
) )
self.validate_all( self.validate_all(
@ -698,6 +722,7 @@ class TestDialect(Validator):
write={ write={
"bigquery": "TIMESTAMP_TRUNC(x, year)", "bigquery": "TIMESTAMP_TRUNC(x, year)",
"spark": "DATE_TRUNC('year', x)", "spark": "DATE_TRUNC('year', x)",
"doris": "DATE_TRUNC(x, 'year')",
}, },
) )
self.validate_all( self.validate_all(
@ -719,6 +744,7 @@ class TestDialect(Validator):
"hive": "CAST(FROM_UNIXTIME(UNIX_TIMESTAMP(x, 'yyyy-MM-ddTHH:mm:ss')) AS DATE)", "hive": "CAST(FROM_UNIXTIME(UNIX_TIMESTAMP(x, 'yyyy-MM-ddTHH:mm:ss')) AS DATE)",
"presto": "CAST(DATE_PARSE(x, '%Y-%m-%dT%T') AS DATE)", "presto": "CAST(DATE_PARSE(x, '%Y-%m-%dT%T') AS DATE)",
"spark": "TO_DATE(x, 'yyyy-MM-ddTHH:mm:ss')", "spark": "TO_DATE(x, 'yyyy-MM-ddTHH:mm:ss')",
"doris": "STR_TO_DATE(x, '%Y-%m-%dT%T')",
}, },
) )
self.validate_all( self.validate_all(
@ -730,6 +756,7 @@ class TestDialect(Validator):
"hive": "CAST(x AS DATE)", "hive": "CAST(x AS DATE)",
"presto": "CAST(DATE_PARSE(x, '%Y-%m-%d') AS DATE)", "presto": "CAST(DATE_PARSE(x, '%Y-%m-%d') AS DATE)",
"spark": "TO_DATE(x)", "spark": "TO_DATE(x)",
"doris": "STR_TO_DATE(x, '%Y-%m-%d')",
}, },
) )
self.validate_all( self.validate_all(
@ -784,6 +811,7 @@ class TestDialect(Validator):
"mysql": "CAST('2022-01-01' AS TIMESTAMP)", "mysql": "CAST('2022-01-01' AS TIMESTAMP)",
"starrocks": "CAST('2022-01-01' AS DATETIME)", "starrocks": "CAST('2022-01-01' AS DATETIME)",
"hive": "CAST('2022-01-01' AS TIMESTAMP)", "hive": "CAST('2022-01-01' AS TIMESTAMP)",
"doris": "CAST('2022-01-01' AS DATETIME)",
}, },
) )
self.validate_all( self.validate_all(
@ -792,6 +820,7 @@ class TestDialect(Validator):
"mysql": "TIMESTAMP('2022-01-01')", "mysql": "TIMESTAMP('2022-01-01')",
"starrocks": "TIMESTAMP('2022-01-01')", "starrocks": "TIMESTAMP('2022-01-01')",
"hive": "TIMESTAMP('2022-01-01')", "hive": "TIMESTAMP('2022-01-01')",
"doris": "TIMESTAMP('2022-01-01')",
}, },
) )
@ -807,6 +836,7 @@ class TestDialect(Validator):
"mysql", "mysql",
"presto", "presto",
"starrocks", "starrocks",
"doris",
) )
}, },
write={ write={
@ -820,6 +850,7 @@ class TestDialect(Validator):
"hive", "hive",
"spark", "spark",
"starrocks", "starrocks",
"doris",
) )
}, },
) )
@ -886,6 +917,7 @@ class TestDialect(Validator):
"postgres": "x->'y'", "postgres": "x->'y'",
"presto": "JSON_EXTRACT(x, 'y')", "presto": "JSON_EXTRACT(x, 'y')",
"starrocks": "x -> 'y'", "starrocks": "x -> 'y'",
"doris": "x -> 'y'",
}, },
write={ write={
"mysql": "JSON_EXTRACT(x, 'y')", "mysql": "JSON_EXTRACT(x, 'y')",
@ -893,6 +925,7 @@ class TestDialect(Validator):
"postgres": "x -> 'y'", "postgres": "x -> 'y'",
"presto": "JSON_EXTRACT(x, 'y')", "presto": "JSON_EXTRACT(x, 'y')",
"starrocks": "x -> 'y'", "starrocks": "x -> 'y'",
"doris": "x -> 'y'",
}, },
) )
self.validate_all( self.validate_all(
@ -1115,6 +1148,7 @@ class TestDialect(Validator):
"sqlite": "LOWER(x) LIKE '%y'", "sqlite": "LOWER(x) LIKE '%y'",
"starrocks": "LOWER(x) LIKE '%y'", "starrocks": "LOWER(x) LIKE '%y'",
"trino": "LOWER(x) LIKE '%y'", "trino": "LOWER(x) LIKE '%y'",
"doris": "LOWER(x) LIKE '%y'",
}, },
) )
self.validate_all( self.validate_all(

View file

@ -0,0 +1,20 @@
from tests.dialects.test_dialect import Validator
class TestDoris(Validator):
dialect = "doris"
def test_identity(self):
self.validate_identity("SELECT CAST(`a`.`b` AS INT) FROM foo")
self.validate_identity("SELECT APPROX_COUNT_DISTINCT(a) FROM x")
def test_time(self):
self.validate_identity("TIMESTAMP('2022-01-01')")
def test_regex(self):
self.validate_all(
"SELECT REGEXP_LIKE(abc, '%foo%')",
write={
"doris": "SELECT REGEXP(abc, '%foo%')",
},
)

View file

@ -337,6 +337,8 @@ class TestDuckDB(Validator):
unsupported_level=ErrorLevel.IMMEDIATE, unsupported_level=ErrorLevel.IMMEDIATE,
) )
self.validate_identity("SELECT ISNAN(x)")
def test_time(self): def test_time(self):
self.validate_identity("SELECT CURRENT_DATE") self.validate_identity("SELECT CURRENT_DATE")
self.validate_identity("SELECT CURRENT_TIMESTAMP") self.validate_identity("SELECT CURRENT_TIMESTAMP")
@ -399,7 +401,7 @@ class TestDuckDB(Validator):
"bigquery": "TIME_TO_STR(x, '%y-%-m-%S')", "bigquery": "TIME_TO_STR(x, '%y-%-m-%S')",
"duckdb": "STRFTIME(x, '%y-%-m-%S')", "duckdb": "STRFTIME(x, '%y-%-m-%S')",
"postgres": "TO_CHAR(x, 'YY-FMMM-SS')", "postgres": "TO_CHAR(x, 'YY-FMMM-SS')",
"presto": "DATE_FORMAT(x, '%y-%c-%S')", "presto": "DATE_FORMAT(x, '%y-%c-%s')",
"spark": "DATE_FORMAT(x, 'yy-M-ss')", "spark": "DATE_FORMAT(x, 'yy-M-ss')",
}, },
) )
@ -497,8 +499,12 @@ class TestDuckDB(Validator):
self.validate_identity("CAST(x AS USMALLINT)") self.validate_identity("CAST(x AS USMALLINT)")
self.validate_identity("CAST(x AS UTINYINT)") self.validate_identity("CAST(x AS UTINYINT)")
self.validate_identity("CAST(x AS TEXT)") self.validate_identity("CAST(x AS TEXT)")
self.validate_identity("CAST(x AS INT128)")
self.validate_identity("CAST(x AS DOUBLE)")
self.validate_identity("CAST(x AS DECIMAL(15, 4))")
self.validate_all("CAST(x AS NUMERIC)", write={"duckdb": "CAST(x AS DOUBLE)"}) self.validate_all("CAST(x AS NUMERIC(1, 2))", write={"duckdb": "CAST(x AS DECIMAL(1, 2))"})
self.validate_all("CAST(x AS HUGEINT)", write={"duckdb": "CAST(x AS INT128)"})
self.validate_all("CAST(x AS CHAR)", write={"duckdb": "CAST(x AS TEXT)"}) self.validate_all("CAST(x AS CHAR)", write={"duckdb": "CAST(x AS TEXT)"})
self.validate_all("CAST(x AS BPCHAR)", write={"duckdb": "CAST(x AS TEXT)"}) self.validate_all("CAST(x AS BPCHAR)", write={"duckdb": "CAST(x AS TEXT)"})
self.validate_all("CAST(x AS STRING)", write={"duckdb": "CAST(x AS TEXT)"}) self.validate_all("CAST(x AS STRING)", write={"duckdb": "CAST(x AS TEXT)"})
@ -513,6 +519,20 @@ class TestDuckDB(Validator):
self.validate_all("CAST(x AS BINARY)", write={"duckdb": "CAST(x AS BLOB)"}) self.validate_all("CAST(x AS BINARY)", write={"duckdb": "CAST(x AS BLOB)"})
self.validate_all("CAST(x AS VARBINARY)", write={"duckdb": "CAST(x AS BLOB)"}) self.validate_all("CAST(x AS VARBINARY)", write={"duckdb": "CAST(x AS BLOB)"})
self.validate_all("CAST(x AS LOGICAL)", write={"duckdb": "CAST(x AS BOOLEAN)"}) self.validate_all("CAST(x AS LOGICAL)", write={"duckdb": "CAST(x AS BOOLEAN)"})
self.validate_all(
"CAST(x AS NUMERIC)",
write={
"duckdb": "CAST(x AS DECIMAL(18, 3))",
"postgres": "CAST(x AS DECIMAL(18, 3))",
},
)
self.validate_all(
"CAST(x AS DECIMAL)",
write={
"duckdb": "CAST(x AS DECIMAL(18, 3))",
"postgres": "CAST(x AS DECIMAL(18, 3))",
},
)
self.validate_all( self.validate_all(
"CAST(x AS BIT)", "CAST(x AS BIT)",
read={ read={

View file

@ -103,6 +103,7 @@ class TestMySQL(Validator):
self.validate_identity("@@GLOBAL.max_connections") self.validate_identity("@@GLOBAL.max_connections")
self.validate_identity("CREATE TABLE A LIKE B") self.validate_identity("CREATE TABLE A LIKE B")
self.validate_identity("SELECT * FROM t1, t2 FOR SHARE OF t1, t2 SKIP LOCKED") self.validate_identity("SELECT * FROM t1, t2 FOR SHARE OF t1, t2 SKIP LOCKED")
self.validate_identity("SELECT a || b", "SELECT a OR b")
self.validate_identity( self.validate_identity(
"""SELECT * FROM foo WHERE 3 MEMBER OF(JSON_EXTRACT(info, '$.value'))""" """SELECT * FROM foo WHERE 3 MEMBER OF(JSON_EXTRACT(info, '$.value'))"""
) )

View file

@ -9,6 +9,10 @@ class TestPostgres(Validator):
dialect = "postgres" dialect = "postgres"
def test_ddl(self): def test_ddl(self):
self.validate_identity(
"CREATE TABLE test (x TIMESTAMP WITHOUT TIME ZONE[][])",
"CREATE TABLE test (x TIMESTAMP[][])",
)
self.validate_identity("CREATE TABLE test (elems JSONB[])") self.validate_identity("CREATE TABLE test (elems JSONB[])")
self.validate_identity("CREATE TABLE public.y (x TSTZRANGE NOT NULL)") self.validate_identity("CREATE TABLE public.y (x TSTZRANGE NOT NULL)")
self.validate_identity("CREATE TABLE test (foo HSTORE)") self.validate_identity("CREATE TABLE test (foo HSTORE)")

View file

@ -1,6 +1,6 @@
from unittest import mock from unittest import mock
from sqlglot import UnsupportedError from sqlglot import UnsupportedError, exp, parse_one
from tests.dialects.test_dialect import Validator from tests.dialects.test_dialect import Validator
@ -8,6 +8,23 @@ class TestPresto(Validator):
dialect = "presto" dialect = "presto"
def test_cast(self): def test_cast(self):
self.validate_identity("CAST(x AS IPADDRESS)")
self.validate_identity("CAST(x AS IPPREFIX)")
self.validate_all(
"CAST(x AS INTERVAL YEAR TO MONTH)",
write={
"oracle": "CAST(x AS INTERVAL YEAR TO MONTH)",
"presto": "CAST(x AS INTERVAL YEAR TO MONTH)",
},
)
self.validate_all(
"CAST(x AS INTERVAL DAY TO SECOND)",
write={
"oracle": "CAST(x AS INTERVAL DAY TO SECOND)",
"presto": "CAST(x AS INTERVAL DAY TO SECOND)",
},
)
self.validate_all( self.validate_all(
"SELECT CAST('10C' AS INTEGER)", "SELECT CAST('10C' AS INTEGER)",
read={ read={
@ -99,18 +116,25 @@ class TestPresto(Validator):
"snowflake": "CAST(OBJECT_CONSTRUCT('a', [1], 'b', [2], 'c', [3]) AS OBJECT)", "snowflake": "CAST(OBJECT_CONSTRUCT('a', [1], 'b', [2], 'c', [3]) AS OBJECT)",
}, },
) )
self.validate_all(
"CAST(x AS TIME(5) WITH TIME ZONE)",
write={
"duckdb": "CAST(x AS TIMETZ)",
"postgres": "CAST(x AS TIMETZ(5))",
"presto": "CAST(x AS TIME(5) WITH TIME ZONE)",
"redshift": "CAST(x AS TIME(5) WITH TIME ZONE)",
},
)
self.validate_all( self.validate_all(
"CAST(x AS TIMESTAMP(9) WITH TIME ZONE)", "CAST(x AS TIMESTAMP(9) WITH TIME ZONE)",
write={ write={
"bigquery": "CAST(x AS TIMESTAMP)", "bigquery": "CAST(x AS TIMESTAMP)",
"duckdb": "CAST(x AS TIMESTAMPTZ(9))", "duckdb": "CAST(x AS TIMESTAMPTZ)",
"presto": "CAST(x AS TIMESTAMP(9) WITH TIME ZONE)", "presto": "CAST(x AS TIMESTAMP(9) WITH TIME ZONE)",
"hive": "CAST(x AS TIMESTAMP)", "hive": "CAST(x AS TIMESTAMP)",
"spark": "CAST(x AS TIMESTAMP)", "spark": "CAST(x AS TIMESTAMP)",
}, },
) )
self.validate_identity("CAST(x AS IPADDRESS)")
self.validate_identity("CAST(x AS IPPREFIX)")
def test_regex(self): def test_regex(self):
self.validate_all( self.validate_all(
@ -179,6 +203,9 @@ class TestPresto(Validator):
) )
def test_time(self): def test_time(self):
expr = parse_one("TIME(7) WITH TIME ZONE", into=exp.DataType, read="presto")
self.assertEqual(expr.this, exp.DataType.Type.TIMETZ)
self.validate_identity("FROM_UNIXTIME(a, b)") self.validate_identity("FROM_UNIXTIME(a, b)")
self.validate_identity("FROM_UNIXTIME(a, b, c)") self.validate_identity("FROM_UNIXTIME(a, b, c)")
self.validate_identity("TRIM(a, b)") self.validate_identity("TRIM(a, b)")

View file

@ -5,6 +5,26 @@ class TestRedshift(Validator):
dialect = "redshift" dialect = "redshift"
def test_redshift(self): def test_redshift(self):
self.validate_all(
"SELECT CAST('01:03:05.124' AS TIME(2) WITH TIME ZONE)",
read={
"postgres": "SELECT CAST('01:03:05.124' AS TIMETZ(2))",
},
write={
"postgres": "SELECT CAST('01:03:05.124' AS TIMETZ(2))",
"redshift": "SELECT CAST('01:03:05.124' AS TIME(2) WITH TIME ZONE)",
},
)
self.validate_all(
"SELECT CAST('2020-02-02 01:03:05.124' AS TIMESTAMP(2) WITH TIME ZONE)",
read={
"postgres": "SELECT CAST('2020-02-02 01:03:05.124' AS TIMESTAMPTZ(2))",
},
write={
"postgres": "SELECT CAST('2020-02-02 01:03:05.124' AS TIMESTAMPTZ(2))",
"redshift": "SELECT CAST('2020-02-02 01:03:05.124' AS TIMESTAMP(2) WITH TIME ZONE)",
},
)
self.validate_all( self.validate_all(
"SELECT INTERVAL '5 days'", "SELECT INTERVAL '5 days'",
read={ read={

View file

@ -853,4 +853,5 @@ SELECT * FROM (tbl1 CROSS JOIN (SELECT * FROM tbl2) AS t1)
/* comment1 */ INSERT INTO x /* comment2 */ VALUES (1, 2, 3) /* comment1 */ INSERT INTO x /* comment2 */ VALUES (1, 2, 3)
/* comment1 */ UPDATE tbl /* comment2 */ SET x = 2 WHERE x < 2 /* comment1 */ UPDATE tbl /* comment2 */ SET x = 2 WHERE x < 2
/* comment1 */ DELETE FROM x /* comment2 */ WHERE y > 1 /* comment1 */ DELETE FROM x /* comment2 */ WHERE y > 1
/* comment */ CREATE TABLE foo AS SELECT 1
SELECT next, transform, if SELECT next, transform, if

View file

@ -944,3 +944,9 @@ SELECT
FROM "m" FROM "m"
JOIN "n" AS "foo"("a") JOIN "n" AS "foo"("a")
ON "m"."a" = "foo"."a"; ON "m"."a" = "foo"."a";
# title: reduction of string concatenation that uses CONCAT(..), || and +
# execute: false
SELECT CONCAT('a', 'b') || CONCAT(CONCAT('c', 'd'), CONCAT('e', 'f')) + ('g' || 'h' || 'i');
SELECT
'abcdefghi' AS "_col_0";

View file

@ -431,6 +431,14 @@ SELECT x.a AS a, i.b AS b FROM x AS x CROSS JOIN UNNEST(SPLIT(x.b, ',')) AS i(b)
SELECT c FROM (SELECT 1 a) AS x LATERAL VIEW EXPLODE(a) AS c; SELECT c FROM (SELECT 1 a) AS x LATERAL VIEW EXPLODE(a) AS c;
SELECT _q_0.c AS c FROM (SELECT 1 AS a) AS x LATERAL VIEW EXPLODE(x.a) _q_0 AS c; SELECT _q_0.c AS c FROM (SELECT 1 AS a) AS x LATERAL VIEW EXPLODE(x.a) _q_0 AS c;
# execute: false
SELECT * FROM foo(bar) AS t(c1, c2, c3);
SELECT t.c1 AS c1, t.c2 AS c2, t.c3 AS c3 FROM FOO(bar) AS t(c1, c2, c3);
# execute: false
SELECT c1, c3 FROM foo(bar) AS t(c1, c2, c3);
SELECT t.c1 AS c1, t.c3 AS c3 FROM FOO(bar) AS t(c1, c2, c3);
-------------------------------------- --------------------------------------
-- Window functions -- Window functions
-------------------------------------- --------------------------------------

View file

@ -240,9 +240,18 @@ A AND B AND C;
SELECT x WHERE TRUE; SELECT x WHERE TRUE;
SELECT x; SELECT x;
SELECT x FROM y LEFT JOIN z ON TRUE; SELECT x FROM y JOIN z ON TRUE;
SELECT x FROM y CROSS JOIN z; SELECT x FROM y CROSS JOIN z;
SELECT x FROM y RIGHT JOIN z ON TRUE;
SELECT x FROM y CROSS JOIN z;
SELECT x FROM y LEFT JOIN z ON TRUE;
SELECT x FROM y LEFT JOIN z ON TRUE;
SELECT x FROM y FULL OUTER JOIN z ON TRUE;
SELECT x FROM y FULL OUTER JOIN z ON TRUE;
SELECT x FROM y JOIN z USING (x); SELECT x FROM y JOIN z USING (x);
SELECT x FROM y JOIN z USING (x); SELECT x FROM y JOIN z USING (x);
@ -602,3 +611,57 @@ TRUE;
x = 2018 OR x <> 2018; x = 2018 OR x <> 2018;
x <> 2018 OR x = 2018; x <> 2018 OR x = 2018;
--------------------------------------
-- Coalesce
--------------------------------------
COALESCE(x);
x;
COALESCE(x, 1) = 2;
x = 2 AND NOT x IS NULL;
2 = COALESCE(x, 1);
2 = x AND NOT x IS NULL;
COALESCE(x, 1, 1) = 1 + 1;
x = 2 AND NOT x IS NULL;
COALESCE(x, 1, 2) = 2;
x = 2 AND NOT x IS NULL;
COALESCE(x, 3) <= 2;
x <= 2 AND NOT x IS NULL;
COALESCE(x, 1) <> 2;
x <> 2 OR x IS NULL;
COALESCE(x, 1) <= 2;
x <= 2 OR x IS NULL;
COALESCE(x, 1) = 1;
x = 1 OR x IS NULL;
COALESCE(x, 1) IS NULL;
FALSE;
--------------------------------------
-- CONCAT
--------------------------------------
CONCAT(x, y);
CONCAT(x, y);
CONCAT(x);
x;
CONCAT('a', 'b', 'c');
'abc';
CONCAT('a', x, y, 'b', 'c');
CONCAT('a', x, y, 'bc');
'a' || 'b';
'ab';
'a' || 'b' || x;
CONCAT('ab', x);

View file

@ -857,7 +857,7 @@ WITH "salesreturns" AS (
), "cte_10" AS ( ), "cte_10" AS (
SELECT SELECT
'catalog channel' AS "channel", 'catalog channel' AS "channel",
'catalog_page' || "csr"."cp_catalog_page_id" AS "id", CONCAT('catalog_page', "csr"."cp_catalog_page_id") AS "id",
"csr"."sales" AS "sales", "csr"."sales" AS "sales",
"csr"."returns1" AS "returns1", "csr"."returns1" AS "returns1",
"csr"."profit" - "csr"."profit_loss" AS "profit" "csr"."profit" - "csr"."profit_loss" AS "profit"
@ -865,7 +865,7 @@ WITH "salesreturns" AS (
UNION ALL UNION ALL
SELECT SELECT
'web channel' AS "channel", 'web channel' AS "channel",
'web_site' || "wsr"."web_site_id" AS "id", CONCAT('web_site', "wsr"."web_site_id") AS "id",
"wsr"."sales" AS "sales", "wsr"."sales" AS "sales",
"wsr"."returns1" AS "returns1", "wsr"."returns1" AS "returns1",
"wsr"."profit" - "wsr"."profit_loss" AS "profit" "wsr"."profit" - "wsr"."profit_loss" AS "profit"
@ -873,7 +873,7 @@ WITH "salesreturns" AS (
), "x" AS ( ), "x" AS (
SELECT SELECT
'store channel' AS "channel", 'store channel' AS "channel",
'store' || "ssr"."s_store_id" AS "id", CONCAT('store', "ssr"."s_store_id") AS "id",
"ssr"."sales" AS "sales", "ssr"."sales" AS "sales",
"ssr"."returns1" AS "returns1", "ssr"."returns1" AS "returns1",
"ssr"."profit" - "ssr"."profit_loss" AS "profit" "ssr"."profit" - "ssr"."profit_loss" AS "profit"
@ -8611,7 +8611,7 @@ WITH "date_dim_2" AS (
"warehouse"."w_county" AS "w_county", "warehouse"."w_county" AS "w_county",
"warehouse"."w_state" AS "w_state", "warehouse"."w_state" AS "w_state",
"warehouse"."w_country" AS "w_country", "warehouse"."w_country" AS "w_country",
'ZOUROS' || ',' || 'ZHOU' AS "ship_carriers", 'ZOUROS,ZHOU' AS "ship_carriers",
"date_dim"."d_year" AS "year1", "date_dim"."d_year" AS "year1",
SUM( SUM(
CASE CASE
@ -8806,7 +8806,7 @@ WITH "date_dim_2" AS (
"warehouse"."w_county" AS "w_county", "warehouse"."w_county" AS "w_county",
"warehouse"."w_state" AS "w_state", "warehouse"."w_state" AS "w_state",
"warehouse"."w_country" AS "w_country", "warehouse"."w_country" AS "w_country",
'ZOUROS' || ',' || 'ZHOU' AS "ship_carriers", 'ZOUROS,ZHOU' AS "ship_carriers",
"date_dim"."d_year" AS "year1", "date_dim"."d_year" AS "year1",
SUM( SUM(
CASE CASE
@ -10833,9 +10833,11 @@ LEFT JOIN "ws"
AND "ws"."ws_item_sk" = "ss"."ss_item_sk" AND "ws"."ws_item_sk" = "ss"."ss_item_sk"
AND "ws"."ws_sold_year" = "ss"."ss_sold_year" AND "ws"."ws_sold_year" = "ss"."ss_sold_year"
WHERE WHERE
"ss"."ss_sold_year" = 1999 "cs"."cs_qty" > 0
AND COALESCE("cs"."cs_qty", 0) > 0 AND "ss"."ss_sold_year" = 1999
AND COALESCE("ws"."ws_qty", 0) > 0 AND "ws"."ws_qty" > 0
AND NOT "cs"."cs_qty" IS NULL
AND NOT "ws"."ws_qty" IS NULL
ORDER BY ORDER BY
"ss_item_sk", "ss_item_sk",
"ss"."ss_qty" DESC, "ss"."ss_qty" DESC,
@ -11121,7 +11123,7 @@ WITH "date_dim_2" AS (
), "cte_4" AS ( ), "cte_4" AS (
SELECT SELECT
'catalog channel' AS "channel", 'catalog channel' AS "channel",
'catalog_page' || "csr"."catalog_page_id" AS "id", CONCAT('catalog_page', "csr"."catalog_page_id") AS "id",
"csr"."sales" AS "sales", "csr"."sales" AS "sales",
"csr"."returns1" AS "returns1", "csr"."returns1" AS "returns1",
"csr"."profit" AS "profit" "csr"."profit" AS "profit"
@ -11129,7 +11131,7 @@ WITH "date_dim_2" AS (
UNION ALL UNION ALL
SELECT SELECT
'web channel' AS "channel", 'web channel' AS "channel",
'web_site' || "wsr"."web_site_id" AS "id", CONCAT('web_site', "wsr"."web_site_id") AS "id",
"wsr"."sales" AS "sales", "wsr"."sales" AS "sales",
"wsr"."returns1" AS "returns1", "wsr"."returns1" AS "returns1",
"wsr"."profit" AS "profit" "wsr"."profit" AS "profit"
@ -11137,7 +11139,7 @@ WITH "date_dim_2" AS (
), "x" AS ( ), "x" AS (
SELECT SELECT
'store channel' AS "channel", 'store channel' AS "channel",
'store' || "ssr"."store_id" AS "id", CONCAT('store', "ssr"."store_id") AS "id",
"ssr"."sales" AS "sales", "ssr"."sales" AS "sales",
"ssr"."returns1" AS "returns1", "ssr"."returns1" AS "returns1",
"ssr"."profit" AS "profit" "ssr"."profit" AS "profit"
@ -11569,7 +11571,7 @@ ORDER BY c_customer_id
LIMIT 100; LIMIT 100;
SELECT SELECT
"customer"."c_customer_id" AS "customer_id", "customer"."c_customer_id" AS "customer_id",
"customer"."c_last_name" || ', ' || "customer"."c_first_name" AS "customername" CONCAT("customer"."c_last_name", ', ', "customer"."c_first_name") AS "customername"
FROM "customer" AS "customer" FROM "customer" AS "customer"
JOIN "customer_address" AS "customer_address" JOIN "customer_address" AS "customer_address"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk" ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"

View file

@ -723,3 +723,24 @@ class TestExecutor(unittest.TestCase):
result = execute(sql, tables=tables) result = execute(sql, tables=tables)
self.assertEqual(result.columns, columns) self.assertEqual(result.columns, columns)
self.assertEqual(result.rows, expected) self.assertEqual(result.rows, expected)
def test_dict_values(self):
tables = {
"foo": [{"raw": {"name": "Hello, World"}}],
}
result = execute("SELECT raw:name AS name FROM foo", read="snowflake", tables=tables)
self.assertEqual(result.columns, ("NAME",))
self.assertEqual(result.rows, [("Hello, World",)])
tables = {
'"ITEM"': [
{"id": 1, "attributes": {"flavor": "cherry", "taste": "sweet"}},
{"id": 2, "attributes": {"flavor": "lime", "taste": "sour"}},
{"id": 3, "attributes": {"flavor": "apple", "taste": None}},
]
}
result = execute("SELECT i.attributes.flavor FROM `ITEM` i", read="bigquery", tables=tables)
self.assertEqual(result.columns, ("flavor",))
self.assertEqual(result.rows, [("cherry",), ("lime",), ("apple",)])

View file

@ -277,6 +277,20 @@ class TestOptimizer(unittest.TestCase):
self.assertEqual(exp.true(), optimizer.simplify.simplify(expression)) self.assertEqual(exp.true(), optimizer.simplify.simplify(expression))
self.assertEqual(exp.true(), optimizer.simplify.simplify(expression.this)) self.assertEqual(exp.true(), optimizer.simplify.simplify(expression.this))
# CONCAT in (e.g.) Presto is parsed as Concat instead of SafeConcat which is the default type
# This test checks that simplify_concat preserves the corresponding expression types.
concat = parse_one("CONCAT('a', x, 'b', 'c')", read="presto")
simplified_concat = optimizer.simplify.simplify(concat)
safe_concat = parse_one("CONCAT('a', x, 'b', 'c')")
simplified_safe_concat = optimizer.simplify.simplify(safe_concat)
self.assertIs(type(simplified_concat), exp.Concat)
self.assertIs(type(simplified_safe_concat), exp.SafeConcat)
self.assertEqual("CONCAT('a', x, 'bc')", simplified_concat.sql(dialect="presto"))
self.assertEqual("CONCAT('a', x, 'bc')", simplified_safe_concat.sql())
def test_unnest_subqueries(self): def test_unnest_subqueries(self):
self.check_file( self.check_file(
"unnest_subqueries", "unnest_subqueries",

View file

@ -17,6 +17,7 @@ class TestTokens(unittest.TestCase):
("foo /*comment 1*/ /*comment 2*/", ["comment 1", "comment 2"]), ("foo /*comment 1*/ /*comment 2*/", ["comment 1", "comment 2"]),
("foo\n-- comment", [" comment"]), ("foo\n-- comment", [" comment"]),
("1 /*/2 */", ["/2 "]), ("1 /*/2 */", ["/2 "]),
("1\n/*comment*/;", ["comment"]),
] ]
for sql, comment in sql_comment: for sql, comment in sql_comment:

View file

@ -90,6 +90,19 @@ class TestTranspile(unittest.TestCase):
self.validate("SELECT 3>=3", "SELECT 3 >= 3") self.validate("SELECT 3>=3", "SELECT 3 >= 3")
def test_comments(self): def test_comments(self):
self.validate("SELECT\n foo\n/* comments */\n;", "SELECT foo /* comments */")
self.validate(
"SELECT * FROM a INNER /* comments */ JOIN b",
"SELECT * FROM a /* comments */ INNER JOIN b",
)
self.validate(
"SELECT * FROM a LEFT /* comment 1 */ OUTER /* comment 2 */ JOIN b",
"SELECT * FROM a /* comment 1 */ /* comment 2 */ LEFT OUTER JOIN b",
)
self.validate(
"SELECT CASE /* test */ WHEN a THEN b ELSE c END",
"SELECT CASE WHEN a THEN b ELSE c END /* test */",
)
self.validate("SELECT 1 /*/2 */", "SELECT 1 /* /2 */") self.validate("SELECT 1 /*/2 */", "SELECT 1 /* /2 */")
self.validate("SELECT */*comment*/", "SELECT * /* comment */") self.validate("SELECT */*comment*/", "SELECT * /* comment */")
self.validate( self.validate(
@ -308,6 +321,7 @@ DROP TABLE IF EXISTS db.tba""",
) )
self.validate( self.validate(
""" """
-- comment4
CREATE TABLE db.tba AS CREATE TABLE db.tba AS
SELECT a, b, c SELECT a, b, c
FROM tb_01 FROM tb_01
@ -316,8 +330,10 @@ DROP TABLE IF EXISTS db.tba""",
a = 1 AND b = 2 --comment6 a = 1 AND b = 2 --comment6
-- and c = 1 -- and c = 1
-- comment7 -- comment7
;
""", """,
"""CREATE TABLE db.tba AS """/* comment4 */
CREATE TABLE db.tba AS
SELECT SELECT
a, a,
b, b,
@ -329,6 +345,44 @@ WHERE
/* comment7 */""", /* comment7 */""",
pretty=True, pretty=True,
) )
self.validate(
"""
SELECT
-- This is testing comments
col,
-- 2nd testing comments
CASE WHEN a THEN b ELSE c END as d
FROM t
""",
"""SELECT
col, /* This is testing comments */
CASE WHEN a THEN b ELSE c END /* 2nd testing comments */ AS d
FROM t""",
pretty=True,
)
self.validate(
"""
SELECT * FROM a
-- comments
INNER JOIN b
""",
"""SELECT
*
FROM a
/* comments */
INNER JOIN b""",
pretty=True,
)
self.validate(
"SELECT * FROM a LEFT /* comment 1 */ OUTER /* comment 2 */ JOIN b",
"""SELECT
*
FROM a
/* comment 1 */
/* comment 2 */
LEFT OUTER JOIN b""",
pretty=True,
)
def test_types(self): def test_types(self):
self.validate("INT 1", "CAST(1 AS INT)") self.validate("INT 1", "CAST(1 AS INT)")