Loading django/db/backends/mysql/base.py +18 −0 Original line number Diff line number Diff line Loading @@ -425,6 +425,24 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': 'LIKE %s', } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\\', '\\\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'contains': "LIKE BINARY CONCAT('%%', {}, '%%')", 'icontains': "LIKE CONCAT('%%', {}, '%%')", 'startswith': "LIKE BINARY CONCAT({}, '%%')", 'istartswith': "LIKE CONCAT({}, '%%')", 'endswith': "LIKE BINARY CONCAT('%%', {})", 'iendswith': "LIKE CONCAT('%%', {})", } Database = Database SchemaEditorClass = DatabaseSchemaEditor Loading django/db/backends/oracle/base.py +26 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,30 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': "LIKEC UPPER(%s) ESCAPE '\\'", }) # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" _pattern_ops = { 'contains': "'%%' || {} || '%%'", 'icontains': "'%%' || UPPER({}) || '%%'", 'startswith': "{} || '%%'", 'istartswith': "UPPER({}) || '%%'", 'endswith': "'%%' || {}", 'iendswith': "'%%' || UPPER({})", } _standard_pattern_ops = {k: "LIKE TRANSLATE( " + v + " USING NCHAR_CS)" " ESCAPE TRANSLATE('\\' USING NCHAR_CS)" for k, v in _pattern_ops.items()} _likec_pattern_ops = {k: "LIKEC " + v + " ESCAPE '\\'" for k, v in _pattern_ops.items()} Database = Database SchemaEditorClass = DatabaseSchemaEditor Loading Loading @@ -674,8 +698,10 @@ class DatabaseWrapper(BaseDatabaseWrapper): ['X']) except DatabaseError: self.operators = self._likec_operators self.pattern_ops = self._likec_pattern_ops else: self.operators = self._standard_operators self.pattern_ops = self._standard_pattern_ops cursor.close() try: Loading django/db/backends/postgresql_psycopg2/base.py +15 −2 Original line number Diff line number Diff line Loading @@ -86,9 +86,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': 'LIKE UPPER(%s)', } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'startswith': "LIKE %s || '%%%%'", 'istartswith': "LIKE UPPER(%s) || '%%%%'", 'contains': "LIKE '%%' || {} || '%%'", 'icontains': "LIKE '%%' || UPPER({}) || '%%'", 'startswith': "LIKE {} || '%%'", 'istartswith': "LIKE UPPER({}) || '%%'", 'endswith': "LIKE '%%' || {}", 'iendswith': "LIKE '%%' || UPPER({})", } Database = Database Loading django/db/backends/sqlite3/base.py +15 −2 Original line number Diff line number Diff line Loading @@ -343,9 +343,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': "LIKE %s ESCAPE '\\'", } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'startswith': "LIKE %s || '%%%%'", 'istartswith': "LIKE UPPER(%s) || '%%%%'", 'contains': r"LIKE '%%' || {} || '%%' ESCAPE '\'", 'icontains': r"LIKE '%%' || UPPER({}) || '%%' ESCAPE '\'", 'startswith': r"LIKE {} || '%%' ESCAPE '\'", 'istartswith': r"LIKE UPPER({}) || '%%' ESCAPE '\'", 'endswith': r"LIKE '%%' || {} ESCAPE '\'", 'iendswith': r"LIKE '%%' || UPPER({}) ESCAPE '\'", } Database = Database Loading django/db/models/lookups.py +15 −13 Original line number Diff line number Diff line Loading @@ -225,16 +225,6 @@ class IExact(BuiltinLookup): default_lookups['iexact'] = IExact class Contains(BuiltinLookup): lookup_name = 'contains' default_lookups['contains'] = Contains class IContains(BuiltinLookup): lookup_name = 'icontains' default_lookups['icontains'] = IContains class GreaterThan(BuiltinLookup): lookup_name = 'gt' default_lookups['gt'] = GreaterThan Loading Loading @@ -306,6 +296,7 @@ default_lookups['in'] = In class PatternLookup(BuiltinLookup): def get_rhs_op(self, connection, rhs): # Assume we are in startswith. We need to produce SQL like: # col LIKE %s, ['thevalue%'] Loading @@ -318,11 +309,22 @@ class PatternLookup(BuiltinLookup): # pattern added. if (hasattr(self.rhs, 'get_compiler') or hasattr(self.rhs, 'as_sql') or hasattr(self.rhs, '_as_sql') or self.bilateral_transforms): return connection.pattern_ops[self.lookup_name] % rhs pattern = connection.pattern_ops[self.lookup_name].format(connection.pattern_esc) return pattern.format(rhs) else: return super(PatternLookup, self).get_rhs_op(connection, rhs) class Contains(PatternLookup): lookup_name = 'contains' default_lookups['contains'] = Contains class IContains(PatternLookup): lookup_name = 'icontains' default_lookups['icontains'] = IContains class StartsWith(PatternLookup): lookup_name = 'startswith' default_lookups['startswith'] = StartsWith Loading @@ -333,12 +335,12 @@ class IStartsWith(PatternLookup): default_lookups['istartswith'] = IStartsWith class EndsWith(BuiltinLookup): class EndsWith(PatternLookup): lookup_name = 'endswith' default_lookups['endswith'] = EndsWith class IEndsWith(BuiltinLookup): class IEndsWith(PatternLookup): lookup_name = 'iendswith' default_lookups['iendswith'] = IEndsWith Loading Loading
django/db/backends/mysql/base.py +18 −0 Original line number Diff line number Diff line Loading @@ -425,6 +425,24 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': 'LIKE %s', } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\\', '\\\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'contains': "LIKE BINARY CONCAT('%%', {}, '%%')", 'icontains': "LIKE CONCAT('%%', {}, '%%')", 'startswith': "LIKE BINARY CONCAT({}, '%%')", 'istartswith': "LIKE CONCAT({}, '%%')", 'endswith': "LIKE BINARY CONCAT('%%', {})", 'iendswith': "LIKE CONCAT('%%', {})", } Database = Database SchemaEditorClass = DatabaseSchemaEditor Loading
django/db/backends/oracle/base.py +26 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,30 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': "LIKEC UPPER(%s) ESCAPE '\\'", }) # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" _pattern_ops = { 'contains': "'%%' || {} || '%%'", 'icontains': "'%%' || UPPER({}) || '%%'", 'startswith': "{} || '%%'", 'istartswith': "UPPER({}) || '%%'", 'endswith': "'%%' || {}", 'iendswith': "'%%' || UPPER({})", } _standard_pattern_ops = {k: "LIKE TRANSLATE( " + v + " USING NCHAR_CS)" " ESCAPE TRANSLATE('\\' USING NCHAR_CS)" for k, v in _pattern_ops.items()} _likec_pattern_ops = {k: "LIKEC " + v + " ESCAPE '\\'" for k, v in _pattern_ops.items()} Database = Database SchemaEditorClass = DatabaseSchemaEditor Loading Loading @@ -674,8 +698,10 @@ class DatabaseWrapper(BaseDatabaseWrapper): ['X']) except DatabaseError: self.operators = self._likec_operators self.pattern_ops = self._likec_pattern_ops else: self.operators = self._standard_operators self.pattern_ops = self._standard_pattern_ops cursor.close() try: Loading
django/db/backends/postgresql_psycopg2/base.py +15 −2 Original line number Diff line number Diff line Loading @@ -86,9 +86,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': 'LIKE UPPER(%s)', } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'startswith': "LIKE %s || '%%%%'", 'istartswith': "LIKE UPPER(%s) || '%%%%'", 'contains': "LIKE '%%' || {} || '%%'", 'icontains': "LIKE '%%' || UPPER({}) || '%%'", 'startswith': "LIKE {} || '%%'", 'istartswith': "LIKE UPPER({}) || '%%'", 'endswith': "LIKE '%%' || {}", 'iendswith': "LIKE '%%' || UPPER({})", } Database = Database Loading
django/db/backends/sqlite3/base.py +15 −2 Original line number Diff line number Diff line Loading @@ -343,9 +343,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': "LIKE %s ESCAPE '\\'", } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression # or the result of a bilateral transformation). # In those cases, special characters for LIKE operators (e.g. \, *, _) should be # escaped on database side. # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" pattern_ops = { 'startswith': "LIKE %s || '%%%%'", 'istartswith': "LIKE UPPER(%s) || '%%%%'", 'contains': r"LIKE '%%' || {} || '%%' ESCAPE '\'", 'icontains': r"LIKE '%%' || UPPER({}) || '%%' ESCAPE '\'", 'startswith': r"LIKE {} || '%%' ESCAPE '\'", 'istartswith': r"LIKE UPPER({}) || '%%' ESCAPE '\'", 'endswith': r"LIKE '%%' || {} ESCAPE '\'", 'iendswith': r"LIKE '%%' || UPPER({}) ESCAPE '\'", } Database = Database Loading
django/db/models/lookups.py +15 −13 Original line number Diff line number Diff line Loading @@ -225,16 +225,6 @@ class IExact(BuiltinLookup): default_lookups['iexact'] = IExact class Contains(BuiltinLookup): lookup_name = 'contains' default_lookups['contains'] = Contains class IContains(BuiltinLookup): lookup_name = 'icontains' default_lookups['icontains'] = IContains class GreaterThan(BuiltinLookup): lookup_name = 'gt' default_lookups['gt'] = GreaterThan Loading Loading @@ -306,6 +296,7 @@ default_lookups['in'] = In class PatternLookup(BuiltinLookup): def get_rhs_op(self, connection, rhs): # Assume we are in startswith. We need to produce SQL like: # col LIKE %s, ['thevalue%'] Loading @@ -318,11 +309,22 @@ class PatternLookup(BuiltinLookup): # pattern added. if (hasattr(self.rhs, 'get_compiler') or hasattr(self.rhs, 'as_sql') or hasattr(self.rhs, '_as_sql') or self.bilateral_transforms): return connection.pattern_ops[self.lookup_name] % rhs pattern = connection.pattern_ops[self.lookup_name].format(connection.pattern_esc) return pattern.format(rhs) else: return super(PatternLookup, self).get_rhs_op(connection, rhs) class Contains(PatternLookup): lookup_name = 'contains' default_lookups['contains'] = Contains class IContains(PatternLookup): lookup_name = 'icontains' default_lookups['icontains'] = IContains class StartsWith(PatternLookup): lookup_name = 'startswith' default_lookups['startswith'] = StartsWith Loading @@ -333,12 +335,12 @@ class IStartsWith(PatternLookup): default_lookups['istartswith'] = IStartsWith class EndsWith(BuiltinLookup): class EndsWith(PatternLookup): lookup_name = 'endswith' default_lookups['endswith'] = EndsWith class IEndsWith(BuiltinLookup): class IEndsWith(PatternLookup): lookup_name = 'iendswith' default_lookups['iendswith'] = IEndsWith Loading