From 2e8ec5f5df0bcb80e2cb36291f73a3cee0780b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 14 Apr 2013 23:17:55 +0200 Subject: [PATCH] Replace SPLIT_PART by SUBSTR and POSITION SPLIT_PART is not a standard SQL function (it is not supported by MySQL). SUBSTR is used even if it is not standard SQL because SUBSTRING is not supported by SQLite. This will change once we will migrate to python-sql. review784002 --- trytond/backend/sqlite/database.py | 12 ++++++++++++ trytond/ir/translation.py | 2 +- trytond/model/fields/property.py | 18 +++++++++--------- trytond/model/modelsql.py | 20 ++++++++++++-------- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 60746c31c6..0f2123f5a2 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -23,6 +23,7 @@ except ImportError: from sqlite3 import OperationalError as DatabaseOperationalError QUOTE_SEPARATION = re.compile(r"(.*?)('.*?')", re.DOTALL) EXTRACT_PATTERN = re.compile(r'EXTRACT\s*\(\s*(\S*)\s+FROM', re.I) +POSITION_PATTERN = re.compile(r'POSITION\s*\(([^\)]*)\s+IN', re.I) def extract(lookup_type, date): @@ -87,6 +88,15 @@ def split_part(text, delimiter, count): return (text.split(delimiter) + [''] * (count - 1))[count - 1] +def position(substring, string): + if string is None: + return + try: + return string.index(substring) + 1 + except ValueError: + return 0 + + def replace(text, pattern, replacement): return str(text).replace(pattern, replacement) @@ -122,6 +132,7 @@ class Database(DatabaseInterface): self._conn.create_function('extract', 2, extract) self._conn.create_function('date_trunc', 2, date_trunc) self._conn.create_function('split_part', 3, split_part) + self._conn.create_function('position', 2, position) if sqlite.sqlite_version_info < (3, 3, 14): self._conn.create_function('replace', 3, replace) return self @@ -278,6 +289,7 @@ class Cursor(CursorInterface): def execute(self, sql, params=None): buf = "" + sql = re.sub(POSITION_PATTERN, r'POSITION(\1,', sql) for nquote, quote in QUOTE_SEPARATION.findall(sql + "''"): nquote = nquote.replace('?', '??') nquote = nquote.replace('%s', '?') diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 91bf4f206f..3f87940f3f 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -144,7 +144,7 @@ class Translation(ModelSQL, ModelView): def search_model(cls, name, clause): cursor = Transaction().cursor cursor.execute('SELECT id FROM "%s" ' - 'WHERE split_part(name, \',\', 1) %s %%s' % + 'WHERE SUBSTR(name, 1, POSITION(\',\' IN name) - 1) %s %%s' % (cls._table, clause[1]), (clause[2],)) return [('id', 'in', [x[0] for x in cursor.fetchall()])] diff --git a/trytond/model/fields/property.py b/trytond/model/fields/property.py index 74e30a88c6..182c3c6efc 100644 --- a/trytond/model/fields/property.py +++ b/trytond/model/fields/property.py @@ -90,7 +90,8 @@ class Property(Function): #Fetch res ids that comply with the domain cursor.execute( 'SELECT CAST(' - 'SPLIT_PART("' + Property._table + '".res,\',\',2) ' + 'SUBSTR("' + Property._table + '".res, ' + 'POSITION(\',\' IN "' + Property._table + '".res) + 1) ' 'AS INTEGER), ' '"' + Property._table + '".id ' 'FROM "' + Property._table + '" ' @@ -135,7 +136,7 @@ class Property(Function): #Fetch the res ids that doesn't use the default value cursor.execute( - "SELECT cast(split_part(res,',',2) as integer) " + "SELECT CAST(SUBSTR(res, POSITION(',' IN res) + 1) AS integer) " 'FROM "' + Property._table + '"' 'WHERE ' + property_query + ' AND res is not null', property_val) @@ -160,23 +161,22 @@ class Property(Function): if sql_type == 'NUMERIC': operator = 'CAST(%s AS NUMERIC)' + value = "SUBSTR(value, POSITION(',' IN value) + 1)" # All negative clauses will be negated later if clause[1] in ('in', 'not in'): operator = operator % '%%s' - return ("(CAST(SPLIT_PART(value,',',2) AS %s) IN (" + return ("(CAST(" + value + " AS %s) IN (" + ",".join((operator,) * len(clause[2])) + ")) ") % sql_type elif ((clause[2] is False or clause[2] is None) and clause[1] in ['=', '!=']): - return "((cast(split_part(value,',',2) as %s) IS NULL " \ - ") = %%s) " % sql_type + return "((CAST(" + value + " AS %s) IS NULL) = %%s) " % sql_type elif clause[1] in ['not like', 'not ilike']: - return "(cast(split_part(value,',',2) as %s) %s %s) " % \ + return "(CAST(" + value + " AS %s) %s %s) " % \ (sql_type, clause[1].split()[1], operator) elif clause[1] == '!=': - return "(cast(split_part(value,',',2) as %s) = %s) " % \ - (sql_type, operator) + return "(CAST(" + value + " AS %s) = %s) " % (sql_type, operator) else: - return "(cast(split_part(value,',',2) as %s) %s %s) " % \ + return "(CAST(" + value + " AS %s) %s %s) " % \ (sql_type, clause[1], operator) @staticmethod diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index b0f75abf22..d438b82273 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -1269,8 +1269,9 @@ class ModelSQL(ModelStorage): sql_type = FIELDS[ cls.id._type].sql_type(cls.id)[0] query = ('SELECT id FROM "' + cls._table + '" ' - 'WHERE CAST(SPLIT_PART(' - '"' + fargs[0] + '", \',\', 2) ' + 'WHERE CAST(SUBSTR("' + fargs[0] + '", ' + 'POSITION(\',\' IN "' + fargs[0] + '")' + + '+ 1) ' 'AS ' + sql_type + ') ' 'IN (' + in_query[0] + ') ' 'AND "' + fargs[0] + '" ilike %s') @@ -1295,8 +1296,9 @@ class ModelSQL(ModelStorage): cls.id._type].sql_type(cls.id)[0] where = ' AND "' + origin + '" LIKE %s' where_args = [cls.__name__ + ',%'] - origin = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)' - % (origin, sql_type)) + origin = ('CAST(SUBSTR("%s", ' + 'POSITION(\',\' IN "%s") + 1) AS %s)' + % (origin, origin, sql_type)) else: origin = '"%s"' % origin where = '' @@ -1336,8 +1338,9 @@ class ModelSQL(ModelStorage): rev_field = Field._fields[field.field] if rev_field._type == 'reference': sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0] - select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)' - % (field.field, sql_type)) + select = ('CAST(SUBSTR("%s", ' + 'POSITION(\',\' IN "%s") + 1) AS %s)' + % (field.field, field.field, sql_type)) where = ' AND "' + field.field + '" LIKE %s' where_args = [cls.__name__ + ',%'] else: @@ -1431,8 +1434,9 @@ class ModelSQL(ModelStorage): origin_field = Relation._fields[field.origin] if origin_field._type == 'reference': sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0] - select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)' - % (field.origin, sql_type)) + select = ('CAST(SUBSTR("%s", ' + 'POSITION(\',\' IN "%s") + 1) AS %s)' + % (field.origin, field.origin, sql_type)) where = ' AND "' + field.origin + '" LIKE %s' where_args = [cls.__name__ + ',%'] else: