@@ -639,6 +639,7 @@ def _needs_client_side_filter(self, statement: str) -> bool:
639639 r"\bIN\s*\(" , # IN clause (emulator has issues)
640640 r"\bHAS\s+ANCESTOR\b" , # HAS ANCESTOR
641641 r"\bHAS\s+DESCENDANT\b" , # HAS DESCENDANT
642+ r"\bBLOB\s*\(" , # BLOB literal (emulator doesn't support)
642643 ]
643644 for pattern in unsupported_patterns :
644645 if re .search (pattern , upper ):
@@ -780,6 +781,43 @@ def _eval_simple_condition(self, context: Dict[str, Any], condition: str) -> boo
780781 """Evaluate a simple comparison condition."""
781782 condition = condition .strip ()
782783
784+ # Handle BLOB equality (before generic handlers, since BLOB literal
785+ # would confuse the generic _parse_literal path)
786+ blob_eq_match = re .match (
787+ r"(\w+)\s*=\s*BLOB\s*\('(.*?)'\)" ,
788+ condition ,
789+ re .IGNORECASE | re .DOTALL ,
790+ )
791+ if blob_eq_match :
792+ field = blob_eq_match .group (1 )
793+ blob_str = blob_eq_match .group (2 )
794+ try :
795+ blob_bytes = blob_str .encode ("latin-1" )
796+ except (UnicodeEncodeError , UnicodeDecodeError ):
797+ blob_bytes = blob_str .encode ("utf-8" )
798+ field_val = context .get (field )
799+ if isinstance (field_val , bytes ):
800+ return field_val == blob_bytes
801+ return False
802+
803+ # Handle BLOB inequality
804+ blob_neq_match = re .match (
805+ r"(\w+)\s*!=\s*BLOB\s*\('(.*?)'\)" ,
806+ condition ,
807+ re .IGNORECASE | re .DOTALL ,
808+ )
809+ if blob_neq_match :
810+ field = blob_neq_match .group (1 )
811+ blob_str = blob_neq_match .group (2 )
812+ try :
813+ blob_bytes = blob_str .encode ("latin-1" )
814+ except (UnicodeEncodeError , UnicodeDecodeError ):
815+ blob_bytes = blob_str .encode ("utf-8" )
816+ field_val = context .get (field )
817+ if isinstance (field_val , bytes ):
818+ return field_val != blob_bytes
819+ return True
820+
783821 # Handle NOT IN
784822 not_in_match = re .match (
785823 r"(\w+)\s+NOT\s+IN\s*\(([^)]+)\)" , condition , re .IGNORECASE
0 commit comments