#1935 closed defect (fixed)
[patch] sqlite3 can't handle initial data with more than one statement
Reported by: | Owned by: | Adrian Holovaty | |
---|---|---|---|
Component: | Core (Other) | Version: | dev |
Severity: | major | Keywords: | |
Cc: | landonf@… | Triage Stage: | Unreviewed |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Using django trunk [2947], pysqlite 2.2.2 and sqlite 3.3.5, I can't include more than one statement in my models' initial data files, or sqlite chokes with an error: "You can only execute one statement at a time". Various googlable comments here and elsewhere indicate that there is some magical combination of sqlite version and pysqlite version that will make this work, but I've been unable to find it. Seems likely that others are probably unable also, so I think a workaround in django will be valuable.
Attached is a patch against [2947] django.core.management.py that uses a regular expression to split multiple statements in a model's sql initial data on ;, so that they can be fed to badly-behaving backends one at a time.
Attachments (3)
Change History (12)
by , 18 years ago
Attachment: | django.core.management.diff added |
---|
comment:1 by , 18 years ago
Further information: according to the sqlite source, executing multiple sql statements in one execute() is explicitly disallowed by DB-API.
Ref: http://www.initd.org/tracker/pysqlite/changeset/177#file3
comment:2 by , 18 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:3 by , 18 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
The current regular expression does not correctly handle ';' terminated SQL statements. Because the regular expression considers '\n' valid within an SQL statement, but ';' is considered a terminator, the following occurs:
ALTER TABLE "assets_company" ADD CONSTRAINT "vvalid_name" CHECK (LENGTH(name) != 3);
is parsed as:
['ALTER TABLE "assets_company" ADD CONSTRAINT "valid_name" CHECK (LENGTH(name) != 0)', '\n']
The postgresql driver errors out upon receiving a statement containing only '\n'. A patch to correctly handle statement termination is attached.
by , 18 years ago
Attachment: | patch-initial_sql_regex added |
---|
comment:5 by , 18 years ago
Cc: | added |
---|
comment:6 by , 18 years ago
Severity: | normal → major |
---|
I've updated the patch to also fix: #2034, #2044, and #2119. I've only tested against Postgesql. Pasting it inline as well as attaching it, since it's short:
Index: management.py
===================================================================
--- management.py (revision 3137)
+++ management.py (working copy)
@@ -337,9 +337,9 @@
r"""( # each statement is...
(?: # one or more chunks of ...
(?:[;'"]+) # not the end of a statement or start of a quote
- | (?:'[']*') # something in single quotes
- | (?:"["]*") # something in double quotes
- )+)""", re.VERBOSE)
+ | (?:'(?:[']|<?=\')*') # something in single quotes
+ | (?:"(?:["]|<?=\")*") # something in double quotes
+ )+;?[ \t\n]?)""", re.VERBOSE)
# Find custom SQL, if it's available.
sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
by , 18 years ago
Attachment: | patch-initial_sql_regex-v2 added |
---|
comment:7 by , 18 years ago
Okay, so I obviously don't know how to use wiki formatting. Sorry!
Index: management.py =================================================================== --- management.py (revision 3137) +++ management.py (working copy) @@ -337,9 +337,9 @@ r"""( # each statement is... (?: # one or more chunks of ... (?:[^;'"]+) # not the end of a statement or start of a quote - | (?:'[^']*') # something in single quotes - | (?:"[^"]*") # something in double quotes - )+)""", re.VERBOSE) + | (?:'(?:[^']|<?=\')*') # something in single quotes + | (?:"(?:[^"]|<?=\")*") # something in double quotes + )+;?[ \t\n]?)""", re.VERBOSE) # Find custom SQL, if it's available. sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
comment:8 by , 18 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
comment:9 by , 14 years ago
This may not be a worthwhile concern, but the current implementation does not properly account for SQL comments after a semicolon. Consider:
DROP VIEW "some_view" IF EXISTS; CREATE VIEW "some_view" AS SELECT "some_field" FROM "some_table" LEFT JOIN "some_other_table" USING "some_other_id" WHERE ( "some_field" BETWEEN 1 AND 1000 ) ; -- CREATE VIEW "some_view"
For an exceptionally large CREATE
statement, the comments are helpful. SQLite will complain about making two queries in the same execute() statement, because the current code doesn't address trailing comments.
patch to split sql initial data into individual sql statements