|
@@ -52,6 +52,8 @@ class SQLDashboardApi(DashboardApi):
|
|
|
self.engine = engine
|
|
self.engine = engine
|
|
|
self.source = source
|
|
self.source = source
|
|
|
self.async = engine == 'hive' or engine == 'impala'
|
|
self.async = engine == 'hive' or engine == 'impala'
|
|
|
|
|
+ self.backticks = '"' if engine == 'postgresql' else '`'
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def query(self, dashboard, query, facet=None):
|
|
def query(self, dashboard, query, facet=None):
|
|
|
if query['qs'] == [{'q': '_root_:*'}]:
|
|
if query['qs'] == [{'q': '_root_:*'}]:
|
|
@@ -70,9 +72,10 @@ class SQLDashboardApi(DashboardApi):
|
|
|
database, table = '', ''
|
|
database, table = '', ''
|
|
|
else:
|
|
else:
|
|
|
database, table = self._get_database_table_names(dashboard['name'])
|
|
database, table = self._get_database_table_names(dashboard['name'])
|
|
|
- sql_from = '`%(database)s`.`%(table)s`' % {
|
|
|
|
|
|
|
+ sql_from = '%(backticks)s%(database)s%(backticks)s.%(backticks)s%(table)s%(backticks)s' % {
|
|
|
'database': database,
|
|
'database': database,
|
|
|
- 'table': table
|
|
|
|
|
|
|
+ 'table': table,
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if facet and facet['properties']['facets']:
|
|
if facet and facet['properties']['facets']:
|
|
@@ -158,7 +161,15 @@ class SQLDashboardApi(DashboardApi):
|
|
|
result_properties = facet['properties']['result']
|
|
result_properties = facet['properties']['result']
|
|
|
else:
|
|
else:
|
|
|
fields = Collection2.get_field_list(dashboard)
|
|
fields = Collection2.get_field_list(dashboard)
|
|
|
- order_by = ', '.join(['`%s` %s' % (f['name'], f['sort']['direction']) for f in dashboard['template']['fieldsAttributes'] if f['sort']['direction'] and f['name'] in fields])
|
|
|
|
|
|
|
+ order_by = ', '.join([
|
|
|
|
|
+ '%(backticks)s%(name)s%(backticks)s %(direction)s' % {
|
|
|
|
|
+ 'backticks': self.backticks,
|
|
|
|
|
+ 'name': f['name'],
|
|
|
|
|
+ 'direction': f['sort']['direction']
|
|
|
|
|
+ }
|
|
|
|
|
+ for f in dashboard['template']['fieldsAttributes'] if f['sort']['direction'] and f['name'] in fields
|
|
|
|
|
+ ]
|
|
|
|
|
+ )
|
|
|
sql = '''
|
|
sql = '''
|
|
|
SELECT %(fields)s
|
|
SELECT %(fields)s
|
|
|
FROM %(sql_from)s
|
|
FROM %(sql_from)s
|
|
@@ -166,7 +177,12 @@ class SQLDashboardApi(DashboardApi):
|
|
|
%(order_by)s
|
|
%(order_by)s
|
|
|
%(limit)s''' % {
|
|
%(limit)s''' % {
|
|
|
'sql_from': sql_from,
|
|
'sql_from': sql_from,
|
|
|
- 'fields': ', '.join(['`%s` as `%s`' % (f, f) if f != '*' else '*' for f in fields]),
|
|
|
|
|
|
|
+ 'fields': ', '.join([
|
|
|
|
|
+ '%(backticks)s%(column)s%(backticks)s as %(backticks)s%(column)s%(backticks)s' % {
|
|
|
|
|
+ 'backticks': self.backticks,
|
|
|
|
|
+ 'column': f
|
|
|
|
|
+ } if f != '*' else '*' for f in fields
|
|
|
|
|
+ ]),
|
|
|
'filters': self._convert_filters_to_where(filters) if filters else '',
|
|
'filters': self._convert_filters_to_where(filters) if filters else '',
|
|
|
'order_by': 'ORDER BY %s' % order_by if order_by else '',
|
|
'order_by': 'ORDER BY %s' % order_by if order_by else '',
|
|
|
'limit': 'LIMIT %s' % dashboard['template']['rows'] or LIMIT
|
|
'limit': 'LIMIT %s' % dashboard['template']['rows'] or LIMIT
|
|
@@ -268,10 +284,16 @@ class SQLDashboardApi(DashboardApi):
|
|
|
|
|
|
|
|
# TODO: check column stats to go faster
|
|
# TODO: check column stats to go faster
|
|
|
|
|
|
|
|
- sql = "SELECT MIN(`%(field)s`), MAX(`%(field)s`) FROM `%(database)s`.`%(table)s`" % {
|
|
|
|
|
- 'field': fields[0],
|
|
|
|
|
- 'database': database,
|
|
|
|
|
- 'table': table
|
|
|
|
|
|
|
+ sql = '''
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ MIN(%(backticks)s%(field)s%(backticks)s),
|
|
|
|
|
+ MAX(%(backticks)s%(field)s%(backticks)s)
|
|
|
|
|
+ FROM %(backticks)s%(database)s%(backticks)s.%(backticks)s%(table)s%(backticks)s
|
|
|
|
|
+ ''' % {
|
|
|
|
|
+ 'field': fields[0],
|
|
|
|
|
+ 'database': database,
|
|
|
|
|
+ 'table': table,
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
result = self._sync_execute(sql, database)
|
|
result = self._sync_execute(sql, database)
|
|
@@ -301,12 +323,17 @@ class SQLDashboardApi(DashboardApi):
|
|
|
field = self._get_field(dashboard, dashboard['idField'])
|
|
field = self._get_field(dashboard, dashboard['idField'])
|
|
|
quotes = '' if self._is_number(field['type']) else "'"
|
|
quotes = '' if self._is_number(field['type']) else "'"
|
|
|
|
|
|
|
|
- sql = "SELECT * FROM `%(database)s`.`%(table)s` WHERE `%(idField)s` = %(quotes)s%(doc_id)s%(quotes)s" % {
|
|
|
|
|
- 'database': database,
|
|
|
|
|
- 'table': table,
|
|
|
|
|
- 'idField': dashboard['idField'], # Only 1 PK currently,
|
|
|
|
|
- 'doc_id': doc_id,
|
|
|
|
|
- 'quotes': quotes
|
|
|
|
|
|
|
+ sql = '''
|
|
|
|
|
+ SELECT *
|
|
|
|
|
+ FROM %(backticks)s%(database)s%(backticks)s.%(backticks)s%(table)s%(backticks)s
|
|
|
|
|
+ WHERE %(backticks)s%(idField)s%(backticks)s = %(quotes)s%(doc_id)s%(quotes)s
|
|
|
|
|
+ ''' % {
|
|
|
|
|
+ 'database': database,
|
|
|
|
|
+ 'table': table,
|
|
|
|
|
+ 'idField': dashboard['idField'], # Only 1 PK currently,
|
|
|
|
|
+ 'doc_id': doc_id,
|
|
|
|
|
+ 'quotes': quotes,
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
result = self._sync_execute(sql, database)
|
|
result = self._sync_execute(sql, database)
|
|
@@ -431,11 +458,16 @@ class SQLDashboardApi(DashboardApi):
|
|
|
quote = "'"
|
|
quote = "'"
|
|
|
else:
|
|
else:
|
|
|
quote = ''
|
|
quote = ''
|
|
|
- clauses.append("`%(field)s` >= %(quote)s%(from)s%(quote)s AND `%(field)s` < %(quote)s%(to)s%(quote)s" % {
|
|
|
|
|
- 'field': fq['field'],
|
|
|
|
|
- 'to': fq['properties'][0]['to'],
|
|
|
|
|
- 'from': fq['properties'][0]['from'],
|
|
|
|
|
- 'quote': quote
|
|
|
|
|
|
|
+ clauses.append(
|
|
|
|
|
+ '''
|
|
|
|
|
+ %(backticks)s%(field)s%(backticks)s >= %(quote)s%(from)s%(quote)s AND
|
|
|
|
|
+ %(backticks)s%(field)s%(backticks)s < %(quote)s%(to)s%(quote)s
|
|
|
|
|
+ ''' % {
|
|
|
|
|
+ 'field': fq['field'],
|
|
|
|
|
+ 'to': fq['properties'][0]['to'],
|
|
|
|
|
+ 'from': fq['properties'][0]['from'],
|
|
|
|
|
+ 'quote': quote,
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
})
|
|
})
|
|
|
elif fq['type'] == 'map':
|
|
elif fq['type'] == 'map':
|
|
|
for direction in ['lat', 'lon']:
|
|
for direction in ['lat', 'lon']:
|
|
@@ -445,20 +477,25 @@ class SQLDashboardApi(DashboardApi):
|
|
|
quote = ''
|
|
quote = ''
|
|
|
else:
|
|
else:
|
|
|
quote = "'"
|
|
quote = "'"
|
|
|
- min_direction = min(fq['properties'][direction+'_sw'], fq['properties'][direction+'_ne'])
|
|
|
|
|
- max_direction = max(fq['properties'][direction+'_sw'], fq['properties'][direction+'_ne'])
|
|
|
|
|
- clauses.append("`%(field)s` >= %(quote)s%(from)s%(quote)s AND `%(field)s` < %(quote)s%(to)s%(quote)s" % {
|
|
|
|
|
- 'field': fq[direction],
|
|
|
|
|
- 'to': max_direction,
|
|
|
|
|
- 'from': min_direction,
|
|
|
|
|
- 'quote': quote
|
|
|
|
|
|
|
+ min_direction = min(fq['properties'][direction+'_sw'], fq['properties'][direction + '_ne'])
|
|
|
|
|
+ max_direction = max(fq['properties'][direction+'_sw'], fq['properties'][direction + '_ne'])
|
|
|
|
|
+ clauses.append('''
|
|
|
|
|
+ %(backticks)s%(field)s%(backticks)s >= %(quote)s%(from)s%(quote)s AND
|
|
|
|
|
+ %(backticks)s%(field)s%(backticks)s < %(quote)s%(to)s%(quote)s
|
|
|
|
|
+ ''' % {
|
|
|
|
|
+ 'field': fq[direction],
|
|
|
|
|
+ 'to': max_direction,
|
|
|
|
|
+ 'from': min_direction,
|
|
|
|
|
+ 'quote': quote,
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
})
|
|
})
|
|
|
return clauses
|
|
return clauses
|
|
|
|
|
|
|
|
def _get_field_condition_formatting(self, table, facet, field_name):
|
|
def _get_field_condition_formatting(self, table, facet, field_name):
|
|
|
field = self._get_field(table, field_name, facet=facet)
|
|
field = self._get_field(table, field_name, facet=facet)
|
|
|
if field:
|
|
if field:
|
|
|
- return "`%s` %s %s" if self._is_number(field['type']) else "`%s` %s '%s'"
|
|
|
|
|
|
|
+ column = self.backticks + "%s" + self.backticks + ' '
|
|
|
|
|
+ return column + ("%s %s" if self._is_number(field['type']) else "%s '%s'")
|
|
|
else:
|
|
else:
|
|
|
return ''
|
|
return ''
|
|
|
|
|
|
|
@@ -481,7 +518,8 @@ class SQLDashboardApi(DashboardApi):
|
|
|
fields.append(facet['field'])
|
|
fields.append(facet['field'])
|
|
|
elif facet['aggregate']['function'] == 'unique':
|
|
elif facet['aggregate']['function'] == 'unique':
|
|
|
facet['aggregate']['function'] = 'COUNT'
|
|
facet['aggregate']['function'] = 'COUNT'
|
|
|
- fields.append('distinct `%(field)s`' % facet)
|
|
|
|
|
|
|
+ facet['backticks'] = self.backticks
|
|
|
|
|
+ fields.append('distinct %(backticks)s%(field)s%(backticks)s' % facet)
|
|
|
elif facet['aggregate']['function'] == 'percentile':
|
|
elif facet['aggregate']['function'] == 'percentile':
|
|
|
if cls._supports_percentile():
|
|
if cls._supports_percentile():
|
|
|
fields.append('%s, %s' % (facet['field'], cls._zero_to_one(float(facet['aggregate']['percentile']))))
|
|
fields.append('%s, %s' % (facet['field'], cls._zero_to_one(float(facet['aggregate']['percentile']))))
|
|
@@ -527,20 +565,21 @@ class SQLDashboardApi(DashboardApi):
|
|
|
|
|
|
|
|
if facet['canRange']:
|
|
if facet['canRange']:
|
|
|
field_name = '%(field)s_range' % facet
|
|
field_name = '%(field)s_range' % facet
|
|
|
- order_by = '`%(field)s_range_%(position)s` %(sort)s' % facet
|
|
|
|
|
|
|
+ facet['backticks'] = self.backticks
|
|
|
|
|
+ order_by = '%(backticks)s%(field)s_range_%(position)s%(backticks)s %(sort)s' % facet
|
|
|
if facet['isDate']:
|
|
if facet['isDate']:
|
|
|
- field = '`%(field)s`' % facet
|
|
|
|
|
|
|
+ field = '%(backticks)s%(field)s%(backticks)s' % facet
|
|
|
|
|
|
|
|
slot = self._gap_to_units(facet['gap'])
|
|
slot = self._gap_to_units(facet['gap'])
|
|
|
|
|
|
|
|
if slot['unit'] != 'SECOND':
|
|
if slot['unit'] != 'SECOND':
|
|
|
select = """
|
|
select = """
|
|
|
- trunc(%(field)s, '%(slot)s') AS `%(field_name)s_%(position)s`,
|
|
|
|
|
- trunc(%(field)s, '%(slot)s') + interval %(slot_interval)s AS `%(field_name)s_to_%(position)s`"""
|
|
|
|
|
|
|
+ trunc(%(field)s, '%(slot)s') AS %(backticks)s%(field_name)s_%(position)s%(backticks)s,
|
|
|
|
|
+ trunc(%(field)s, '%(slot)s') + interval %(slot_interval)s AS %(backticks)s%(field_name)s_to_%(position)s%(backticks)s"""
|
|
|
else:
|
|
else:
|
|
|
select = """
|
|
select = """
|
|
|
- %(field)s AS `%(field_name)s_%(position)s`,
|
|
|
|
|
- %(field)s + interval %(slot_interval)s AS `%(field_name)s_to_%(position)s`"""
|
|
|
|
|
|
|
+ %(field)s AS %(backticks)s%(field_name)s_%(position)s%(backticks)s,
|
|
|
|
|
+ %(field)s + interval %(slot_interval)s AS %(backticks)s%(field_name)s_to_%(position)s%(backticks)s"""
|
|
|
select = select % {
|
|
select = select % {
|
|
|
'field': field,
|
|
'field': field,
|
|
|
'slot': slot['sql_trunc'],
|
|
'slot': slot['sql_trunc'],
|
|
@@ -548,17 +587,19 @@ class SQLDashboardApi(DashboardApi):
|
|
|
'field_name': field_name,
|
|
'field_name': field_name,
|
|
|
'start': facet['start'],
|
|
'start': facet['start'],
|
|
|
'end': facet['end'],
|
|
'end': facet['end'],
|
|
|
- 'position': facet['position']
|
|
|
|
|
|
|
+ 'position': facet['position'],
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
}
|
|
}
|
|
|
else:
|
|
else:
|
|
|
slot = facet['gap']
|
|
slot = facet['gap']
|
|
|
select = """
|
|
select = """
|
|
|
- floor(floor((`%(field)s` - %(start)s) / %(slot)s) * %(slot)s) + %(start)s AS `%(field_name)s_%(position)s`""" % { # Beware: start might be not in sync with the UI
|
|
|
|
|
|
|
+ floor(floor((%(backticks)s%(field)s%(backticks)s - %(start)s) / %(slot)s) * %(slot)s) + %(start)s AS %(backticks)s%(field_name)s_%(position)s%(backticks)s""" % { # Beware: start might be not in sync with the UI
|
|
|
'field': facet['field'],
|
|
'field': facet['field'],
|
|
|
'slot': slot,
|
|
'slot': slot,
|
|
|
'field_name': field_name,
|
|
'field_name': field_name,
|
|
|
'start': facet['start'],
|
|
'start': facet['start'],
|
|
|
- 'position': facet['position']
|
|
|
|
|
|
|
+ 'position': facet['position'],
|
|
|
|
|
+ 'backticks': self.backticks
|
|
|
}
|
|
}
|
|
|
else:
|
|
else:
|
|
|
field_name = '%(field)s' % facet
|
|
field_name = '%(field)s' % facet
|
|
@@ -566,7 +607,7 @@ class SQLDashboardApi(DashboardApi):
|
|
|
order_by = '%(field)s_%(position)s %(sort)s' % facet
|
|
order_by = '%(field)s_%(position)s %(sort)s' % facet
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- 'name': '`%s`' % field_name,
|
|
|
|
|
|
|
+ 'name': '%(backticks)s%(field)s%(backticks)s' % {'backticks': self.backticks, 'field': field_name},
|
|
|
'select': select,
|
|
'select': select,
|
|
|
'order_by': order_by
|
|
'order_by': order_by
|
|
|
}
|
|
}
|
|
@@ -665,7 +706,8 @@ class SQLDashboardApi(DashboardApi):
|
|
|
props = self._get_time_filter_range(collection, query)
|
|
props = self._get_time_filter_range(collection, query)
|
|
|
|
|
|
|
|
if props:
|
|
if props:
|
|
|
- return "(`%(field)s` >= %(from)s AND `%(field)s` <= %(to)s)" % props
|
|
|
|
|
|
|
+ props['backticks'] = self.backticks
|
|
|
|
|
+ return "(%(backticks)s%(field)s%(backticks)s >= %(from)s AND %(backticks)s%(field)s%(backticks)s <= %(to)s)" % props
|
|
|
else:
|
|
else:
|
|
|
return {}
|
|
return {}
|
|
|
|
|
|