Skip to content

Commit 5bb129d

Browse files
committed
Thread-safe initialization of Lexer class (fixes andialbrecht#730).
1 parent 02819f6 commit 5bb129d

File tree

2 files changed

+12
-8
lines changed

2 files changed

+12
-8
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Bug Fixes
1818
* Ignore dunder attributes when creating Tokens (issue672).
1919
* Allow operators to precede dollar-quoted strings (issue763).
2020
* Fix parsing of nested order clauses (issue745, pr746 by john-bodley).
21+
* Thread-safe initialization of Lexer class (issue730).
2122

2223

2324
Release 0.4.4 (Apr 18, 2023)

sqlparse/lexer.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
"""SQL Lexer"""
99
import re
10+
from threading import Lock
1011

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

2627
_default_instance = None
28+
_lock = Lock()
2729

2830
# Development notes:
2931
# - This class is prepared to be able to support additional SQL dialects
3032
# in the future by adding additional functions that take the place of
31-
# the function default_initialization()
33+
# the function default_initialization().
3234
# - The lexer class uses an explicit singleton behavior with the
3335
# instance-getter method get_default_instance(). This mechanism has
3436
# the advantage that the call signature of the entry-points to the
3537
# sqlparse library are not affected. Also, usage of sqlparse in third
36-
# party code does not need to be adapted. On the other hand, singleton
37-
# behavior is not thread safe, and the current implementation does not
38-
# easily allow for multiple SQL dialects to be parsed in the same
39-
# process. Such behavior can be supported in the future by passing a
38+
# party code does not need to be adapted. On the other hand, the current
39+
# implementation does not easily allow for multiple SQL dialects to be
40+
# parsed in the same process.
41+
# Such behavior can be supported in the future by passing a
4042
# suitably initialized lexer object as an additional parameter to the
4143
# entry-point functions (such as `parse`). Code will need to be written
4244
# to pass down and utilize such an object. The current implementation
@@ -47,9 +49,10 @@ class Lexer:
4749
def get_default_instance(cls):
4850
"""Returns the lexer instance used internally
4951
by the sqlparse core functions."""
50-
if cls._default_instance is None:
51-
cls._default_instance = cls()
52-
cls._default_instance.default_initialization()
52+
with cls._lock:
53+
if cls._default_instance is None:
54+
cls._default_instance = cls()
55+
cls._default_instance.default_initialization()
5356
return cls._default_instance
5457

5558
def default_initialization(self):

0 commit comments

Comments
 (0)