Merge lp:~stub/launchpad/pending-db-changes into lp:launchpad/db-devel

Proposed by Stuart Bishop
Status: Merged
Approved by: Stuart Bishop
Approved revision: no longer in the source branch.
Merged at revision: 10059
Proposed branch: lp:~stub/launchpad/pending-db-changes
Merge into: lp:launchpad/db-devel
Diff against target: 54 lines (+10/-22)
1 file modified
database/schema/upgrade.py (+10/-22)
To merge this branch: bzr merge lp:~stub/launchpad/pending-db-changes
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Review via email: mp+43763@code.launchpad.net

Commit message

[r=jelmer][ui=none][bug=689642] Fail if we attempt to apply a database script that doesn't terminate with a semicolon.

Description of the change

Per Bug #689642, database patches could be applied locally if they did not terminate with a semicolon, but would fail when applied to a replicated environment. This bug would also apply to trusted.sql and comments.sql.

I fixed this by removing some unnecessary code where we were splitting the patches into statements and failing if we attempt to apply an sql script with no terminating semicolon.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

As discussed on IRC, please clarify the error message to mention that the last non-whitespace character in the file should be a semicolon - in case the last line contains a comment.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/upgrade.py'
2--- database/schema/upgrade.py 2010-12-07 12:31:55 +0000
3+++ database/schema/upgrade.py 2010-12-15 15:09:45 +0000
4@@ -496,26 +496,7 @@
5
6
7 def apply_patch(con, major, minor, patch, patch_file):
8- log.info("Applying %s" % patch_file)
9- cur = con.cursor()
10- full_sql = open(patch_file).read()
11-
12- # Strip comments
13- full_sql = re.sub('(?xms) \/\* .*? \*\/', '', full_sql)
14- full_sql = re.sub('(?xm) ^\s*-- .*? $', '', full_sql)
15-
16- # Regular expression to extract a single statement.
17- # A statement may contain semicolons if it is a stored procedure
18- # definition, which requires a disgusting regexp or a parser for
19- # PostgreSQL specific SQL.
20- statement_re = re.compile(
21- r"( (?: [^;$] | \$ (?! \$) | \$\$.*? \$\$)+ )",
22- re.DOTALL | re.MULTILINE | re.VERBOSE
23- )
24- for sql in statement_re.split(full_sql):
25- sql = sql.strip()
26- if sql and sql != ';':
27- cur.execute(sql) # Will die on a bad patch.
28+ apply_other(con, patch_file, no_commit=True)
29
30 # Ensure the patch updated LaunchpadDatabaseRevision. We could do this
31 # automatically and avoid the boilerplate, but then we would lose the
32@@ -531,14 +512,21 @@
33 con.commit()
34
35
36-def apply_other(con, script):
37+def apply_other(con, script, no_commit=False):
38 log.info("Applying %s" % script)
39 cur = con.cursor()
40 path = os.path.join(os.path.dirname(__file__), script)
41 sql = open(path).read()
42+ if not sql.rstrip().endswith(';'):
43+ # This is important because patches are concatenated together
44+ # into a single script when we apply them to a replicated
45+ # environment.
46+ log.fatal(
47+ "Last non-whitespace character of %s must be a semicolon", script)
48+ sys.exit(3)
49 cur.execute(sql)
50
51- if options.commit and options.partial:
52+ if not no_commit and options.commit and options.partial:
53 log.debug("Committing changes")
54 con.commit()
55

Subscribers

People subscribed via source and target branches

to status/vote changes: