diff --git a/product/ZSQLCatalog/SearchText/SearchTextParser.py b/product/ZSQLCatalog/SearchText/SearchTextParser.py
index e75581af1ea233e587cbbf628a6f9c217fffdfd6..64784e221c6a799d01258a64ce62da0345125528 100755
--- a/product/ZSQLCatalog/SearchText/SearchTextParser.py
+++ b/product/ZSQLCatalog/SearchText/SearchTextParser.py
@@ -43,28 +43,36 @@ if __name__ == '__main__':
 else:
   DEBUG = 0
 
-parser_pool = threading.local()
+class ParserPool(object):
+  """
+  Per-thread parser pool, because ply is not thread-safe.
+  """
 
-@profiler_decorator
-def getAdvancedSearchTextDetector():
-  try:
-    return parser_pool.advanced_search_text_detector
-  except AttributeError:
-    advanced_search_text_detector = AdvancedSearchTextDetector()
-    advanced_search_text_detector.init(debug=DEBUG)
-    parser_pool.advanced_search_text_detector = advanced_search_text_detector
-    return advanced_search_text_detector
+  def __init__(self):
+    self.parser_pool = threading.local()
+    self.parser_registry = {}
 
-@profiler_decorator
-def getAdvancedSearchTextParser():
-  try:
-    return parser_pool.parser
-  except AttributeError:
-    parser = AdvancedSearchTextParser()
-    parser.init(debug=DEBUG)
-    parser_pool.parser = parser
+  def register(self, parser):
+    parser_registry = self.parser_registry
+    name = (parser.__module__, parser.__name__)
+    if name in parser_registry:
+      raise ValueError, 'Duplicate parser for name %r' % (name, )
+    parser_registry[name] = parser
+    return name
+
+  def get(self, name):
+    try:
+      parser = getattr(self.parser_pool, name)
+    except AttributeError:
+      parser = self.parser_registry[name]()
+      parser.init(debug=DEBUG)
+      setattr(self.parser_pool, name, parser)
     return parser
 
+parser_pool = ParserPool()
+DETECTOR_ID = parser_pool.register(AdvancedSearchTextDetector)
+PARSER_ID = parser_pool.register(AdvancedSearchTextParser)
+
 def safeParsingDecorator(func):
   """
   Wrapper hiding parsing errors and returning None when they occur.
@@ -84,13 +92,13 @@ def safeParsingDecorator(func):
 
 @profiler_decorator
 def isAdvancedSearchText(input, is_column):
-  return getAdvancedSearchTextDetector()(input, is_column)
+  return parser_pool.get(DETECTOR_ID)(input, is_column)
 
 @profiler_decorator
 @safeParsingDecorator
 def parse(input, is_column, *args, **kw):
   if isAdvancedSearchText(input, is_column):
-    result = getAdvancedSearchTextParser()(input, is_column, *args, **kw)
+    result = parser_pool.get(PARSER_ID)(input, is_column, *args, **kw)
   else:
     result = None
   return result
@@ -328,7 +336,8 @@ if __name__ == '__main__':
     print repr(input)
     try:
       try:
-        detector_result = getAdvancedSearchTextDetector()(input, isColumn)
+        detector_result = parser_pool.get(DETECTOR_ID)(input,
+          isColumn)
       except ParserOrLexerError, message:
         print '  Detector raise: %r' % (message, )
         detector_result = False
@@ -336,7 +345,7 @@ if __name__ == '__main__':
         print '  Detector: %r' % (detector_result, )
       if detector_result:
         print '  LEX:'
-        advanced_parser = getAdvancedSearchTextParser()
+        advanced_parser = parser_pool.get(PARSER_ID)
         lexer = advanced_parser.lexer
         advanced_parser.isColumn = isColumn
         lexer.input(input)