Repository: andialbrecht/sqlparse

Issue:
sqlparse.utils.remove_quotes does not remove backtick
Should back tick `` ` `` considered to be a quote character ?

For example `` `test_schema` `` when passed to remove_quotes() should return schema name without the backtick. 
[https://github.com/andialbrecht/sqlparse/blob/23d29933ddc4272b495d36e0e32d3eaf0c3ef76d/sqlparse/utils.py#L58](https://github.com/andialbrecht/sqlparse/blob/23d29933ddc4272b495d36e0e32d3eaf0c3ef76d/sqlparse/utils.py#L58)

I'm not too sure if adding backtick to this line will break anything. If it's OK to do, I'll send a PR.



Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht) Report
> Merging [#629](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht) (797792c) into [master](https://codecov.io/gh/andialbrecht/sqlparse/commit/23d29933ddc4272b495d36e0e32d3eaf0c3ef76d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht) (23d2993) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/andialbrecht/sqlparse/pull/629/graphs/tree.svg?width=650&height=150&src=pr&token=BCoSopytDp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht)](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht)

```diff
@@           Coverage Diff           @@
##           master     #629   +/-   ##
=======================================
  Coverage   96.82%   96.82%           
=======================================
  Files          20       20           
  Lines        1514     1514           
=======================================
  Hits         1466     1466           
  Misses         48       48           
