You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/08/27 03:51:15 UTC
(superset) branch master updated: fix(sqllab): stop a database with no extra from breaking SET_DATABASES (#43216)
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new b71293acde0 fix(sqllab): stop a database with no extra from breaking SET_DATABASES (#43216)
b71293acde0 is described below
commit b71293acde004b4e82758675a23d2cf2207f67c8
Author: Bikash <bi...@gmail.com>
AuthorDate: Thu Aug 27 09:21:08 2026 +0530
fix(sqllab): stop a database with no extra from breaking SET_DATABASES (#43216)
Co-authored-by: bikashJMV <bi...@jmv.co.in>
Co-authored-by: Claude Opus 5 (1M context) <no...@anthropic.com>
Co-authored-by: Evan Rusackas <ev...@rusackas.com>
---
.../src/SqlLab/reducers/sqlLab.test.ts | 47 ++++++++++++++++++++++
superset-frontend/src/SqlLab/reducers/sqlLab.ts | 23 ++++++++++-
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.test.ts b/superset-frontend/src/SqlLab/reducers/sqlLab.test.ts
index 3166a902e84..11e6c199678 100644
--- a/superset-frontend/src/SqlLab/reducers/sqlLab.test.ts
+++ b/superset-frontend/src/SqlLab/reducers/sqlLab.test.ts
@@ -61,6 +61,53 @@ describe('sqlLabReducer', () => {
});
});
+ test('should default extra_json to an empty object when extra is unset', () => {
+ // `extra` is nullable in the metadata database, and JSON.parse(extra || '')
+ // is guaranteed to throw because '' is never valid JSON, so one such row
+ // took down the whole reducer.
+ const incomingDb = {
+ ...databases.result[0],
+ extra: null,
+ };
+ const incomingDbId = Number(incomingDb.id);
+
+ const action = actions.setDatabases([incomingDb] as any);
+
+ const newState = sqlLabReducer(initialState, action);
+
+ expect(newState.databases[incomingDbId]).toEqual({
+ ...incomingDb,
+ extra_json: {},
+ });
+ });
+
+ test('defaults extra_json when a database has malformed extra', () => {
+ const incomingDb = { ...databases.result[0], extra: '{not json' };
+
+ const newState = sqlLabReducer(
+ initialState,
+ actions.setDatabases([incomingDb] as any),
+ );
+
+ expect(newState.databases[Number(incomingDb.id)].extra_json).toEqual({});
+ });
+
+ test('keeps a valid extra payload', () => {
+ const incomingDb = {
+ ...databases.result[0],
+ extra: '{"engine_params": {"pool_size": 5}}',
+ };
+
+ const newState = sqlLabReducer(
+ initialState,
+ actions.setDatabases([incomingDb] as any),
+ );
+
+ expect(newState.databases[Number(incomingDb.id)].extra_json).toEqual({
+ engine_params: { pool_size: 5 },
+ });
+ });
+
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Query editors actions', () => {
let newState: SqlLabState;
diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.ts b/superset-frontend/src/SqlLab/reducers/sqlLab.ts
index ac3b7a96d6f..874ff94e6ef 100644
--- a/superset-frontend/src/SqlLab/reducers/sqlLab.ts
+++ b/superset-frontend/src/SqlLab/reducers/sqlLab.ts
@@ -36,6 +36,27 @@ import {
type SqlLabState = SqlLabRootState['sqlLab'];
+/**
+ * A database's `extra` column is free-form and frequently empty: it is nullable
+ * in the metadata database and the API returns it verbatim. `JSON.parse` cannot
+ * represent that, and `JSON.parse(extra || '')` is guaranteed to throw, since
+ * the empty string is never valid JSON — so a single database row with no
+ * `extra` took down the whole SET_DATABASES reducer and with it SQL Lab.
+ * Malformed JSON is treated the same way: one bad row must not cost the user
+ * every other database.
+ */
+function parseDatabaseExtra(extra: unknown): Record<string, unknown> {
+ if (typeof extra !== 'string' || extra.trim() === '') {
+ return {};
+ }
+ try {
+ const parsed = JSON.parse(extra);
+ return parsed && typeof parsed === 'object' ? parsed : {};
+ } catch {
+ return {};
+ }
+}
+
function alterUnsavedQueryEditorState(
state: SqlLabState,
updatedState: Partial<QueryEditor>,
@@ -727,7 +748,7 @@ export default function sqlLabReducer(
(action.databases as any[])!.forEach((db: any) => {
databases[db.id] = {
...db,
- extra_json: JSON.parse(db.extra || ''),
+ extra_json: parseDatabaseExtra(db.extra),
};
});
return {