diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-09-01 19:49:26 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-09-01 19:49:26 +0000 |
commit | 69f7084c9b79b0b70f2b24400fb150a0a40d0424 (patch) | |
tree | 1da7f3a6b0a873472b57ad0e093339be6cff0b48 /test/dialect/postgres.py | |
parent | 15ab87994ced6f27e0403ce16fd7ffada31e6858 (diff) | |
download | sqlalchemy-69f7084c9b79b0b70f2b24400fb150a0a40d0424.tar.gz |
- merged inline inserts branch
- all executemany() style calls put all sequences and SQL defaults inline into a single SQL statement
and don't do any pre-execution
- regular Insert and Update objects can have inline=True, forcing all executions to be inlined.
- no last_inserted_ids(), lastrow_has_defaults() available with inline execution
- calculation of pre/post execute pushed into compiler; DefaultExecutionContext greatly simplified
- fixed postgres reflection of primary key columns with no sequence/default generator, sets autoincrement=False
- fixed postgres executemany() behavior regarding sequences present, not present, passivedefaults, etc.
- all tests pass for sqlite, mysql, postgres; oracle tests pass as well as they did previously including all
insert/update/default functionality
Diffstat (limited to 'test/dialect/postgres.py')
-rw-r--r-- | test/dialect/postgres.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/test/dialect/postgres.py b/test/dialect/postgres.py index c12115c9a..3a1c978ac 100644 --- a/test/dialect/postgres.py +++ b/test/dialect/postgres.py @@ -1,10 +1,282 @@ import testbase import datetime from sqlalchemy import * +from sqlalchemy import exceptions from sqlalchemy.databases import postgres from testlib import * +class InsertTest(AssertMixin): + @testing.supported('postgres') + def setUpAll(self): + global metadata + metadata = MetaData(testbase.db) + + @testing.supported('postgres') + def tearDown(self): + metadata.drop_all() + metadata.tables.clear() + + @testing.supported('postgres') + def test_compiled_insert(self): + table = Table('testtable', metadata, + Column('id', Integer, primary_key=True), + Column('data', String(30))) + + metadata.create_all() + ins = table.insert(values={'data':bindparam('x')}).compile() + ins.execute({'x':"five"}, {'x':"seven"}) + assert table.select().execute().fetchall() == [(1, 'five'), (2, 'seven')] + + @testing.supported('postgres') + def test_sequence_insert(self): + table = Table('testtable', metadata, + Column('id', Integer, Sequence('my_seq'), primary_key=True), + Column('data', String(30))) + metadata.create_all() + self._assert_data_with_sequence(table, "my_seq") + + @testing.supported('postgres') + def test_opt_sequence_insert(self): + table = Table('testtable', metadata, + Column('id', Integer, Sequence('my_seq', optional=True), primary_key=True), + Column('data', String(30))) + metadata.create_all() + self._assert_data_autoincrement(table) + + @testing.supported('postgres') + def test_autoincrement_insert(self): + table = Table('testtable', metadata, + Column('id', Integer, primary_key=True), + Column('data', String(30))) + metadata.create_all() + self._assert_data_autoincrement(table) + + @testing.supported('postgres') + def test_noautoincrement_insert(self): + table = Table('testtable', metadata, + Column('id', Integer, primary_key=True, autoincrement=False), + Column('data', String(30))) + metadata.create_all() + self._assert_data_noautoincrement(table) + + def _assert_data_autoincrement(self, table): + def go(): + # execute with explicit id + r = table.insert().execute({'id':30, 'data':'d1'}) + assert r.last_inserted_ids() == [30] + + # execute with prefetch id + r = table.insert().execute({'data':'d2'}) + assert r.last_inserted_ids() == [1] + + # executemany with explicit ids + table.insert().execute({'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}) + + # executemany, uses SERIAL + table.insert().execute({'data':'d5'}, {'data':'d6'}) + + # single execute, explicit id, inline + table.insert(inline=True).execute({'id':33, 'data':'d7'}) + + # single execute, inline, uses SERIAL + table.insert(inline=True).execute({'data':'d8'}) + + # note that the test framework doesnt capture the "preexecute" of a seqeuence + # or default. we just see it in the bind params. + + self.assert_sql(testbase.db, go, [], with_sequences=[ + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':30, 'data':'d1'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':1, 'data':'d2'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}] + ), + ( + "INSERT INTO testtable (data) VALUES (:data)", + [{'data':'d5'}, {'data':'d6'}] + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':33, 'data':'d7'}] + ), + ( + "INSERT INTO testtable (data) VALUES (:data)", + [{'data':'d8'}] + ), + ]) + + assert table.select().execute().fetchall() == [ + (30, 'd1'), + (1, 'd2'), + (31, 'd3'), + (32, 'd4'), + (2, 'd5'), + (3, 'd6'), + (33, 'd7'), + (4, 'd8'), + ] + table.delete().execute() + + # test the same series of events using a reflected + # version of the table + m2 = MetaData(testbase.db) + table = Table(table.name, m2, autoload=True) + + def go(): + table.insert().execute({'id':30, 'data':'d1'}) + r = table.insert().execute({'data':'d2'}) + assert r.last_inserted_ids() == [5] + table.insert().execute({'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}) + table.insert().execute({'data':'d5'}, {'data':'d6'}) + table.insert(inline=True).execute({'id':33, 'data':'d7'}) + table.insert(inline=True).execute({'data':'d8'}) + + self.assert_sql(testbase.db, go, [], with_sequences=[ + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':30, 'data':'d1'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':5, 'data':'d2'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}] + ), + ( + "INSERT INTO testtable (data) VALUES (:data)", + [{'data':'d5'}, {'data':'d6'}] + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':33, 'data':'d7'}] + ), + ( + "INSERT INTO testtable (data) VALUES (:data)", + [{'data':'d8'}] + ), + ]) + + assert table.select().execute().fetchall() == [ + (30, 'd1'), + (5, 'd2'), + (31, 'd3'), + (32, 'd4'), + (6, 'd5'), + (7, 'd6'), + (33, 'd7'), + (8, 'd8'), + ] + table.delete().execute() + + def _assert_data_with_sequence(self, table, seqname): + def go(): + table.insert().execute({'id':30, 'data':'d1'}) + table.insert().execute({'data':'d2'}) + table.insert().execute({'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}) + table.insert().execute({'data':'d5'}, {'data':'d6'}) + table.insert(inline=True).execute({'id':33, 'data':'d7'}) + table.insert(inline=True).execute({'data':'d8'}) + + self.assert_sql(testbase.db, go, [], with_sequences=[ + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':30, 'data':'d1'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + {'id':1, 'data':'d2'} + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':31, 'data':'d3'}, {'id':32, 'data':'d4'}] + ), + ( + "INSERT INTO testtable (id, data) VALUES (nextval('%s'), :data)" % seqname, + [{'data':'d5'}, {'data':'d6'}] + ), + ( + "INSERT INTO testtable (id, data) VALUES (:id, :data)", + [{'id':33, 'data':'d7'}] + ), + ( + "INSERT INTO testtable (id, data) VALUES (nextval('%s'), :data)" % seqname, + [{'data':'d8'}] + ), + ]) + + assert table.select().execute().fetchall() == [ + (30, 'd1'), + (1, 'd2'), + (31, 'd3'), + (32, 'd4'), + (2, 'd5'), + (3, 'd6'), + (33, 'd7'), + (4, 'd8'), + ] + + # cant test reflection here since the Sequence must be + # explicitly specified + + def _assert_data_noautoincrement(self, table): + table.insert().execute({'id':30, 'data':'d1'}) + try: + table.insert().execute({'data':'d2'}) + assert False + except exceptions.IntegrityError, e: + assert "violates not-null constraint" in str(e) + try: + table.insert().execute({'data':'d2'}, {'data':'d3'}) + assert False + except exceptions.IntegrityError, e: + assert "violates not-null constraint" in str(e) + + table.insert().execute({'id':31, 'data':'d2'}, {'id':32, 'data':'d3'}) + table.insert(inline=True).execute({'id':33, 'data':'d4'}) + + assert table.select().execute().fetchall() == [ + (30, 'd1'), + (31, 'd2'), + (32, 'd3'), + (33, 'd4'), + ] + table.delete().execute() + + # test the same series of events using a reflected + # version of the table + m2 = MetaData(testbase.db) + table = Table(table.name, m2, autoload=True) + table.insert().execute({'id':30, 'data':'d1'}) + try: + table.insert().execute({'data':'d2'}) + assert False + except exceptions.IntegrityError, e: + assert "violates not-null constraint" in str(e) + try: + table.insert().execute({'data':'d2'}, {'data':'d3'}) + assert False + except exceptions.IntegrityError, e: + assert "violates not-null constraint" in str(e) + + table.insert().execute({'id':31, 'data':'d2'}, {'id':32, 'data':'d3'}) + table.insert(inline=True).execute({'id':33, 'data':'d4'}) + + assert table.select().execute().fetchall() == [ + (30, 'd1'), + (31, 'd2'), + (32, 'd3'), + (33, 'd4'), + ] + class DomainReflectionTest(AssertMixin): "Test PostgreSQL domains" |