```


| [Impacted Files](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht) | Coverage Δ | |
|---|---|---|
| [sqlparse/utils.py](https://codecov.io/gh/andialbrecht/sqlparse/pull/629/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht#diff-c3FscGFyc2UvdXRpbHMucHk=) | `98.24% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht). Last update [23d2993...797792c](https://codecov.io/gh/andialbrecht/sqlparse/pull/629?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andi+Albrecht).


Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..1cde398
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,71 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ master ]
+  schedule:
+    - cron: '25 5 * * 1'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'python' ]
+        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+        # Learn more:
+        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v3
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v2
+      with:
+        languages: ${{ matrix.language }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v2
+
+    # ℹ️ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml
new file mode 100644
index 0000000..4f16585
--- /dev/null
+++ b/.github/workflows/python-app.yml
@@ -0,0 +1,36 @@
+# This workflow will install Python dependencies, run tests and lint with a single version of Python
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
+
+name: Python application
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11-dev"]
+
+    steps:
+    - uses: actions/checkout@v3
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v4
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install codecov flake8 pytest pytest-cov
+        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+    - name: Lint with flake8
+      run: flake8 sqlparse --count --max-complexity=31 --show-source --statistics
+    - name: Test with pytest
+      run: pytest --cov=sqlparse
+    - name: Publish to codecov
+      run: codecov
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index b9774a2..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: python
-python:
-  - "3.5"
-  - "3.6"
-  - "3.7"
-  - "3.8"
-  - "3.9-dev"
-  - "nightly"
-  - "pypy3"
-
-matrix:
-  include:
-    - stage: codecheck
-      python: 3.8
-      install:
-        - pip install flake8
-      script:
-        - flake8 sqlparse
-      after_success: skip
-
-install:
-  - pip install -Uq pytest pytest-cov codecov
-  - pytest --version
-
-script:
-  - pytest --cov=sqlparse
-
-after_success:
-    - codecov
diff --git a/AUTHORS b/AUTHORS
index 2e31ae0..e1e2089 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,6 +8,7 @@ project: https://bitbucket.org/gutworth/six.
 
 Alphabetical list of contributors:
 * Adam Greenhall <agreenhall@lyft.com>
+* Aki Ariga <chezou+github@gmail.com>
 * Alexander Beedie <ayembee@gmail.com>
 * Alexey Malyshev <nostrict@gmail.com>
 * ali-tny <aliteeney@googlemail.com>
@@ -16,20 +17,24 @@ Alphabetical list of contributors:
 * atronah <atronah.ds@gmail.com>
 * casey <casey@cloudera.com>
 * Cauê Beloni <cbeloni@gmail.com>
+* Christian Clauss <cclauss@me.com>
 * circld <circld1@gmail.com>
 * Corey Zumar <corey.zumar@databricks.com>
 * Cristian Orellana <cristiano@groupon.com>
 * Dag Wieers <dag@wieers.com>
+* Daniel Harding <dharding@living180.net>
 * Darik Gamble <darik.gamble@gmail.com>
 * Demetrio92 <Demetrio.Rodriguez.T@gmail.com>
 * Dennis Taylor <dennis.taylor@clio.com>
 * Dvořák Václav <Vaclav.Dvorak@ysoft.com>
+* Erik Cederstrand <erik@adamatics.com>
 * Florian Bauer <florian.bauer@zmdi.com>
 * Fredy Wijaya <fredy.wijaya@gmail.com>
 * Gavin Wahl <gwahl@fusionbox.com>
 * hurcy <cinyoung.hur@gmail.com>
 * Ian Robertson <ian.robertson@capitalone.com>
 * JacekPliszka <Jacek.Pliszka@gmail.com>
+* JavierPan <PeterSandwich@users.noreply.github.com>
 * Jean-Martin Archer <jm@jmartin.ca>
 * Jesús Leganés Combarro "Piranna" <piranna@gmail.com>
 * Johannes Hoff <johshoff@gmail.com>
@@ -44,6 +49,7 @@ Alphabetical list of contributors:
 * Mike Amy <cocoade@googlemail.com>
 * mulos <daniel.strackbein@gmail.com>
 * Oleg Broytman <phd@phdru.name>
+* osmnv <80402144+osmnv@users.noreply.github.com>
 * Patrick Schemitz <patrick.schemitz@digitalbriefkasten.de>
 * Pi Delport <pjdelport@gmail.com>
 * Prudhvi Vatala <pvatala@gmail.com>
@@ -55,6 +61,7 @@ Alphabetical list of contributors:
 * Ryan Wooden <rygwdn@gmail.com>
 * saaj <id@saaj.me>
 * Shen Longxing <shenlongxing2012@gmail.com>
+* Simon Heisterkamp <she@delegate.dk>
 * Sjoerd Job Postmus
 * Soloman Weng <soloman1124@gmail.com>
 * spigwitmer <itgpmc@gmail.com>
diff --git a/CHANGELOG b/CHANGELOG
index eb5c381..83510b5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,12 +3,45 @@ Development Version
 
 Enhancements
 
+* Add support for DIV operator (pr664, by chezou).
+* Add support for additional SPARK keywords (pr643, by mrmasterplan).
+* Avoid tokens copy (pr622, by living180).
+* Add REGEXP as a comparision (pr647, by PeterSandwich).
+* Add DISTINCTROW keyword for MS Access (issue677).
+* Improve parsing of CREATE TABLE AS SELECT (pr662, by chezou).
+
+Bug Fixes
+
+* Fix spelling of INDICATOR keyword (pr653, by ptld).
+* Fix formatting error in EXTRACT function (issue562, issue670, pr676, by ecederstrand).
+* Fix bad parsing of create table statements that use lower case (issue217, pr642, by mrmasterplan).
+
+Other
+
+* Update github actions to test on Python 3.10 as well (pr661, by cclaus).
+
+
+Release 0.4.2 (Sep 10, 2021)
+----------------------------
+
+Notable Changes
+
+* IMPORTANT: This release fixes a security vulnerability in the
+  strip comments filter. In this filter a regular expression that was
+  vulnerable to ReDOS (Regular Expression Denial of Service) was
+  used. See the security advisory for details: https://github.com/andialbrecht/sqlparse/security/advisories/GHSA-p5w8-wqhj-9hhf
+  The vulnerability was discovered by @erik-krogh and @yoff from
+  GitHub Security Lab (GHSL). Thanks for reporting!
+
+Enhancements
+
 * Add ELSIF as keyword (issue584).
 * Add CONFLICT and ON_ERROR_STOP keywords (pr595, by j-martin).
 
 Bug Fixes
 
 * Fix parsing of backticks (issue588).
+* Fix parsing of scientific number (issue399).
 
 
 Release 0.4.1 (Oct 08, 2020)
@@ -68,7 +101,7 @@ Bug Fixes
 * Remove support for parsing double slash comments introduced in
   0.3.0 (issue456) as it had some side-effects with other dialects and
   doesn't seem to be widely used (issue476).
-* Restrict detection of alias names to objects that acutally could
+* Restrict detection of alias names to objects that actually could
   have an alias (issue455, adopted some parts of pr509 by john-bodley).
 * Fix parsing of date/time literals (issue438, by vashek).
 * Fix initialization of TokenList (issue499, pr505 by john-bodley).
diff --git a/README.rst b/README.rst
index 92e15c1..df4e7e3 100644
--- a/README.rst
+++ b/README.rst
@@ -4,6 +4,7 @@ python-sqlparse - Parse SQL statements
 |buildstatus|_
 |coverage|_
 |docs|_
+|packageversion|_
 
 .. docincludebegin
 
@@ -59,7 +60,7 @@ Documentation
    https://sqlparse.readthedocs.io/
 
 Online Demo
-  https://sqlformat.org/
+   https://sqlformat.org/
 
 
 sqlparse is licensed under the BSD license.
@@ -67,9 +68,11 @@ sqlparse is licensed under the BSD license.
 Parts of the code are based on pygments written by Georg Brandl and others.
 pygments-Homepage: http://pygments.org/
 
-.. |buildstatus| image:: https://secure.travis-ci.org/andialbrecht/sqlparse.png?branch=master
-.. _buildstatus: https://travis-ci.org/#!/andialbrecht/sqlparse
+.. |buildstatus| image:: https://github.com/andialbrecht/sqlparse/actions/workflows/python-app.yml/badge.svg
+.. _buildstatus: https://github.com/andialbrecht/sqlparse/actions/workflows/python-app.yml
 .. |coverage| image:: https://codecov.io/gh/andialbrecht/sqlparse/branch/master/graph/badge.svg
 .. _coverage: https://codecov.io/gh/andialbrecht/sqlparse
 .. |docs| image:: https://readthedocs.org/projects/sqlparse/badge/?version=latest
 .. _docs: https://sqlparse.readthedocs.io/en/latest/?badge=latest
+.. |packageversion| image:: https://img.shields.io/pypi/v/sqlparse?color=%2334D058&label=pypi%20package
+.. _packageversion: https://pypi.org/project/sqlparse
diff --git a/setup.cfg b/setup.cfg
index a9127c0..0843b70 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -20,6 +20,7 @@ classifiers =
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
+    Programming Language :: Python :: 3.10
     Programming Language :: Python :: Implementation :: CPython
     Programming Language :: Python :: Implementation :: PyPy
     Topic :: Database
diff --git a/sqlparse/__init__.py b/sqlparse/__init__.py
index bb9b88a..33be0ee 100644
--- a/sqlparse/__init__.py
+++ b/sqlparse/__init__.py
@@ -16,7 +16,7 @@ from sqlparse import filters
 from sqlparse import formatter
 
 
-__version__ = '0.4.2.dev0'
+__version__ = '0.4.3.dev0'
 __all__ = ['engine', 'filters', 'formatter', 'sql', 'tokens', 'cli']
 
 
diff --git a/sqlparse/engine/grouping.py b/sqlparse/engine/grouping.py
index 175ae8e..86d8fc6 100644
--- a/sqlparse/engine/grouping.py
+++ b/sqlparse/engine/grouping.py
@@ -91,13 +91,20 @@ def group_tzcasts(tlist):
     def match(token):
         return token.ttype == T.Keyword.TZCast
 
-    def valid(token):
+    def valid_prev(token):
         return token is not None
 
+    def valid_next(token):
+        return token is not None and (
+            token.is_whitespace
+            or token.match(T.Keyword, 'AS')
+            or token.match(*sql.TypedLiteral.M_CLOSE)
+        )
+
     def post(tlist, pidx, tidx, nidx):
         return pidx, nidx
 
-    _group(tlist, sql.Identifier, match, valid, valid, post)
+    _group(tlist, sql.Identifier, match, valid_prev, valid_next, post)
 
 
 def group_typed_literal(tlist):
@@ -334,12 +341,15 @@ def group_aliased(tlist):
 def group_functions(tlist):
     has_create = False
     has_table = False
+    has_as = False
     for tmp_token in tlist.tokens:
-        if tmp_token.value == 'CREATE':
+        if tmp_token.value.upper() == 'CREATE':
             has_create = True
-        if tmp_token.value == 'TABLE':
+        if tmp_token.value.upper() == 'TABLE':
             has_table = True
-    if has_create and has_table:
+        if tmp_token.value == 'AS':
+            has_as = True
+    if has_create and has_table and not has_as:
         return
 
     tidx, token = tlist.token_next_by(t=T.Name)
diff --git a/sqlparse/filters/others.py b/sqlparse/filters/others.py
index e0e1ca1..6905f2d 100644
--- a/sqlparse/filters/others.py
+++ b/sqlparse/filters/others.py
@@ -22,7 +22,10 @@ class StripCommentsFilter:
         def _get_insert_token(token):
             """Returns either a whitespace or the line breaks from token."""
             # See issue484 why line breaks should be preserved.
-            m = re.search(r'((\r\n|\r|\n)+) *$', token.value)
+            # Note: The actual value for a line break is replaced by \n
+            # in SerializerUnicode which will be executed in the
+            # postprocessing state.
+            m = re.search(r'((\r|\n)+) *$', token.value)
             if m is not None:
                 return sql.Token(T.Whitespace.Newline, m.groups()[0])
             else:
diff --git a/sqlparse/keywords.py b/sqlparse/keywords.py
index 26dd3b3..0f3a459 100644
--- a/sqlparse/keywords.py
+++ b/sqlparse/keywords.py
@@ -16,6 +16,7 @@ def is_keyword(value):
             or KEYWORDS_ORACLE.get(val)
             or KEYWORDS_PLPGSQL.get(val)
             or KEYWORDS_HQL.get(val)
+            or KEYWORDS_MSACCESS.get(val)
             or KEYWORDS.get(val, tokens.Name)), value
 
 
