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
This commit is contained in:
Cédric Krier committed 2013-04-14 23:17:55 +02:00
1 parent 3492e90308
commit 2e8ec5f5df
4 files changed
+34 -18

No files matched your search

+12
View File
@@ -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', '?')
+1 -1
View File
@@ -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()])]
+9 -9
View File
@@ -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
+12 -8
View File
@@ -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: