From aa033afeeedd4d41493819312d652041017abf72 Mon Sep 17 00:00:00 2001 From: Jason Kirtland Date: Fri, 7 Mar 2008 16:56:37 +0000 Subject: [PATCH] Added support for vendor-extended INSERT syntax like INSERT DELAYED INTO --- CHANGES | 4 +++ lib/sqlalchemy/sql/compiler.py | 5 +++- lib/sqlalchemy/sql/expression.py | 22 +++++++++++++++- test/sql/generative.py | 45 ++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 0fe58815fb..b176db4ac9 100644 --- a/CHANGES +++ b/CHANGES @@ -27,6 +27,10 @@ CHANGES delete() and DDL(). The .bind property is now assignable on those statements as well as on select(). + - Insert statements can now be compiled with extra "prefix" + words between INSERT and INTO, for vendor extensions like + MySQL's INSERT IGNORE INTO table. + - orm - any(), has(), contains(), ~contains(), attribute level == and != now work properly with self-referential relations - diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 8a2a5f2ddb..bb9cc7597a 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -626,7 +626,10 @@ class DefaultCompiler(engine.Compiled): colparams = self._get_colparams(insert_stmt) preparer = self.preparer - return ("INSERT INTO %s (%s) VALUES (%s)" % + insert = ' '.join(["INSERT"] + + [self.process(x) for x in insert_stmt._prefixes]) + + return (insert + " INTO %s (%s) VALUES (%s)" % (preparer.format_table(insert_stmt.table), ', '.join([preparer.quote(c[0], c[0].name) for c in colparams]), diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 8e2a13e7ce..316cbd7c19 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -274,6 +274,10 @@ def insert(table, values=None, inline=False, **kwargs): column specifications will be generated from the full list of table columns. + prefixes + A list of modifier keywords to be inserted between INSERT and INTO, + see ``Insert.prefix_with``. + inline if True, SQL defaults will be compiled 'inline' into the statement and not pre-executed. @@ -3475,11 +3479,16 @@ class _UpdateBase(ClauseElement): bind = property(bind, _set_bind) class Insert(_UpdateBase): - def __init__(self, table, values=None, inline=False, bind=None, **kwargs): + def __init__(self, table, values=None, inline=False, bind=None, prefixes=None, **kwargs): self._bind = bind self.table = table self.select = None self.inline=inline + if prefixes: + self._prefixes = [_literal_as_text(p) for p in prefixes] + else: + self._prefixes = [] + self.parameters = self._process_colparams(values) self.kwargs = kwargs @@ -3504,6 +3513,17 @@ class Insert(_UpdateBase): u.parameters.update(u._process_colparams(v)) return u + def prefix_with(self, clause): + """Add a word or expression between INSERT and INTO. Generative. + + If multiple prefixes are supplied, they will be separated with + spaces. + """ + gen = self._clone() + clause = _literal_as_text(clause) + gen._prefixes = self._prefixes + [clause] + return gen + class Update(_UpdateBase): def __init__(self, table, whereclause, values=None, inline=False, bind=None, **kwargs): self._bind = bind diff --git a/test/sql/generative.py b/test/sql/generative.py index 5e6b3b7e6c..3d7c88972e 100644 --- a/test/sql/generative.py +++ b/test/sql/generative.py @@ -510,5 +510,50 @@ class SelectTest(TestBase, AssertsCompiledSQL): self.assert_compile(select_copy, "SELECT FOOBER table1.col1, table1.col2, table1.col3 FROM table1") self.assert_compile(s, "SELECT table1.col1, table1.col2, table1.col3 FROM table1") + +class InsertTest(TestBase, AssertsCompiledSQL): + """Tests the generative capability of Insert""" + + # fixme: consolidate converage from elsewhere here and expand + + def setUpAll(self): + global t1, t2 + t1 = table("table1", + column("col1"), + column("col2"), + column("col3"), + ) + t2 = table("table2", + column("col1"), + column("col2"), + column("col3"), + ) + + def test_prefixes(self): + i = t1.insert() + self.assert_compile(i, + "INSERT INTO table1 (col1, col2, col3) " + "VALUES (:col1, :col2, :col3)") + + gen = i.prefix_with("foober") + self.assert_compile(gen, + "INSERT foober INTO table1 (col1, col2, col3) " + "VALUES (:col1, :col2, :col3)") + + self.assert_compile(i, + "INSERT INTO table1 (col1, col2, col3) " + "VALUES (:col1, :col2, :col3)") + + i2 = t1.insert(prefixes=['squiznart']) + self.assert_compile(i2, + "INSERT squiznart INTO table1 (col1, col2, col3) " + "VALUES (:col1, :col2, :col3)") + + gen2 = i2.prefix_with("quux") + self.assert_compile(gen2, + "INSERT squiznart quux INTO " + "table1 (col1, col2, col3) " + "VALUES (:col1, :col2, :col3)") + if __name__ == '__main__': testenv.main() -- 2.47.3