@@ -62,7 +63,7 @@ SQL_REGEX = {
         (r'(?<=\.)[A-ZÀ-Ü]\w*', tokens.Name),  # .'Name'
         (r'[A-ZÀ-Ü]\w*(?=\()', tokens.Name),  # side effect: change kw to func
         (r'-?0x[\dA-F]+', tokens.Number.Hexadecimal),
-        (r'-?\d*(\.\d+)?E-?\d+', tokens.Number.Float),
+        (r'-?\d+(\.\d+)?E-?\d+', tokens.Number.Float),
         (r'(?![_A-ZÀ-Ü])-?(\d+(\.\d*)|\.\d+)(?![_A-ZÀ-Ü])',
          tokens.Number.Float),
         (r'(?![_A-ZÀ-Ü])-?\d+(?![_A-ZÀ-Ü])', tokens.Number.Integer),
@@ -90,6 +91,7 @@ SQL_REGEX = {
          tokens.Keyword),
         (r"(AT|WITH')\s+TIME\s+ZONE\s+'[^']+'", tokens.Keyword.TZCast),
         (r'(NOT\s+)?(LIKE|ILIKE|RLIKE)\b', tokens.Operator.Comparison),
+        (r'(NOT\s+)?(REGEXP)\b', tokens.Operator.Comparison),
         (r'[0-9_A-ZÀ-Ü][_$#\w]*', is_keyword),
         (r'[;:()\[\],\.]', tokens.Punctuation),
         (r'[<>=~!]+', tokens.Operator.Comparison),
@@ -241,6 +243,7 @@ KEYWORDS = {
     'DISABLE': tokens.Keyword,
     'DISCONNECT': tokens.Keyword,
     'DISPATCH': tokens.Keyword,
+    'DIV': tokens.Operator,
     'DO': tokens.Keyword,
     'DOMAIN': tokens.Keyword,
     'DYNAMIC': tokens.Keyword,
@@ -314,7 +317,7 @@ KEYWORDS = {
     'INCREMENT': tokens.Keyword,
     'INDEX': tokens.Keyword,
 
-    'INDITCATOR': tokens.Keyword,
+    'INDICATOR': tokens.Keyword,
     'INFIX': tokens.Keyword,
     'INHERITS': tokens.Keyword,
     'INITIAL': tokens.Keyword,
@@ -907,6 +910,7 @@ KEYWORDS_HQL = {
     'INLINE': tokens.Keyword,
     'INSTR': tokens.Keyword,
     'LEN': tokens.Keyword,
+    'MAP': tokens.Name.Builtin,
     'MAXELEMENT': tokens.Keyword,
     'MAXINDEX': tokens.Keyword,
     'MAX_PART_DATE': tokens.Keyword,
@@ -938,9 +942,12 @@ KEYWORDS_HQL = {
     'SQRT': tokens.Keyword,
     'STACK': tokens.Keyword,
     'STR': tokens.Keyword,
+    'STRING': tokens.Name.Builtin,
+    'STRUCT': tokens.Name.Builtin,
     'SUBSTR': tokens.Keyword,
     'SUMMARY': tokens.Keyword,
     'TBLPROPERTIES': tokens.Keyword,
+    'TIMESTAMP': tokens.Name.Builtin,
     'TIMESTAMP_ISO': tokens.Keyword,
     'TO_CHAR': tokens.Keyword,
     'TO_DATE': tokens.Keyword,
@@ -956,3 +963,8 @@ KEYWORDS_HQL = {
     'BREAK': tokens.Keyword,
     'LEAVE': tokens.Keyword,
 }
+
+
+KEYWORDS_MSACCESS = {
+    'DISTINCTROW': tokens.Keyword,
+}
diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 6a32c26..586cd21 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -234,16 +234,16 @@ class TokenList(Token):
 
         if reverse:
             assert end is None
-            for idx in range(start - 2, -1, -1):
-                token = self.tokens[idx]
-                for func in funcs:
-                    if func(token):
-                        return idx, token
+            indexes = range(start - 2, -1, -1)
         else:
-            for idx, token in enumerate(self.tokens[start:end], start=start):
-                for func in funcs:
-                    if func(token):
-                        return idx, token
+            if end is None:
+                end = len(self.tokens)
+            indexes = range(start, end)
+        for idx in indexes:
+            token = self.tokens[idx]
+            for func in funcs:
+                if func(token):
+                    return idx, token
         return None, None
 
     def token_first(self, skip_ws=True, skip_cm=False):
diff --git a/sqlparse/utils.py b/sqlparse/utils.py
index 299a84c..512f038 100644
--- a/sqlparse/utils.py
+++ b/sqlparse/utils.py
@@ -55,7 +55,7 @@ def remove_quotes(val):
     """Helper that removes surrounding quotes from strings."""
     if val is None:
         return
-    if val[0] in ('"', "'") and val[0] == val[-1]:
+    if val[0] in ('"', "'", '`') and val[0] == val[-1]:
         val = val[1:-1]
     return val
 


Test patch:
diff --git a/tests/test_format.py b/tests/test_format.py
index 7117d9d..70bb805 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -84,6 +84,23 @@ class TestFormat:
         res = sqlparse.format(sql, strip_comments=True)
         assert res == 'select (select 2)'
 
+    def test_strip_comments_preserves_linebreak(self):
+        sql = 'select * -- a comment\r\nfrom foo'
+        res = sqlparse.format(sql, strip_comments=True)
+        assert res == 'select *\nfrom foo'
+        sql = 'select * -- a comment\nfrom foo'
+        res = sqlparse.format(sql, strip_comments=True)
+        assert res == 'select *\nfrom foo'
+        sql = 'select * -- a comment\rfrom foo'
+        res = sqlparse.format(sql, strip_comments=True)
+        assert res == 'select *\nfrom foo'
+        sql = 'select * -- a comment\r\n\r\nfrom foo'
+        res = sqlparse.format(sql, strip_comments=True)
+        assert res == 'select *\n\nfrom foo'
+        sql = 'select * -- a comment\n\nfrom foo'
+        res = sqlparse.format(sql, strip_comments=True)
+        assert res == 'select *\n\nfrom foo'
+
     def test_strip_ws(self):
         f = lambda sql: sqlparse.format(sql, strip_whitespace=True)
         s = 'select\n* from      foo\n\twhere  ( 1 = 2 )\n'
diff --git a/tests/test_grouping.py b/tests/test_grouping.py
index cf629e9..546ad4b 100644
--- a/tests/test_grouping.py
+++ b/tests/test_grouping.py
@@ -324,6 +324,11 @@ def test_grouping_alias_case():
     assert p.tokens[0].get_alias() == 'foo'
 
 
+def test_grouping_alias_ctas():
+    p = sqlparse.parse('CREATE TABLE tbl1 AS SELECT coalesce(t1.col1, 0) AS col1 FROM t1')[0]
+    assert p.tokens[10].get_alias() == 'col1'
+    assert isinstance(p.tokens[10].tokens[0], sql.Function)
+
 def test_grouping_subquery_no_parens():
     # Not totally sure if this is the right approach...
     # When a THEN clause contains a subquery w/o parenthesis around it *and*
@@ -655,3 +660,7 @@ def test_grouping_as_cte():
     assert p[0].get_alias() is None
     assert p[2].value == 'AS'
     assert p[4].value == 'WITH'
+
+def test_grouping_create_table():
+    p = sqlparse.parse("create table db.tbl (a string)")[0].tokens
+    assert p[4].value == "db.tbl"
diff --git a/tests/test_parse.py b/tests/test_parse.py
index 5fe6ed2..caba537 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -132,6 +132,12 @@ def test_parse_nested_function():
     assert type(t[0]) is sql.Function
 
 
+def test_parse_div_operator():
+    p = sqlparse.parse('col1 DIV 5 AS div_col1')[0].tokens
+    assert p[0].tokens[0].tokens[2].ttype is T.Operator
+    assert p[0].get_alias() == 'div_col1'
+
+
 def test_quoted_identifier():
     t = sqlparse.parse('select x.y as "z" from foo')[0].tokens
     assert isinstance(t[2], sql.Identifier)
@@ -188,11 +194,16 @@ def test_placeholder(ph):
     assert p[0].ttype is T.Name.Placeholder
 
 
-@pytest.mark.parametrize('num', ['6.67428E-8', '1.988e33', '1e-12'])
-def test_scientific_numbers(num):
+@pytest.mark.parametrize('num, expected', [
+    ('6.67428E-8', T.Number.Float),
+    ('1.988e33', T.Number.Float),
+    ('1e-12', T.Number.Float),
+    ('e1', None),
+])
+def test_scientific_numbers(num, expected):
     p = sqlparse.parse(num)[0].tokens
     assert len(p) == 1
-    assert p[0].ttype is T.Number.Float
+    assert p[0].ttype is expected
 
 
 def test_single_quotes_are_strings():
@@ -336,7 +347,8 @@ def test_pprint():
         "|  |  `- 0 Name 'd0'",
         "|  |- 10 Punctuation ','",
         "|  |- 11 Whitespace ' '",
-        "|  `- 12 Float 'e0'",
+        "|  `- 12 Identifier 'e0'",
+        "|     `- 0 Name 'e0'",
         "|- 3 Whitespace ' '",
         "|- 4 Keyword 'from'",
         "|- 5 Whitespace ' '",
diff --git a/tests/test_regressions.py b/tests/test_regressions.py
index 38d1840..4ffc69f 100644
--- a/tests/test_regressions.py
+++ b/tests/test_regressions.py
@@ -401,6 +401,15 @@ def test_issue489_tzcasts():
     assert p.tokens[-1].get_alias() == 'foo'
 
 
+def test_issue562_tzcasts():
+    # Test that whitespace between 'from' and 'bar' is retained
+    formatted = sqlparse.format(
+        'SELECT f(HOUR from bar AT TIME ZONE \'UTC\') from foo', reindent=True
+    )
+    assert formatted == \
+           'SELECT f(HOUR\n         from bar AT TIME ZONE \'UTC\')\nfrom foo'
+
+
 def test_as_in_parentheses_indents():
     # did raise NoneType has no attribute is_group in _process_parentheses
     formatted = sqlparse.format('(as foo)', reindent=True)