Skip to content

Commit ba973eb

Browse files
authored
Fixes #6767: correctly rehash queries in a migration (#7184)
1 parent d8dde6c commit ba973eb

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""fix_hash
2+
3+
Revision ID: 9e8c841d1a30
4+
Revises: 7205816877ec
5+
Create Date: 2024-10-05 18:55:35.730573
6+
7+
"""
8+
import logging
9+
from alembic import op
10+
import sqlalchemy as sa
11+
from sqlalchemy.sql import table
12+
from sqlalchemy import select
13+
14+
from redash.query_runner import BaseQueryRunner, get_query_runner
15+
16+
17+
# revision identifiers, used by Alembic.
18+
revision = '9e8c841d1a30'
19+
down_revision = '7205816877ec'
20+
branch_labels = None
21+
depends_on = None
22+
23+
24+
def update_query_hash(record):
25+
should_apply_auto_limit = record['options'].get("apply_auto_limit", False) if record['options'] else False
26+
query_runner = get_query_runner(record['type'], {}) if record['type'] else BaseQueryRunner({})
27+
query_text = record['query']
28+
29+
parameters_dict = {p["name"]: p.get("value") for p in record['options'].get('parameters', [])} if record.options else {}
30+
if any(parameters_dict):
31+
print(f"Query {record['query_id']} has parameters. Hash might be incorrect.")
32+
33+
return query_runner.gen_query_hash(query_text, should_apply_auto_limit)
34+
35+
36+
def upgrade():
37+
conn = op.get_bind()
38+
39+
metadata = sa.MetaData(bind=conn)
40+
queries = sa.Table("queries", metadata, autoload=True)
41+
data_sources = sa.Table("data_sources", metadata, autoload=True)
42+
43+
joined_table = queries.outerjoin(data_sources, queries.c.data_source_id == data_sources.c.id)
44+
45+
query = select([
46+
queries.c.id.label("query_id"),
47+
queries.c.query,
48+
queries.c.query_hash,
49+
queries.c.options,
50+
data_sources.c.id.label("data_source_id"),
51+
data_sources.c.type
52+
]).select_from(joined_table)
53+
54+
for record in conn.execute(query):
55+
new_hash = update_query_hash(record)
56+
print(f"Updating hash for query {record['query_id']} from {record['query_hash']} to {new_hash}")
57+
conn.execute(
58+
queries.update()
59+
.where(queries.c.id == record['query_id'])
60+
.values(query_hash=new_hash))
61+
62+
63+
def downgrade():
64+
pass

redash/cli/queries.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@
55
manager = AppGroup(help="Queries management commands.")
66

77

8+
@manager.command(name="rehash")
9+
def rehash():
10+
from redash import models
11+
12+
for q in models.Query.query.all():
13+
old_hash = q.query_hash
14+
q.update_query_hash()
15+
new_hash = q.query_hash
16+
17+
if old_hash != new_hash:
18+
print(f"Query {q.id} has changed hash from {old_hash} to {new_hash}")
19+
models.db.session.add(q)
20+
21+
models.db.session.commit()
22+
23+
824
@manager.command(name="add_tag")
925
@argument("query_id")
1026
@argument("tag")

redash/metrics/database.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from sqlalchemy.engine import Engine
66
from sqlalchemy.event import listens_for
77
from sqlalchemy.orm.util import _ORMJoin
8-
from sqlalchemy.sql.selectable import Alias
8+
from sqlalchemy.sql.selectable import Alias, Join
99

1010
from redash import statsd_client
1111

@@ -18,7 +18,7 @@ def _table_name_from_select_element(elt):
1818
if isinstance(t, Alias):
1919
t = t.original.froms[0]
2020

21-
while isinstance(t, _ORMJoin):
21+
while isinstance(t, _ORMJoin) or isinstance(t, Join):
2222
t = t.left
2323

2424
return t.name

0 commit comments

Comments
 (0)