db.dropcolumn: Circumvent length limit for sqlite3 SQL STDIN string#3273
Conversation
|
(Backport to 8.3 would be nice - I am not allowed to add labels) |
wenzeslaus
left a comment
There was a problem hiding this comment.
This is really great upgrade!
| driver=driver, | ||
| ) | ||
|
|
||
| if sqlite3_version >= "3.35.0": |
There was a problem hiding this comment.
Testing versions is a pain:
>>> "10.0.0" >= "3.35.0"
False
>>> [int(i) for i in "10.0.0".split(".")] >= [int(i) for i in "3.35.0".split(".")]
Truebut:
>>> [int(i) for i in "4.0.0-dev".split(".")] >= [int(i) for i in "3.35.0".split(".")]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
ValueError: invalid literal for int() with base 10: '0-dev'There was a problem hiding this comment.
Testing only major and minor version (3.35) should be enough and skip the patch/minor part which is not really relevant to this.
There was a problem hiding this comment.
Now comparing major and minor versions as arrays of INTs in recent commit.
|
In a little concerned about the old and new code in there. I never did SQL in Python, but if a code equivalent to that was done in C# and PHP, what looks like concatenation of strings to create a SQL query, would be vulnerable to SQL injection. I would expect that placeholders would be used and the parameters would be binded then executed. |
Co-authored-by: Vaclav Petras <[email protected]>
How could this look like? I read in some stackoverflow posts (no documentation quote at hand) that binding table or column names is not possible (for sqlite3), only values. if table not in gscript.read_command("db.tables"):
gscript.fatal(_("Table <%s> not found in db.tables") % column)but I am not sure if this is how |
| flags="c", | ||
| database=database, | ||
| driver=driver, | ||
| ).split(".")[0:2] |
There was a problem hiding this comment.
See maxsplit parameter which avoids the need for indexing later.
There was a problem hiding this comment.
I don't see the option to select only the first items when using maxsplit, or am I overseeing something? It will split until the given index but then adding all following into one item. This will cause the problem you described above:
>>> sqlite3_version = "4.0.0-dev"
>>> sqlite3_version.split('.',1)
['4', '0.0-dev']
>>> [int(i) for i in sqlite3_version.split('.',1)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
ValueError: invalid literal for int() with base 10: '0.0-dev'
>>> sqlite3_version.split('.',2)
['4', '0', '0-dev']
>>> [int(i) for i in sqlite3_version.split('.',2)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
ValueError: invalid literal for int() with base 10: '0-dev'
There was a problem hiding this comment.
@mmacata You're right, maxsplit might be used to limit the resulting list to three parts, eg:
>>> sqlite3_version = "4.0.0-dev"
>>> sqlite3_version.split('.', maxsplit=3)[:2]
['4', '0']but the index is needed. Although that seems to me to be over doing things. Index should be enough.
There was a problem hiding this comment.
@wenzeslaus do you also agee? Can this be merged as is?
I think this question on sql safety is out of scope for this PR. |
|
I'll merge this if no objections. |
…3273) * db.dropcolumn: support more recent sqlite3 drop column command * use sqlite_version() * Update scripts/db.dropcolumn/db.dropcolumn.py * enhance version comparison Co-authored-by: Vaclav Petras <[email protected]>
…SGeo#3273) * db.dropcolumn: support more recent sqlite3 drop column command * use sqlite_version() * Update scripts/db.dropcolumn/db.dropcolumn.py * enhance version comparison Co-authored-by: Vaclav Petras <[email protected]>
This PR supports a more recent sqlite3 command to drop a column within db.dropcolumn.
In sqlite3 3.35.0, the DROP COLUMN command was added. This PR makes use of the command if the sqlite3 version is high enough.
Background is a failing
db.in.ogrcommand for a CSV file containing many columns:And with further debugging:
So the created SQL string becomes too long to be passed via stdin in
"db.execute", input="-", database=database, driver=driver, stdin=sqlcommand. This PR circumvents this by using the newer sqlite3 syntax if available.