From 24cd8c8c624e044ec815484c98672b2a42ebf008 Mon Sep 17 00:00:00 2001 From: Herman Snevajs Date: Mon, 11 May 2026 10:56:40 +0200 Subject: [PATCH 1/3] Fix sqlite3 cursor and placeholder syntax in get_row_from_db (#895) --- Mergin/diff.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Mergin/diff.py b/Mergin/diff.py index 82f6d538..6930c56b 100644 --- a/Mergin/diff.py +++ b/Mergin/diff.py @@ -75,22 +75,22 @@ def get_row_from_db(db_conn, schema_table, entry_changes): Fetches a single row from DB's table based on the values of pkeys in changeset entry """ - with db_conn.cursor() as c: - where_clauses = [] - query_params = [] + c = db_conn.cursor() + where_clauses = [] + query_params = [] - for i, col in enumerate(schema_table.columns): - if col.pkey: - where_clauses.append('"{}" = %s'.format(col.name)) - val = old_value_for_column_by_index(entry_changes, i) - query_params.append(val) + for i, col in enumerate(schema_table.columns): + if col.pkey: + where_clauses.append('"{}" = ?'.format(col.name)) + val = old_value_for_column_by_index(entry_changes, i) + query_params.append(val) - # We parameterize values securely; table/column names are trusted internal schema objects. - query = 'SELECT * FROM "{}" WHERE {}'.format(schema_table.name, " AND ".join(where_clauses)) # nosec B608 + # We parameterize values securely; table/column names are trusted internal schema objects. + query = 'SELECT * FROM "{}" WHERE {}'.format(schema_table.name, " AND ".join(where_clauses)) # nosec B608 - c.execute(query, tuple(query_params)) + c.execute(query, tuple(query_params)) - return c.fetchone() + return c.fetchone() def parse_gpkg_geom_encoding(wkb_with_gpkg_hdr): From 1432f6a3caf1e117e81de158aadf644c773359d3 Mon Sep 17 00:00:00 2001 From: Herman Snevajs Date: Thu, 14 May 2026 16:11:56 +0200 Subject: [PATCH 2/3] Close sqlite3 connections after diff inspection (try/finally) --- Mergin/diff.py | 16 ++++++++++------ Mergin/processing/algs/create_diff.py | 8 ++++++-- Mergin/processing/algs/extract_local_changes.py | 8 ++++++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Mergin/diff.py b/Mergin/diff.py index 6930c56b..51e1a4ca 100644 --- a/Mergin/diff.py +++ b/Mergin/diff.py @@ -348,10 +348,11 @@ def make_local_changes_layer(mp, layer): fields, cols_to_fields = create_field_list(db_schema[table_name]) - db_conn = None # no ref. db db_conn = sqlite3.connect(base_file) - - features = diff_table_to_features(diff[table_name], db_schema[table_name], fields, cols_to_fields, db_conn) + try: + features = diff_table_to_features(diff[table_name], db_schema[table_name], fields, cols_to_fields, db_conn) + finally: + db_conn.close() # create diff layer vl = QgsVectorLayer( @@ -400,10 +401,13 @@ def make_version_changes_layers(project_path, version): fields, cols_to_fields = create_field_list(db_schema[table_name]) geom_type, geom_crs = get_layer_geometry_info(schema_json, table_name) - db_conn = None # no ref. db db_conn = sqlite3.connect(gpkg_file) - - features = diff_table_to_features(diff[table_name], db_schema[table_name], fields, cols_to_fields, db_conn) + try: + features = diff_table_to_features( + diff[table_name], db_schema[table_name], fields, cols_to_fields, db_conn + ) + finally: + db_conn.close() # create diff layer if geom_type is None: diff --git a/Mergin/processing/algs/create_diff.py b/Mergin/processing/algs/create_diff.py index 9fca41d7..aa275900 100644 --- a/Mergin/processing/algs/create_diff.py +++ b/Mergin/processing/algs/create_diff.py @@ -180,9 +180,13 @@ def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(30) if diff and table_name in diff.keys(): - db_conn = None # no ref. db db_conn = sqlite3.connect(layer_path) - features = diff_table_to_features(diff[table_name], db_schema[table_name], fields, fields_mapping, db_conn) + try: + features = diff_table_to_features( + diff[table_name], db_schema[table_name], fields, fields_mapping, db_conn + ) + finally: + db_conn.close() feedback.setProgress(40) step = 60.0 / len(features) if features else 0 diff --git a/Mergin/processing/algs/extract_local_changes.py b/Mergin/processing/algs/extract_local_changes.py index e4d07823..135c94c9 100644 --- a/Mergin/processing/algs/extract_local_changes.py +++ b/Mergin/processing/algs/extract_local_changes.py @@ -115,9 +115,13 @@ def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(15) if diff and table_name in diff.keys(): - db_conn = None # no ref. db db_conn = sqlite3.connect(layer_path) - features = diff_table_to_features(diff[table_name], db_schema[table_name], fields, fields_mapping, db_conn) + try: + features = diff_table_to_features( + diff[table_name], db_schema[table_name], fields, fields_mapping, db_conn + ) + finally: + db_conn.close() feedback.setProgress(20) step = 80.0 / len(features) if features else 0 From bb5ed0ee9ebe7cb6d33dd44343f36b153cc181ec Mon Sep 17 00:00:00 2001 From: Herman Snevajs Date: Fri, 15 May 2026 10:43:09 +0200 Subject: [PATCH 3/3] Use Connection.execute shortcut instead of explicit cursors --- Mergin/diff.py | 5 +---- Mergin/processing/algs/download_vector_tiles.py | 9 +++------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Mergin/diff.py b/Mergin/diff.py index 51e1a4ca..1c64de98 100644 --- a/Mergin/diff.py +++ b/Mergin/diff.py @@ -75,7 +75,6 @@ def get_row_from_db(db_conn, schema_table, entry_changes): Fetches a single row from DB's table based on the values of pkeys in changeset entry """ - c = db_conn.cursor() where_clauses = [] query_params = [] @@ -88,9 +87,7 @@ def get_row_from_db(db_conn, schema_table, entry_changes): # We parameterize values securely; table/column names are trusted internal schema objects. query = 'SELECT * FROM "{}" WHERE {}'.format(schema_table.name, " AND ".join(where_clauses)) # nosec B608 - c.execute(query, tuple(query_params)) - - return c.fetchone() + return db_conn.execute(query, tuple(query_params)).fetchone() def parse_gpkg_geom_encoding(wkb_with_gpkg_hdr): diff --git a/Mergin/processing/algs/download_vector_tiles.py b/Mergin/processing/algs/download_vector_tiles.py index 42be8ab7..4582e3c2 100644 --- a/Mergin/processing/algs/download_vector_tiles.py +++ b/Mergin/processing/algs/download_vector_tiles.py @@ -56,8 +56,7 @@ def create(self): "CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);" "COMMIT;" ) - cur = self.conn.cursor() - cur.executescript(sql) + self.conn.executescript(sql) return True def set_metadata_value(self, key, value): @@ -65,8 +64,7 @@ def set_metadata_value(self, key, value): return params = (key, value) - cur = self.conn.cursor() - cur.execute("insert into metadata values (?, ?)", params) + self.conn.execute("insert into metadata values (?, ?)", params) self.conn.commit() def set_tile_data(self, z, x, y, data): @@ -74,8 +72,7 @@ def set_tile_data(self, z, x, y, data): return params = (z, x, y, data) - cur = self.conn.cursor() - cur.execute("insert into tiles values (?, ?, ?, ?)", params) + self.conn.execute("insert into tiles values (?, ?, ?, ?)", params) self.conn.commit() def close(self):