Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

db: fix SQL TRANSACTION syntax compatible with all DB backends #3636

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

tmszi
Copy link
Member

@tmszi tmszi commented Apr 21, 2024

SQL TRANSACTION syntax (compatible with all DB backends):

BEGIN;
...;
COMMIT;

This default SQL TRANSACTION syntax is not compatible with MySQL/MariaDB DB backend:

BEGIN TRANSACTION;
...;
END TRANSACTION;

Successfully tested with SQLite, PostgreSQL, MySQL DB backend.

@tmszi tmszi added this to the 8.4.0 milestone Apr 21, 2024
@tmszi tmszi self-assigned this Apr 21, 2024
@github-actions github-actions bot added vector Related to vector data processing Python Related code is in Python database Related to database management libraries module labels Apr 21, 2024
@tmszi tmszi added bug Something isn't working backport to 8.3 PR needs to be backported to release branch 8.3 labels Apr 21, 2024
@nilason
Copy link
Contributor

nilason commented Apr 22, 2024

I wonder if this shouldn't be approached in a different way. There is C API (driver specific) for this (db_begin_transaction(), db_commit_transaction()).

Anyways, it should have been START TRANSACTION and COMMIT, not BEGIN TRANSACTION and END TRANSACTION.

@tmszi
Copy link
Member Author

tmszi commented Apr 22, 2024

Anyways, it should have been START TRANSACTION and COMMIT, not BEGIN TRANSACTION and END TRANSACTION.

or BEGIN as alias for START TRANSACTION.

@nilason
Copy link
Contributor

nilason commented Apr 22, 2024

Anyways, it should have been START TRANSACTION and COMMIT, not BEGIN TRANSACTION and END TRANSACTION.

or BEGIN as alias for START TRANSACTION.

Yes, for the drivers that support it. You may take a look at how this is implemented for the different drivers in db/drivers/*/execute.c files.

@tmszi
Copy link
Member Author

tmszi commented Apr 22, 2024

I wonder if this shouldn't be approached in a different way. There is C API (driver specific) for this (db_begin_transaction(), db_commit_transaction()).

Yes you are right we can refactor it to better implementation on the low C lang level.

@github-actions github-actions bot added the C Related code is in C label Apr 22, 2024
@tmszi tmszi force-pushed the fix-sql-transaction-syntax-compatible-with-all-db-backends branch from ad77c20 to 6e66ee9 Compare April 22, 2024 10:04
@nilason
Copy link
Contributor

nilason commented Apr 22, 2024

Injecting sql code in db.execute breaks current behaviour, so that is not a good option. I was originally thinking of directly use C API in Python, like in:

def _deleteRecords(self, cats):

or
def CopyCats(self, fromId, toId, copyAttrb=False):

but that will require quite a lot of rewriting.

But you could perhaps use:
https://github.com/OSGeo/grass/blob/7413740dd81c11c2909ad10e7c3161fc097088f9/python/grass/script/db.py

def db_begin_transaction(driver):

…ansaction() func

To use C API db_begin_transaction(), db_commit_transaction().

Used by modules:

- db.dropcolumn
- v.db.addcolumn
- v.db.dropcolumn
- v.db.join.py
- v.db.univar
- v.dissolve
- v.rast.stats
@tmszi tmszi marked this pull request as draft April 22, 2024 18:51
@tmszi tmszi marked this pull request as ready for review April 23, 2024 10:35
@nilason
Copy link
Contributor

nilason commented Apr 23, 2024

I like where this is going. Something like this is what I had in mind, although it is way beyond the original intent of this PR. But I don't mind. Allows for more flexibility and control using C API directly, than via the module db.execute.
Not sure what to do about the change of behaviour of db_commit_transaction(API break).
I can also imagine making this a class, reducing the need to pass driver, database etc to every function call, and possibility to push sql commands (instead of building a string)... but before you put more work into this let us ask for the general opinion of this change by e.g. @petrasovaa, @wenzeslaus, @marisn.

@wenzeslaus
Copy link
Member

I also would like to replace putting the strings together by something better given our C database API and Python database APIs. While alternatives exists and some are employed in the code already, using the C library directly through C types is a straightforward option.

The API change is a potential issue. How big, I don't know, I'm guessing not big. Still, breaking it seems wrong. You also mentioned the issue of passing multiple parameters. I would certainly try how this would look as a class. This would be one way to avoid the change in the API. Perhaps following PEP 249 – Python Database API Specification or mimicking relevant parts of an existing SQL database Python API (Psycopg, sqlite3, SQLAlchemy, ...) would be good. Ideally, such API would actually hide whatever is happening in the background (constructing string for db.execute, passing to a native wrapper like sqlite3 or passing directly, or through a subprocess, to C API).

While when ctypes works, everything is just perfect, the experience is that something is often missing from the things which need to be in place for C API to work in Python. Hence, we have all the lazy imports in this PR and elsewhere. That's a thing which can be gradually improved, though. The many updates to ctypes lately were certainly helpful. Switching to Filesystem Hierarchy Standard might be another update which would help here ([GRASS-dev] GRASS 8.0 support in GDAL and QGIS).

I'm curious what others think.

@@ -122,9 +122,15 @@ def main():
sql = f'ALTER TABLE {table} DROP COLUMN "{column}"'

try:
pdriver = db_begin_transaction(driver_name=driver, database=database)
grass.write_command(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not db_execute as in other cases?

@marisn
Copy link
Contributor

marisn commented May 3, 2024

I also would like to replace putting the strings together by something better given our C database API and Python database APIs. While alternatives exists and some are employed in the code already, using the C library directly through C types is a straightforward option.

Proper prepared statements are way to go but lets take one step at a time (that would require a new C and Python API).

The API change is a potential issue. How big, I don't know, I'm guessing not big. Still, breaking it seems wrong.

This wouldn't be the first time when we break API on a minor release. Taking into account that this is not the most commonly used functionality, it fixes compatibility with one of our supported back-ends, I would not cry over this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport to 8.3 PR needs to be backported to release branch 8.3 bug Something isn't working C Related code is in C database Related to database management libraries module Python Related code is in Python vector Related to vector data processing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants