Skip to content

Commit

Permalink
Thread-safe initialization of Lexer class (fixes #730).
Browse files Browse the repository at this point in the history
  • Loading branch information
andialbrecht committed Mar 16, 2024
1 parent 02819f6 commit 5bb129d
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Bug Fixes
* Ignore dunder attributes when creating Tokens (issue672).
* Allow operators to precede dollar-quoted strings (issue763).
* Fix parsing of nested order clauses (issue745, pr746 by john-bodley).
* Thread-safe initialization of Lexer class (issue730).


Release 0.4.4 (Apr 18, 2023)
Expand Down
19 changes: 11 additions & 8 deletions sqlparse/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

"""SQL Lexer"""
import re
from threading import Lock

# This code is based on the SqlLexer in pygments.
# http://pygments.org/
Expand All @@ -24,19 +25,20 @@ class Lexer:
To add support for additional keywords, use the `add_keywords` method."""

_default_instance = None
_lock = Lock()

# Development notes:
# - This class is prepared to be able to support additional SQL dialects
# in the future by adding additional functions that take the place of
# the function default_initialization()
# the function default_initialization().
# - The lexer class uses an explicit singleton behavior with the
# instance-getter method get_default_instance(). This mechanism has
# the advantage that the call signature of the entry-points to the
# sqlparse library are not affected. Also, usage of sqlparse in third
# party code does not need to be adapted. On the other hand, singleton
# behavior is not thread safe, and the current implementation does not
# easily allow for multiple SQL dialects to be parsed in the same
# process. Such behavior can be supported in the future by passing a
# party code does not need to be adapted. On the other hand, the current
# implementation does not easily allow for multiple SQL dialects to be
# parsed in the same process.
# Such behavior can be supported in the future by passing a
# suitably initialized lexer object as an additional parameter to the
# entry-point functions (such as `parse`). Code will need to be written
# to pass down and utilize such an object. The current implementation
Expand All @@ -47,9 +49,10 @@ class Lexer:
def get_default_instance(cls):
"""Returns the lexer instance used internally
by the sqlparse core functions."""
if cls._default_instance is None:
cls._default_instance = cls()
cls._default_instance.default_initialization()
with cls._lock:
if cls._default_instance is None:
cls._default_instance = cls()
cls._default_instance.default_initialization()
return cls._default_instance

def default_initialization(self):
Expand Down

0 comments on commit 5bb129d

Please sign in to comment.