Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lib/features/workspace/generic_sql_workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,15 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {

final Map<String, SqlResultGridSchema> _gridSchemaCache = {};

static String _schemaCacheKey(String sql, List<String> cols) =>
'${cols.join('\u0001')}\u0000$sql';
/// Table schemas are cached per (database, schema, table), so any query on a
/// table reuses the lookup, not only the same text. A query with no single
/// target table is not cached.
String? _schemaCacheKey(String sql) {
final target = SqlTableTargetExtractor.extract(sql);
if (target == null) return null;
return '$effectiveDatabase\u0001${target.schema ?? ''}\u0001'
'${target.tableName}';
}

static final _readQueryRegex = RegExp(
r'^\s*(select|with|values|show|explain|pragma|describe)\b',
Expand Down Expand Up @@ -725,8 +732,8 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {

// Rows show now. The table schema (keys, types, edit hint) follows: from
// the cache, or from the delegate in the background.
final cacheKey = _schemaCacheKey(shownSql, cols);
final cached = _gridSchemaCache[cacheKey];
final cacheKey = _schemaCacheKey(shownSql);
final cached = cacheKey == null ? null : _gridSchemaCache[cacheKey];
invalidatePane(session);
setState(() {
session.columns = cols;
Expand All @@ -753,7 +760,11 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
widget.delegate.resolveTableSchema(shownSql, cols).then(
(gridSchema) {
if (!mounted) return;
_gridSchemaCache[cacheKey] = gridSchema;
// A result with no columns gets no schema from the delegate, so
// it is not worth keeping for the table.
if (cacheKey != null && cols.isNotEmpty) {
_gridSchemaCache[cacheKey] = gridSchema;
}
_applyGridSchema(session, shownSql, cols, outRows, gridSchema,
result, scriptStatus);
},
Expand Down
22 changes: 22 additions & 0 deletions test/features/workspace/generic_sql_workspace_schema_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,26 @@ void main() {
await runAndWait(tester, state);
expect(delegate.probes, 1);
});

testWidgets('another query on the same table reuses the lookup (#1171)',
(tester) async {
final delegate = _SchemaDelegate();
final state = await pumpWorkspace(tester, delegate, 'select * from users');
await runAndWait(tester, state);
state.activeSession.controller.text = 'select name from users';
await runAndWait(tester, state);
expect(delegate.lookups.length, 1);
});

testWidgets('a DDL run makes the next query on the table look it up again',
(tester) async {
final delegate = _SchemaDelegate();
final state = await pumpWorkspace(tester, delegate, 'select * from users');
await runAndWait(tester, state);
state.activeSession.controller.text = 'alter table users add column age int';
await runAndWait(tester, state);
state.activeSession.controller.text = 'select * from users';
await runAndWait(tester, state);
expect(delegate.lookups.length, 3);
});
}
Loading