Opened 18 years ago

Closed 18 years ago

Last modified 13 years ago

#1935 closed defect (fixed)

[patch] sqlite3 can't handle initial data with more than one statement

Reported by: jpellerin@… 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)

django.core.management.diff (1.5 KB ) - added by jpellerin@… 18 years ago.
patch to split sql initial data into individual sql statements
patch-initial_sql_regex (575 bytes ) - added by anonymous 18 years ago.
patch-initial_sql_regex-v2 (804 bytes ) - added by Landon Fuller <landonf@…> 18 years ago.

Download all attachments as: .zip

Change History (12)

by jpellerin@…, 18 years ago

Attachment: django.core.management.diff added

patch to split sql initial data into individual sql statements

comment:1 by jpellerin@…, 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 Adrian Holovaty, 18 years ago

Resolution: fixed
Status: newclosed

(In [2985]) Fixed #1935 -- Initial SQL data now works in SQLite if there are multiple statements. Thanks, jpellerin@…

comment:3 by anonymous, 18 years ago

Resolution: fixed
Status: closedreopened

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 anonymous, 18 years ago

Attachment: patch-initial_sql_regex added

comment:4 by landonf@…, 18 years ago

Comment to note non-anonymous source of regex patch and bug re-opening.

comment:5 by Landon Fuller <landonf@…>, 18 years ago

Cc: landonf@… added

comment:6 by Landon Fuller <landonf@…>, 18 years ago

Severity: normalmajor

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 Landon Fuller <landonf@…>, 18 years ago

Attachment: patch-initial_sql_regex-v2 added

comment:7 by Landon Fuller <landonf@…>, 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 Malcolm Tredinnick, 18 years ago

Resolution: fixed
Status: reopenedclosed

(In [3178]) Fixed #2119 -- fixed problems with splitting SQL statements into separate
statements. Uses a patch from eaw@… and some contributions from
jpellerin@…. Also fixes #2034 and #1935.

comment:9 by David Rogers, 13 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.

Note: See TracTickets for help on using tickets.
Back to Top