public inbox for [email protected]help / color / mirror / Atom feed
Re: TAP test command_fails versus command_fails_like 6+ messages / 5 participants [nested] [flat]
* Re: TAP test command_fails versus command_fails_like @ 2025-02-12 13:58 Dagfinn Ilmari Mannsåker <[email protected]> 0 siblings, 2 replies; 6+ messages in thread From: Dagfinn Ilmari Mannsåker @ 2025-02-12 13:58 UTC (permalink / raw) To: Ashutosh Bapat <[email protected]>; +Cc: Peter Smith <[email protected]>; PostgreSQL Hackers <[email protected]> Ashutosh Bapat <[email protected]> writes: > On Wed, Feb 12, 2025 at 10:36 AM Peter Smith <[email protected]> wrote: >> >> Hi hackers, >> >> Recently, while writing some new TAP tests my colleague inadvertently >> called the command_fails() subroutine instead of command_fails_like() >> subroutine. Their parameters are almost the same but >> command_fails_like() also takes a pattern for checking in the logs. >> Notice if too many parameters are passed to command_fails they get >> silently ignored. >> >> Because of the mistake, the tests were all bogus because they were no >> longer testing error messages as was the intention. OTOH, because >> command failure was expected those tests still would record a "pass" >> despite the wrong subroutine being used, so there is no evidence that >> anything is wrong. >> >> I wondered if the command_fails() subroutine could have done more to >> protect users from accidentally shooting themselves. My attached patch >> does this by ensuring that no "extra" (unexpected) parameters are >> being passed to command_fails(). It seems more foolproof. >> > > We will need to fix many perl functions this way but I think > command_fails and command_fails_like or any other pair of similarly > named functions needs better protection. Looking at > https://stackoverflow.com/questions/19234209/perl-subroutine-arguments, > I feel a construct like below is more readable and crisp. > > die "Too many arguments for subroutine" unless @_ <= 1; I would write that as `if @_ > 1`, but otherwise I agree. This is a programmer error, not a test failure, so it should use die() (or even croak(), to report the error from the caller's perspective), not is(). > Another question is whether command_fails and command_fails_like is > the only pair or there are more which need stricter checks? If we do this, we should do it across the board for PostgreSQL::Test::Utils and ::Cluster at least. Once we bump the minimum perl version to 5.20 or beyond we should switch to using function signatures (https://perldoc.perl.org/perlsub#Signatures), which gives us this checking for free. > This won't eliminate cases where command_like is used instead of > command_like_safe, and vice-versa, where logic is slightly different. > So the question is how far do we go detecting such misuses? command_like and command_like_safe take exactly the same parameters, the only difference is how they capture stdout/stderr, so there's no way to tell which one the caller meant. What we can detect however is if command_ok is called when someone meant command_like. - imari ^ permalink raw reply [nested|flat] 6+ messages in thread
* Re: TAP test command_fails versus command_fails_like @ 2025-02-12 15:40 Andrew Dunstan <[email protected]> parent: Dagfinn Ilmari Mannsåker <[email protected]> 1 sibling, 1 reply; 6+ messages in thread From: Andrew Dunstan @ 2025-02-12 15:40 UTC (permalink / raw) To: Dagfinn Ilmari Mannsåker <[email protected]>; Ashutosh Bapat <[email protected]>; +Cc: Peter Smith <[email protected]>; PostgreSQL Hackers <[email protected]> On 2025-02-12 We 8:58 AM, Dagfinn Ilmari Mannsåker wrote: > >> Another question is whether command_fails and command_fails_like is >> the only pair or there are more which need stricter checks? > If we do this, we should do it across the board for > PostgreSQL::Test::Utils and ::Cluster at least. Once we bump the > minimum perl version to 5.20 or beyond we should switch to using > function signatures (https://perldoc.perl.org/perlsub#Signatures), which > gives us this checking for free. > Is there any reason we can't move to 5.20? Are there any buildfarm animals using such an old version? 5.20 is now almost 10 years old. cheers andrew -- Andrew Dunstan EDB: https://www.enterprisedb.com ^ permalink raw reply [nested|flat] 6+ messages in thread
* Re: TAP test command_fails versus command_fails_like @ 2025-02-12 16:58 Dagfinn Ilmari Mannsåker <[email protected]> parent: Andrew Dunstan <[email protected]> 0 siblings, 1 reply; 6+ messages in thread From: Dagfinn Ilmari Mannsåker @ 2025-02-12 16:58 UTC (permalink / raw) To: Andrew Dunstan <[email protected]>; +Cc: Ashutosh Bapat <[email protected]>; Peter Smith <[email protected]>; PostgreSQL Hackers <[email protected]> Andrew Dunstan <[email protected]> writes: > On 2025-02-12 We 8:58 AM, Dagfinn Ilmari Mannsåker wrote: >> >>> Another question is whether command_fails and command_fails_like is >>> the only pair or there are more which need stricter checks? >> If we do this, we should do it across the board for >> PostgreSQL::Test::Utils and ::Cluster at least. Once we bump the >> minimum perl version to 5.20 or beyond we should switch to using >> function signatures (https://perldoc.perl.org/perlsub#Signatures), which >> gives us this checking for free. > > Is there any reason we can't move to 5.20? Are there any buildfarm > animals using such an old version? 5.20 is now almost 10 years old. Red Hat Enterprise Linux 7 has Perl 5.16 and is on Extended Lifecycle Support until 2028-06-30. I don't know how long other distros based on that (e.g. CentOS, Scientific Linux) are supported, but I can see that Amazon Linux 2 is almost out of support (2025-06-30). > cheers > > andrew - ilmari ^ permalink raw reply [nested|flat] 6+ messages in thread
* Re: TAP test command_fails versus command_fails_like @ 2025-02-12 17:18 Tom Lane <[email protected]> parent: Dagfinn Ilmari Mannsåker <[email protected]> 0 siblings, 0 replies; 6+ messages in thread From: Tom Lane @ 2025-02-12 17:18 UTC (permalink / raw) To: Dagfinn Ilmari Mannsåker <[email protected]>; +Cc: Andrew Dunstan <[email protected]>; Ashutosh Bapat <[email protected]>; Peter Smith <[email protected]>; PostgreSQL Hackers <[email protected]> =?utf-8?Q?Dagfinn_Ilmari_Manns=C3=A5ker?= <[email protected]> writes: > Andrew Dunstan <[email protected]> writes: >> Is there any reason we can't move to 5.20? Are there any buildfarm >> animals using such an old version? 5.20 is now almost 10 years old. > Red Hat Enterprise Linux 7 has Perl 5.16 and is on Extended Lifecycle > Support until 2028-06-30. I don't know how long other distros based on > that (e.g. CentOS, Scientific Linux) are supported, but I can see that > Amazon Linux 2 is almost out of support (2025-06-30). The oldest perl versions I see in the buildfarm are longfin | 2025-02-12 14:42:03 | configure: using perl 5.14.0 lapwing | 2025-02-10 16:24:03 | configure: using perl 5.14.2 arowana | 2025-02-12 04:08:19 | configure: using perl 5.16.3 boa | 2025-02-12 16:28:51 | configure: using perl 5.16.3 buri | 2025-02-11 21:11:11 | configure: using perl 5.16.3 dhole | 2025-02-12 06:08:04 | configure: using perl 5.16.3 rhinoceros | 2025-02-12 14:52:10 | configure: using perl 5.16.3 siskin | 2025-02-11 21:39:44 | configure: using perl 5.16.3 snakefly | 2025-02-10 01:00:04 | configure: using perl 5.16.3 shelduck | 2025-02-12 12:13:18 | configure: using perl 5.18.2 topminnow | 2025-01-27 08:22:18 | configure: using perl 5.20.2 batfish | 2025-02-12 15:38:00 | configure: using perl 5.22.1 cuon | 2025-02-12 05:08:03 | configure: using perl 5.22.1 ayu | 2025-02-12 13:15:26 | configure: using perl 5.24.1 chimaera | 2025-02-12 11:14:35 | configure: using perl 5.24.1 urocryon | 2025-02-12 02:07:16 | configure: using perl 5.24.1 (This scan did not account for meson-using animals, which I'm assuming are generally newer.) longfin is my own animal and is intentionally set up with the oldest supported Perl version; I'd have no problem moving it to another version if we decide to move that goalpost. lapwing I believe we've already nagged the owner of to update (its flex is museum-grade too). But it looks like moving past 5.16 would be more problematic. regards, tom lane ^ permalink raw reply [nested|flat] 6+ messages in thread
* Re: TAP test command_fails versus command_fails_like @ 2025-02-22 01:27 Peter Smith <[email protected]> parent: Dagfinn Ilmari Mannsåker <[email protected]> 1 sibling, 0 replies; 6+ messages in thread From: Peter Smith @ 2025-02-22 01:27 UTC (permalink / raw) To: Dagfinn Ilmari Mannsåker <[email protected]>; +Cc: Ashutosh Bapat <[email protected]>; PostgreSQL Hackers <[email protected]> On Thu, Feb 13, 2025 at 12:58 AM Dagfinn Ilmari Mannsåker <[email protected]> wrote: > > Ashutosh Bapat <[email protected]> writes: > > > On Wed, Feb 12, 2025 at 10:36 AM Peter Smith <[email protected]> wrote: > >> > >> Hi hackers, > >> > >> Recently, while writing some new TAP tests my colleague inadvertently > >> called the command_fails() subroutine instead of command_fails_like() > >> subroutine. Their parameters are almost the same but > >> command_fails_like() also takes a pattern for checking in the logs. > >> Notice if too many parameters are passed to command_fails they get > >> silently ignored. > >> > >> Because of the mistake, the tests were all bogus because they were no > >> longer testing error messages as was the intention. OTOH, because > >> command failure was expected those tests still would record a "pass" > >> despite the wrong subroutine being used, so there is no evidence that > >> anything is wrong. > >> > >> I wondered if the command_fails() subroutine could have done more to > >> protect users from accidentally shooting themselves. My attached patch > >> does this by ensuring that no "extra" (unexpected) parameters are > >> being passed to command_fails(). It seems more foolproof. > >> > > > > We will need to fix many perl functions this way but I think > > command_fails and command_fails_like or any other pair of similarly > > named functions needs better protection. Looking at > > https://stackoverflow.com/questions/19234209/perl-subroutine-arguments, > > I feel a construct like below is more readable and crisp. > > > > die "Too many arguments for subroutine" unless @_ <= 1; > > I would write that as `if @_ > 1`, but otherwise I agree. This is a > programmer error, not a test failure, so it should use die() (or even > croak(), to report the error from the caller's perspective), not is(). > > > Another question is whether command_fails and command_fails_like is > > the only pair or there are more which need stricter checks? > > If we do this, we should do it across the board for > PostgreSQL::Test::Utils and ::Cluster at least. Here is a v2 patch covering many more subroutines, using the syntax that was suggested above. make check-world passes. ====== Kind Regards, Peter Smith. Fujitsu Australia Attachments: [application/octet-stream] v2-0001-Help-prevent-users-from-calling-the-wrong-functio.patch (21.1K, ../../CAHut+Puho_Xa4cKxf+8_4dASpGvbXJT2D4Dwk-JD=NRnP273NQ@mail.gmail.com/2-v2-0001-Help-prevent-users-from-calling-the-wrong-functio.patch) download | inline diff: From 93554e07865945b2f8fdefdae0edfcb229f5e0f5 Mon Sep 17 00:00:00 2001 From: Peter Smith <[email protected]> Date: Sat, 22 Feb 2025 12:14:11 +1100 Subject: [PATCH v2] Help prevent users from calling the wrong function --- src/test/perl/PostgreSQL/Test/Cluster.pm | 59 ++++++++++++++++++++++++++++++++ src/test/perl/PostgreSQL/Test/Utils.pm | 23 +++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm index f521ad0..cd9de4b 100644 --- a/src/test/perl/PostgreSQL/Test/Cluster.pm +++ b/src/test/perl/PostgreSQL/Test/Cluster.pm @@ -201,6 +201,7 @@ Use $node->connstr() if you want a connection string. sub port { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_port}; } @@ -217,6 +218,7 @@ Use $node->connstr() if you want a connection string. sub host { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_host}; } @@ -232,6 +234,7 @@ backups, etc. sub basedir { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_basedir}; } @@ -246,6 +249,7 @@ The name assigned to the node at creation time. sub name { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_name}; } @@ -260,6 +264,7 @@ Path to the PostgreSQL log file for this instance. sub logfile { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_logfile}; } @@ -275,6 +280,7 @@ this node. Suitable for passing to psql, DBD::Pg, etc. sub connstr { my ($self, $dbname) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $pgport = $self->port; my $pghost = $self->host; if (!defined($dbname)) @@ -302,6 +308,7 @@ used by low-level protocol and connection limit tests. sub raw_connect { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $pgport = $self->port; my $pghost = $self->host; @@ -348,6 +355,7 @@ architecture". sub raw_connect_works { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; # If we're using Unix domain sockets, we need a working # IO::Socket::UNIX implementation. @@ -377,6 +385,7 @@ Does the data dir allow group access? sub group_access { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $dir_stat = stat($self->data_dir); @@ -398,6 +407,7 @@ always here. sub data_dir { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $res = $self->basedir; return "$res/pgdata"; } @@ -413,6 +423,7 @@ If archiving is enabled, WAL files go here. sub archive_dir { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $basedir = $self->basedir; return "$basedir/archives"; } @@ -428,6 +439,7 @@ The output path for backups taken with $node->backup() sub backup_dir { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $basedir = $self->basedir; return "$basedir/backup"; } @@ -443,6 +455,7 @@ The configured install path (if any) for the node. sub install_path { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_install_path}; } @@ -457,6 +470,7 @@ The version number for the node, from PostgreSQL::Version. sub pg_version { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return $self->{_pg_version}; } @@ -477,6 +491,7 @@ If options are supplied, return the list of values. sub config_data { my ($self, @options) = @_; + die "Too many arguments for subroutine" if @_ > 2; local %ENV = $self->_get_env(); my ($stdout, $stderr); @@ -516,6 +531,7 @@ about this node. sub info { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $_info = ''; open my $fh, '>', \$_info or die; print $fh "Name: " . $self->name . "\n"; @@ -543,6 +559,7 @@ Print $node->info() sub dump_info { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; print $self->info; return; } @@ -553,6 +570,7 @@ sub dump_info sub set_replication_conf { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $pgdata = $self->data_dir; $self->host eq $test_pghost @@ -759,6 +777,7 @@ A newline is automatically appended to the string. sub append_conf { my ($self, $filename, $str) = @_; + die "Too many arguments for subroutine" if @_ > 3; my $conffile = $self->data_dir . '/' . $filename; @@ -787,6 +806,7 @@ responsibility to do that. sub adjust_conf { my ($self, $filename, $setting, $value, $skip_equals) = @_; + die "Too many arguments for subroutine" if @_ > 5; my $conffile = $self->data_dir . '/' . $filename; @@ -863,6 +883,7 @@ Use B<backup> if you want to back up a running server. sub backup_fs_cold { my ($self, $backup_name) = @_; + die "Too many arguments for subroutine" if @_ > 2; PostgreSQL::Test::RecursiveCopy::copypath( $self->data_dir, @@ -1088,6 +1109,7 @@ will use the new name. Return the new name. sub rotate_logfile { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; $self->{_logfile} = sprintf('%s_%d.log', $self->{_logfile_base}, ++$self->{_logfile_generation}); @@ -1171,6 +1193,7 @@ this to fail. Otherwise, tests might fail to detect server crashes. sub kill9 { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $name = $self->name; return unless defined $self->{_pid}; @@ -1246,6 +1269,7 @@ Reload configuration parameters on the node. sub reload { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $port = $self->port; my $pgdata = $self->data_dir; my $name = $self->name; @@ -1312,6 +1336,7 @@ Wrapper for pg_ctl promote sub promote { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $port = $self->port; my $pgdata = $self->data_dir; my $logfile = $self->logfile; @@ -1336,6 +1361,7 @@ Wrapper for pg_ctl logrotate sub logrotate { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $port = $self->port; my $pgdata = $self->data_dir; my $logfile = $self->logfile; @@ -1353,6 +1379,7 @@ sub logrotate sub enable_streaming { my ($self, $root_node) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $root_connstr = $root_node->connstr; my $name = $self->name; @@ -1369,6 +1396,7 @@ primary_conninfo='$root_connstr' sub enable_restoring { my ($self, $root_node, $standby) = @_; + die "Too many arguments for subroutine" if @_ > 3; my $path = $root_node->archive_dir; my $name = $self->name; @@ -1414,6 +1442,7 @@ Place recovery.signal file. sub set_recovery_mode { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; $self->append_conf('recovery.signal', ''); return; @@ -1430,6 +1459,7 @@ Place standby.signal file. sub set_standby_mode { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; $self->append_conf('standby.signal', ''); return; @@ -1439,6 +1469,7 @@ sub set_standby_mode sub enable_archiving { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $path = $self->archive_dir; my $name = $self->name; @@ -1472,6 +1503,7 @@ archive_command = '$copy_command' sub _update_pid { my ($self, $is_running) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $name = $self->name; # If we can open the PID file, read its first line and that's the PID we @@ -1639,6 +1671,7 @@ sub new sub _set_pg_version { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; my $inst = $self->{_install_path}; my $pg_config = "pg_config"; @@ -1759,6 +1792,7 @@ sub _get_env sub installed_command { my ($self, $cmd) = @_; + die "Too many arguments for subroutine" if @_ > 2; # Nodes using alternate installation locations use their installation's # bin/ directory explicitly @@ -1851,6 +1885,7 @@ sub get_free_port sub can_bind { my ($host, $port) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $iaddr = inet_aton($host); my $paddr = sockaddr_in($port, $iaddr); @@ -2417,6 +2452,7 @@ sub interactive_psql sub _pgbench_make_files { my ($self, $files) = @_; + die "Too many arguments for subroutine" if @_ > 2; my @file_opts; if (defined $files) @@ -2626,6 +2662,7 @@ Returns 1 if successful, 0 if timed out. sub poll_query_until { my ($self, $dbname, $query, $expected) = @_; + die "Too many arguments for subroutine" if @_ > 4; local %ENV = $self->_get_env(); @@ -2787,6 +2824,7 @@ sub issues_sql_like local $Test::Builder::Level = $Test::Builder::Level + 1; my ($self, $cmd, $expected_sql, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 4; local %ENV = $self->_get_env(); @@ -2811,6 +2849,7 @@ Returns the contents of log of the node sub log_content { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return PostgreSQL::Test::Utils::slurp_file($self->logfile); } @@ -2887,6 +2926,7 @@ Find pattern in logfile of node after offset byte. sub log_contains { my ($self, $pattern, $offset) = @_; + die "Too many arguments for subroutine" if @_ > 3; return PostgreSQL::Test::Utils::slurp_file($self->logfile, $offset) =~ m/$pattern/; @@ -2929,6 +2969,7 @@ mode must be specified. sub lsn { my ($self, $mode) = @_; + die "Too many arguments for subroutine" if @_ > 2; my %modes = ( 'insert' => 'pg_current_wal_insert_lsn()', 'flush' => 'pg_current_wal_flush_lsn()', @@ -2967,6 +3008,7 @@ Returns the path of the WAL segment written to. sub write_wal { my ($self, $tli, $lsn, $segment_size, $data) = @_; + die "Too many arguments for subroutine" if @_ > 5; # Calculate segment number and offset position in segment based on the # input LSN. @@ -2996,6 +3038,7 @@ Returns the end LSN of the record inserted, in bytes. sub emit_wal { my ($self, $size) = @_; + die "Too many arguments for subroutine" if @_ > 2; return int( $self->safe_psql( @@ -3011,6 +3054,7 @@ sub emit_wal sub _get_insert_lsn { my ($self) = @_; + die "Too many arguments for subroutine" if @_ > 1; return int( $self->safe_psql( 'postgres', "SELECT pg_current_wal_insert_lsn() - '0/0'")); @@ -3033,6 +3077,7 @@ Returns the end LSN up to which WAL has advanced, in bytes. sub advance_wal_out_of_record_splitting_zone { my ($self, $wal_block_size) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $page_threshold = $wal_block_size / 4; my $end_lsn = $self->_get_insert_lsn(); @@ -3060,6 +3105,7 @@ Returns the end LSN up to which WAL has advanced, in bytes. sub advance_wal_to_record_splitting_zone { my ($self, $wal_block_size) = @_; + die "Too many arguments for subroutine" if @_ > 2; # Size of record header. my $RECORD_HEADER_SIZE = 24; @@ -3115,6 +3161,7 @@ Returns 1 if the extension is available, 0 otherwise. sub check_extension { my ($self, $extension_name) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $result = $self->safe_psql('postgres', "SELECT count(*) > 0 FROM pg_available_extensions WHERE name = '$extension_name';" @@ -3134,6 +3181,7 @@ Poll pg_stat_activity until backend_type reaches wait_event_name. sub wait_for_event { my ($self, $backend_type, $wait_event_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; $self->poll_query_until( 'postgres', qq[ @@ -3184,6 +3232,7 @@ This is not a test. It die()s on failure. sub wait_for_catchup { my ($self, $standby_name, $mode, $target_lsn) = @_; + die "Too many arguments for subroutine" if @_ > 4; $mode = defined($mode) ? $mode : 'replay'; my %valid_modes = ('sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1); @@ -3268,6 +3317,7 @@ This is not a test. It die()s on failure. sub wait_for_replay_catchup { my ($self, $standby_name, $node) = @_; + die "Too many arguments for subroutine" if @_ > 3; $node = defined($node) ? $node : $self; $self->wait_for_catchup($standby_name, 'replay', $node->lsn('flush')); @@ -3294,6 +3344,7 @@ Note that for logical slots, restart_lsn is held down by the oldest in-progress sub wait_for_slot_catchup { my ($self, $slot_name, $mode, $target_lsn) = @_; + die "Too many arguments for subroutine" if @_ > 4; $mode = defined($mode) ? $mode : 'restart'; if (!($mode eq 'restart' || $mode eq 'confirmed_flush')) { @@ -3343,6 +3394,7 @@ This is not a test. It die()s on failure. sub wait_for_subscription_sync { my ($self, $publisher, $subname, $dbname) = @_; + die "Too many arguments for subroutine" if @_ > 4; my $name = $self->name; $dbname = defined($dbname) ? $dbname : 'postgres'; @@ -3387,6 +3439,7 @@ If successful, returns the length of the entire log file, in bytes. sub wait_for_log { my ($self, $regexp, $offset) = @_; + die "Too many arguments for subroutine" if @_ > 3; $offset = 0 unless defined $offset; my $max_attempts = 10 * $PostgreSQL::Test::Utils::timeout_default; @@ -3471,6 +3524,7 @@ either. sub slot { my ($self, $slot_name) = @_; + die "Too many arguments for subroutine" if @_ > 2; my @columns = ( 'plugin', 'slot_type', 'datoid', 'database', 'active', 'active_pid', 'xmin', 'catalog_xmin', @@ -3588,6 +3642,7 @@ page_offset had better be a multiple of the cluster's block size. sub corrupt_page_checksum { my ($self, $file, $page_offset) = @_; + die "Too many arguments for subroutine" if @_ > 3; my $pgdata = $self->data_dir; my $pageheader; @@ -3616,6 +3671,7 @@ the standby. sub log_standby_snapshot { my ($self, $standby, $slot_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; # Once the slot's restart_lsn is determined, the standby looks for # xl_running_xacts WAL record from the restart_lsn onwards. First wait @@ -3645,6 +3701,7 @@ Create logical replication slot on given standby sub create_logical_slot_on_standby { my ($self, $primary, $slot_name, $dbname) = @_; + die "Too many arguments for subroutine" if @_ > 4; my ($stdout, $stderr); my $handle; @@ -3684,6 +3741,7 @@ time and return it. sub validate_slot_inactive_since { my ($self, $slot_name, $reference_time) = @_; + die "Too many arguments for subroutine" if @_ > 3; my $name = $self->name; my $inactive_since = $self->safe_psql( @@ -3716,6 +3774,7 @@ Advance WAL of node by given number of segments. sub advance_wal { my ($self, $num) = @_; + die "Too many arguments for subroutine" if @_ > 2; # Advance by $n segments (= (wal_segment_size * $num) bytes). # pg_switch_wal() forces a WAL flush, making pg_logical_emit_message() diff --git a/src/test/perl/PostgreSQL/Test/Utils.pm b/src/test/perl/PostgreSQL/Test/Utils.pm index efe0321..cbb0a21 100644 --- a/src/test/perl/PostgreSQL/Test/Utils.pm +++ b/src/test/perl/PostgreSQL/Test/Utils.pm @@ -290,6 +290,7 @@ Otherwise the template is C<tmp_test_XXXX>. sub tempdir { my ($prefix) = @_; + die "Too many arguments for subroutine" if @_ > 1; $prefix = "tmp_test" unless defined $prefix; return File::Temp::tempdir( $prefix . '_XXXX', @@ -418,6 +419,7 @@ The return value is C<($stdout, $stderr)>. sub run_command { my ($cmd) = @_; + die "Too many arguments for subroutine" if @_ > 1; my ($stdout, $stderr); my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; chomp($stdout); @@ -436,6 +438,7 @@ Pump until string is matched on the specified stream, or timeout occurs. sub pump_until { my ($proc, $timeout, $stream, $until) = @_; + die "Too many arguments for subroutine" if @_ > 4; $proc->pump_nb(); while (1) { @@ -470,6 +473,7 @@ Generate a string made of the given range of ASCII characters. sub generate_ascii_string { my ($from_char, $to_char) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $res; for my $i ($from_char .. $to_char) @@ -490,6 +494,7 @@ Return the complete list of entries in the specified directory. sub slurp_dir { my ($dir) = @_; + die "Too many arguments for subroutine" if @_ > 1; opendir(my $dh, $dir) or croak "could not opendir \"$dir\": $!"; my @direntries = readdir $dh; @@ -509,6 +514,7 @@ offset position if specified. sub slurp_file { my ($filename, $offset) = @_; + die "Too many arguments for subroutine" if @_ > 2; local $/; my $contents; my $fh; @@ -553,6 +559,7 @@ end of file.) sub append_to_file { my ($filename, $str) = @_; + die "Too many arguments for subroutine" if @_ > 2; open my $fh, ">>", $filename or croak "could not write \"$filename\": $!"; print $fh $str; @@ -571,6 +578,7 @@ Find and replace string of a given file. sub string_replace_file { my ($filename, $find, $replace) = @_; + die "Too many arguments for subroutine" if @_ > 3; open(my $in, '<', $filename) or croak $!; my $content = ''; while (<$in>) @@ -598,6 +606,7 @@ ignoring files in C<ignore_list> (basename only). sub check_mode_recursive { my ($dir, $expected_dir_mode, $expected_file_mode, $ignore_list) = @_; + die "Too many arguments for subroutine" if @_ > 4; # Result defaults to true my $result = 1; @@ -688,6 +697,7 @@ C<chmod> recursively each file and directory within the given directory. sub chmod_recursive { my ($dir, $dir_mode, $file_mode) = @_; + die "Too many arguments for subroutine" if @_ > 3; find( { @@ -721,6 +731,7 @@ retrieve specific value patterns from the installation's header files. sub scan_server_header { my ($header_path, $regexp) = @_; + die "Too many arguments for subroutine" if @_ > 2; my ($stdout, $stderr); my $result = IPC::Run::run [ 'pg_config', '--includedir-server' ], '>', @@ -760,6 +771,7 @@ within the installation's C<pg_config.h>. sub check_pg_config { my ($regexp) = @_; + die "Too many arguments for subroutine" if @_ > 1; my ($stdout, $stderr); my $result = IPC::Run::run [ 'pg_config', '--includedir' ], '>', \$stdout, '2>', \$stderr @@ -787,6 +799,7 @@ function, passed down as-is to File::Compare::compare_text. sub compare_files { my ($file1, $file2, $testname, $line_comp_function) = @_; + die "Too many arguments for subroutine" if @_ > 4; # If nothing is given, all lines should be equal. $line_comp_function = sub { $_[0] ne $_[1] } @@ -862,6 +875,7 @@ sub command_ok { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $result = run_log($cmd); ok($result, $test_name); return; @@ -879,6 +893,7 @@ sub command_fails { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 2; my $result = run_log($cmd); ok(!$result, $test_name); return; @@ -896,6 +911,7 @@ sub command_exit_is { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $expected, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; print("# Running: " . join(" ", @{$cmd}) . "\n"); my $h = IPC::Run::start $cmd; $h->finish(); @@ -923,6 +939,7 @@ sub program_help_ok { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd) = @_; + die "Too many arguments for subroutine" if @_ > 1; my ($stdout, $stderr); print("# Running: $cmd --help\n"); my $result = IPC::Run::run [ $cmd, '--help' ], '>', \$stdout, '2>', @@ -954,6 +971,7 @@ sub program_version_ok { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd) = @_; + die "Too many arguments for subroutine" if @_ > 1; my ($stdout, $stderr); print("# Running: $cmd --version\n"); my $result = IPC::Run::run [ $cmd, '--version' ], '>', \$stdout, '2>', @@ -977,6 +995,7 @@ sub program_options_handling_ok { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd) = @_; + die "Too many arguments for subroutine" if @_ > 1; my ($stdout, $stderr); print("# Running: $cmd --not-a-valid-option\n"); my $result = IPC::Run::run [ $cmd, '--not-a-valid-option' ], '>', @@ -1000,6 +1019,7 @@ sub command_like { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $expected_stdout, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; my ($stdout, $stderr); print("# Running: " . join(" ", @{$cmd}) . "\n"); my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; @@ -1027,6 +1047,7 @@ sub command_like_safe # which can fail, causing the process to hang, notably on Msys # when used with 'pg_ctl start' my ($cmd, $expected_stdout, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; my ($stdout, $stderr); my $stdoutfile = File::Temp->new(); my $stderrfile = File::Temp->new(); @@ -1053,6 +1074,7 @@ sub command_fails_like { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $expected_stderr, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 3; my ($stdout, $stderr); print("# Running: " . join(" ", @{$cmd}) . "\n"); my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; @@ -1089,6 +1111,7 @@ sub command_checks_all local $Test::Builder::Level = $Test::Builder::Level + 1; my ($cmd, $expected_ret, $out, $err, $test_name) = @_; + die "Too many arguments for subroutine" if @_ > 5; # run command my ($stdout, $stderr); -- 1.8.3.1 ^ permalink raw reply [nested|flat] 6+ messages in thread
* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance @ 2026-05-29 09:31 Yugo Nagata <[email protected]> 0 siblings, 0 replies; 6+ messages in thread From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw) --- .../isolation/expected/ivm-create-insert.out | 285 ++++++++ .../isolation/expected/ivm-create-insert2.out | 305 ++++++++ .../isolation/expected/ivm-create-insert3.out | 305 ++++++++ .../isolation/expected/ivm-insert-insert.out | 497 +++++++++++++ .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++ .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++ .../isolation/expected/ivm-refresh-insert.out | 213 ++++++ .../expected/ivm-refresh-insert2.out | 191 +++++ .../expected/ivm-refresh-insert3.out | 191 +++++ src/test/isolation/isolation_schedule | 9 + .../isolation/specs/ivm-create-insert.spec | 47 ++ .../isolation/specs/ivm-create-insert2.spec | 54 ++ .../isolation/specs/ivm-create-insert3.spec | 54 ++ .../isolation/specs/ivm-insert-insert.spec | 62 ++ .../isolation/specs/ivm-insert-insert2.spec | 62 ++ .../isolation/specs/ivm-insert-insert3.spec | 62 ++ .../isolation/specs/ivm-refresh-insert.spec | 46 ++ .../isolation/specs/ivm-refresh-insert2.spec | 46 ++ .../isolation/specs/ivm-refresh-insert3.spec | 46 ++ .../regress/expected/incremental_matview.out | 667 ++++++++++++++++++ src/test/regress/parallel_schedule | 1 + src/test/regress/sql/incremental_matview.sql | 407 +++++++++++ 22 files changed, 4296 insertions(+) create mode 100644 src/test/isolation/expected/ivm-create-insert.out create mode 100644 src/test/isolation/expected/ivm-create-insert2.out create mode 100644 src/test/isolation/expected/ivm-create-insert3.out create mode 100644 src/test/isolation/expected/ivm-insert-insert.out create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out create mode 100644 src/test/isolation/specs/ivm-create-insert.spec create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec create mode 100644 src/test/regress/expected/incremental_matview.out create mode 100644 src/test/regress/sql/incremental_matview.sql diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out new file mode 100644 index 00000000000..5da00043aba --- /dev/null +++ b/src/test/isolation/expected/ivm-create-insert.out @@ -0,0 +1,285 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 create s2 insert c1 check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 create s2 c1 insert check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 create insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert create c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 create c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 create c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 c2 create check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert c2 create check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out new file mode 100644 index 00000000000..907d892c6d4 --- /dev/null +++ b/src/test/isolation/expected/ivm-create-insert2.out @@ -0,0 +1,305 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 create s2 insert c1 check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 create s2 c1 insert check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 create insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert create c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s1 s2 create c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 create c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s2 insert s1 c2 create check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s2 s1 insert c2 create check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out new file mode 100644 index 00000000000..907d892c6d4 --- /dev/null +++ b/src/test/isolation/expected/ivm-create-insert3.out @@ -0,0 +1,305 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 create s2 insert c1 check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 create s2 c1 insert check2 c2 mv +step s1: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 create insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert create c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s1 s2 create c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 create c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + <waiting ...> +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s2 insert s1 c2 create check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + + +starting permutation: s2 s1 insert c2 create check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +tx1: NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the materialized view for efficient incremental maintenance. +tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ +DETAIL: The view may not include effects of a concurrent transaction. +HINT: The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent. +step create: + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; + +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ng +(1 row) + diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out new file mode 100644 index 00000000000..5ca4cfea677 --- /dev/null +++ b/src/test/isolation/expected/ivm-insert-insert.out @@ -0,0 +1,497 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 update1 s2 update2 c1 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...> +step c1: COMMIT; +step update2: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 update1 s2 c1 update2 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 update2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...> +step c1: COMMIT; +step update2: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update2 update1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...> +step c2: COMMIT; +step update1: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 c1 update2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 update1 c2 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...> +step c2: COMMIT; +step update1: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 c2 update1 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 update2 c2 update1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...> +step c1: COMMIT; +step insert2: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...> +step c1: COMMIT; +step insert2: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...> +step c2: COMMIT; +step insert1: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...> +step c2: COMMIT; +step insert1: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +20|20|200 +20|20|201 +20|21|200 +20|21|201 +21|20|200 +21|20|201 +21|21|200 +21|21|201 +(12 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out new file mode 100644 index 00000000000..e1c66d4de5e --- /dev/null +++ b/src/test/isolation/expected/ivm-insert-insert2.out @@ -0,0 +1,373 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 update1 s2 update2 c1 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 update1 s2 c1 update2 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 update2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update2 update1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 c1 update2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 update1 c2 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 c2 update1 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 update2 c2 update1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out new file mode 100644 index 00000000000..e1c66d4de5e --- /dev/null +++ b/src/test/isolation/expected/ivm-insert-insert3.out @@ -0,0 +1,373 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 update1 s2 update2 c1 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 update1 s2 c1 update2 check2 c2 mv +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step s2: SELECT; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 update2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update2 update1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 update1 c1 update2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +step c1: COMMIT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +11|11|100 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 update1 c2 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 update2 s1 c2 update1 check1 c1 mv +step s2: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step s1: SELECT; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 update2 c2 update1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step update2: UPDATE b SET j = 111 WHERE i = 1; +step c2: COMMIT; +step update1: UPDATE a SET j = 11 WHERE i = 1; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|111 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step s2: SELECT; +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +step c1: COMMIT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +20|20|200 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c2: COMMIT; +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv +step s2: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step s1: SELECT; +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); +step c2: COMMIT; +step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); + x| y| z +--+--+--- +10|10|100 +10|11|100 +11|10|100 +11|11|100 +21|21|201 +(5 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out new file mode 100644 index 00000000000..a925938bf1c --- /dev/null +++ b/src/test/isolation/expected/ivm-refresh-insert.out @@ -0,0 +1,213 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 refresh s2 insert c1 check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 refresh s2 c1 insert check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step insert: INSERT INTO a VALUES (2); <waiting ...> +step c1: COMMIT; +step insert: <... completed> +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert refresh c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 refresh c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 c2 refresh check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert c2 refresh check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step check1: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out new file mode 100644 index 00000000000..dc1b16ae34e --- /dev/null +++ b/src/test/isolation/expected/ivm-refresh-insert2.out @@ -0,0 +1,191 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 refresh s2 insert c1 check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 refresh s2 c1 insert check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step insert: INSERT INTO a VALUES (2); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert refresh c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 refresh c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 c2 refresh check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert c2 refresh check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out new file mode 100644 index 00000000000..dc1b16ae34e --- /dev/null +++ b/src/test/isolation/expected/ivm-refresh-insert3.out @@ -0,0 +1,191 @@ +Parsed test spec with 2 sessions + +starting permutation: s1 refresh s2 insert c1 check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 refresh s2 c1 insert check2 c2 mv +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step s2: SELECT; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh insert c1 check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step insert: INSERT INTO a VALUES (2); +ERROR: could not obtain lock on materialized view "mv" during incremental maintenance +step c1: COMMIT; +step check2: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +(1 row) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 insert refresh c2 check1 c1 mv +step s1: SELECT; +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s1 s2 refresh c1 insert check2 c2 mv +step s1: SELECT; +step s2: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; +step c1: COMMIT; +step insert: INSERT INTO a VALUES (2); +step check2: SELECT check_mv(); +check_mv +-------- +ok +(1 row) + +step c2: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 refresh c2 check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...> +step c2: COMMIT; +step refresh: <... completed> +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 insert s1 c2 refresh check1 c1 mv +step s2: SELECT; +step insert: INSERT INTO a VALUES (2); +step s1: SELECT; +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + + +starting permutation: s2 s1 insert c2 refresh check1 c1 mv +step s2: SELECT; +step s1: SELECT; +step insert: INSERT INTO a VALUES (2); +step c2: COMMIT; +step refresh: REFRESH MATERIALIZED VIEW mv; +ERROR: the materialized view is incrementally updated in concurrent transaction +step check1: SELECT check_mv(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +step c1: COMMIT; +step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); +x|y +-+- +1|1 +2|2 +(2 rows) + +check_mv +-------- +ok +(1 row) + diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index b8ebe92553c..6b7e873b370 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -128,3 +128,12 @@ test: matview-write-skew test: lock-nowait test: for-portion-of test: ddl-dependency-locking +test: ivm-create-insert +test: ivm-create-insert2 +test: ivm-create-insert3 +test: ivm-insert-insert +test: ivm-insert-insert2 +test: ivm-insert-insert3 +test: ivm-refresh-insert +test: ivm-refresh-insert2 +test: ivm-refresh-insert3 diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec new file mode 100644 index 00000000000..ccd6fd080a9 --- /dev/null +++ b/src/test/isolation/specs/ivm-create-insert.spec @@ -0,0 +1,47 @@ +# Test interaction between concurrent transactions performing +# create and insert in READ COMMITTED isolation level + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s1 { SELECT; } +step create { + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 { SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 create s2 insert c1 check2 c2 mv +permutation s1 create s2 c1 insert check2 c2 mv +permutation s1 s2 create insert c1 check2 c2 mv +permutation s1 s2 insert create c2 check1 c1 mv +permutation s1 s2 create c1 insert check2 c2 mv +permutation s2 insert s1 create c2 check1 c1 mv +permutation s2 insert s1 c2 create check1 c1 mv +permutation s2 s1 insert c2 create check1 c1 mv diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec new file mode 100644 index 00000000000..02cec85ae07 --- /dev/null +++ b/src/test/isolation/specs/ivm-create-insert2.spec @@ -0,0 +1,54 @@ +# Test interaction between concurrent transactions performing +# create and insert in REPEATABLE READ isolation level +# +# Note: +# In this isolation level, it is possible that create_immv could +# create an inconsistent view not including effects of a concurrent +# transaction. So, an warning message is raised to suggest using it +# in READ COMMITTED or executing refresh_immv to make sure to +# make the view contents consistent. + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s1 { SELECT; } +step create { + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 {SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 create s2 insert c1 check2 c2 mv +permutation s1 create s2 c1 insert check2 c2 mv +permutation s1 s2 create insert c1 check2 c2 mv +permutation s1 s2 insert create c2 check1 c1 mv +permutation s1 s2 create c1 insert check2 c2 mv +permutation s2 insert s1 create c2 check1 c1 mv +permutation s2 insert s1 c2 create check1 c1 mv +permutation s2 s1 insert c2 create check1 c1 mv diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec new file mode 100644 index 00000000000..19ce03185a4 --- /dev/null +++ b/src/test/isolation/specs/ivm-create-insert3.spec @@ -0,0 +1,54 @@ +# Test interaction between concurrent transactions performing +# create and insert in SERIALIZABLE isolation level +# +# Note: +# In this isolation level, it is possible that create_immv could +# create an inconsistent view not including effects of a concurrent +# transaction. So, an warning message is raised to suggest using it +# in READ COMMITTED or executing refresh_immv to make sure to +# make the view contents consistent. + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s1 { SELECT; } +step create { + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 {SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 create s2 insert c1 check2 c2 mv +permutation s1 create s2 c1 insert check2 c2 mv +permutation s1 s2 create insert c1 check2 c2 mv +permutation s1 s2 insert create c2 check1 c1 mv +permutation s1 s2 create c1 insert check2 c2 mv +permutation s2 insert s1 create c2 check1 c1 mv +permutation s2 insert s1 c2 create check1 c1 mv +permutation s2 s1 insert c2 create check1 c1 mv diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec new file mode 100644 index 00000000000..b8f794ca191 --- /dev/null +++ b/src/test/isolation/specs/ivm-insert-insert.spec @@ -0,0 +1,62 @@ +# Test interaction between concurrent transactions performing +# table modifications in READ COMMITTED isolation level + +setup +{ + CREATE TABLE a (i int, j int); + CREATE TABLE b (i int, j int); + INSERT INTO a VALUES (1,10); + INSERT INTO b VALUES (1,100); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE VIEW v(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; + DROP TABLE b; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s1 { SELECT; } +step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); } +step update1 { UPDATE a SET j = 11 WHERE i = 1; } +step check1 { SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s2 { SELECT; } +step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); } +step update2 { UPDATE b SET j = 111 WHERE i = 1; } +step check2 { SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 update1 s2 update2 c1 check2 c2 mv +permutation s1 update1 s2 c1 update2 check2 c2 mv +permutation s1 s2 update1 update2 c1 check2 c2 mv +permutation s1 s2 update2 update1 c2 check1 c1 mv +permutation s1 s2 update1 c1 update2 check2 c2 mv +permutation s2 update2 s1 update1 c2 check1 c1 mv +permutation s2 update2 s1 c2 update1 check1 c1 mv +permutation s2 s1 update2 c2 update1 check1 c1 mv + +permutation s1 insert1 s2 insert2 c1 check2 c2 mv +permutation s1 insert1 s2 c1 insert2 check2 c2 mv +permutation s1 s2 insert1 insert2 c1 check2 c2 mv +permutation s1 s2 insert2 insert1 c2 check1 c1 mv +permutation s1 s2 insert1 c1 insert2 check2 c2 mv +permutation s2 insert2 s1 insert1 c2 check1 c1 mv +permutation s2 insert2 s1 c2 insert1 check1 c1 mv +permutation s2 s1 insert2 c2 insert1 check1 c1 mv diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec new file mode 100644 index 00000000000..ed086d1ba1e --- /dev/null +++ b/src/test/isolation/specs/ivm-insert-insert2.spec @@ -0,0 +1,62 @@ +# Test interaction between concurrent transactions performing +# table modifications in REPEATABLE READ isolation level + +setup +{ + CREATE TABLE a (i int, j int); + CREATE TABLE b (i int, j int); + INSERT INTO a VALUES (1,10); + INSERT INTO b VALUES (1,100); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE VIEW v(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; + DROP TABLE b; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s1 { SELECT; } +step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); } +step update1 { UPDATE a SET j = 11 WHERE i = 1; } +step check1 { SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s2 { SELECT; } +step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); } +step update2 { UPDATE b SET j = 111 WHERE i = 1; } +step check2 { SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 update1 s2 update2 c1 check2 c2 mv +permutation s1 update1 s2 c1 update2 check2 c2 mv +permutation s1 s2 update1 update2 c1 check2 c2 mv +permutation s1 s2 update2 update1 c2 check1 c1 mv +permutation s1 s2 update1 c1 update2 check2 c2 mv +permutation s2 update2 s1 update1 c2 check1 c1 mv +permutation s2 update2 s1 c2 update1 check1 c1 mv +permutation s2 s1 update2 c2 update1 check1 c1 mv + +permutation s1 insert1 s2 insert2 c1 check2 c2 mv +permutation s1 insert1 s2 c1 insert2 check2 c2 mv +permutation s1 s2 insert1 insert2 c1 check2 c2 mv +permutation s1 s2 insert2 insert1 c2 check1 c1 mv +permutation s1 s2 insert1 c1 insert2 check2 c2 mv +permutation s2 insert2 s1 insert1 c2 check1 c1 mv +permutation s2 insert2 s1 c2 insert1 check1 c1 mv +permutation s2 s1 insert2 c2 insert1 check1 c1 mv diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec new file mode 100644 index 00000000000..b18bd121033 --- /dev/null +++ b/src/test/isolation/specs/ivm-insert-insert3.spec @@ -0,0 +1,62 @@ +# Test interaction between concurrent transactions performing +# table modifications in SERIALIZABLE isolation level + +setup +{ + CREATE TABLE a (i int, j int); + CREATE TABLE b (i int, j int); + INSERT INTO a VALUES (1,10); + INSERT INTO b VALUES (1,100); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE VIEW v(x,y,z) AS + SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; + DROP TABLE b; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s1 { SELECT; } +step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); } +step update1 { UPDATE a SET j = 11 WHERE i = 1; } +step check1 { SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s2 { SELECT; } +step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); } +step update2 { UPDATE b SET j = 111 WHERE i = 1; } +step check2 { SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 update1 s2 update2 c1 check2 c2 mv +permutation s1 update1 s2 c1 update2 check2 c2 mv +permutation s1 s2 update1 update2 c1 check2 c2 mv +permutation s1 s2 update2 update1 c2 check1 c1 mv +permutation s1 s2 update1 c1 update2 check2 c2 mv +permutation s2 update2 s1 update1 c2 check1 c1 mv +permutation s2 update2 s1 c2 update1 check1 c1 mv +permutation s2 s1 update2 c2 update1 check1 c1 mv + +permutation s1 insert1 s2 insert2 c1 check2 c2 mv +permutation s1 insert1 s2 c1 insert2 check2 c2 mv +permutation s1 s2 insert1 insert2 c1 check2 c2 mv +permutation s1 s2 insert2 insert1 c2 check1 c1 mv +permutation s1 s2 insert1 c1 insert2 check2 c2 mv +permutation s2 insert2 s1 insert1 c2 check1 c1 mv +permutation s2 insert2 s1 c2 insert1 check1 c1 mv +permutation s2 s1 insert2 c2 insert1 check1 c1 mv diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec new file mode 100644 index 00000000000..d7181251962 --- /dev/null +++ b/src/test/isolation/specs/ivm-refresh-insert.spec @@ -0,0 +1,46 @@ +# Test interaction between concurrent transactions performing +# refresh and insert in READ COMMITTED isolation level + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s1 { SELECT; } +step refresh { REFRESH MATERIALIZED VIEW mv; } +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 {SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 refresh s2 insert c1 check2 c2 mv +permutation s1 refresh s2 c1 insert check2 c2 mv +permutation s1 s2 refresh insert c1 check2 c2 mv +permutation s1 s2 insert refresh c2 check1 c1 mv +permutation s1 s2 refresh c1 insert check2 c2 mv +permutation s2 insert s1 refresh c2 check1 c1 mv +permutation s2 insert s1 c2 refresh check1 c1 mv +permutation s2 s1 insert c2 refresh check1 c1 mv diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec new file mode 100644 index 00000000000..f2d1d5013f2 --- /dev/null +++ b/src/test/isolation/specs/ivm-refresh-insert2.spec @@ -0,0 +1,46 @@ +# Test interaction between concurrent transactions performing +# refresh and insert in REPEATABLE READ isolation level + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s1 { SELECT; } +step refresh { REFRESH MATERIALIZED VIEW mv; } +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 {SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 refresh s2 insert c1 check2 c2 mv +permutation s1 refresh s2 c1 insert check2 c2 mv +permutation s1 s2 refresh insert c1 check2 c2 mv +permutation s1 s2 insert refresh c2 check1 c1 mv +permutation s1 s2 refresh c1 insert check2 c2 mv +permutation s2 insert s1 refresh c2 check1 c1 mv +permutation s2 insert s1 c2 refresh check1 c1 mv +permutation s2 s1 insert c2 refresh check1 c1 mv diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec new file mode 100644 index 00000000000..0ec2b1d1de0 --- /dev/null +++ b/src/test/isolation/specs/ivm-refresh-insert3.spec @@ -0,0 +1,46 @@ +# Test interaction between concurrent transactions performing +# refresh and insert in SERIALIZABLE isolation level + +setup +{ + CREATE TABLE a (i int); + INSERT INTO a VALUES (1); + CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i; + CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i; + CREATE FUNCTION check_mv() RETURNS text AS + $$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END + FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL + (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql; +} + +teardown +{ + DROP FUNCTION check_mv(); + DROP MATERIALIZED VIEW mv; + DROP VIEW v; + DROP TABLE a; +} + +session tx1 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s1 { SELECT; } +step refresh { REFRESH MATERIALIZED VIEW mv; } +step check1 {SELECT check_mv();} +step c1 { COMMIT; } +step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); } + +session tx2 +setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; } +step s2 { SELECT; } +step insert { INSERT INTO a VALUES (2); } +step check2 {SELECT check_mv(); } +step c2 { COMMIT; } + +permutation s1 refresh s2 insert c1 check2 c2 mv +permutation s1 refresh s2 c1 insert check2 c2 mv +permutation s1 s2 refresh insert c1 check2 c2 mv +permutation s1 s2 insert refresh c2 check1 c1 mv +permutation s1 s2 refresh c1 insert check2 c2 mv +permutation s2 insert s1 refresh c2 check1 c1 mv +permutation s2 insert s1 c2 refresh check1 c1 mv +permutation s2 s1 insert c2 refresh check1 c1 mv diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out new file mode 100644 index 00000000000..c7fd19fdca3 --- /dev/null +++ b/src/test/regress/expected/incremental_matview.out @@ -0,0 +1,667 @@ +-- create a table to use as a basis for views and materialized views in various combinations +CREATE TABLE mv_base_a (x int, i int, y int, j int); +CREATE TABLE mv_base_b (x int, i int, y int, k int); +-- test for base tables with dropped columns +ALTER TABLE mv_base_a DROP COLUMN x; +ALTER TABLE mv_base_a DROP COLUMN y; +ALTER TABLE mv_base_b DROP COLUMN x; +ALTER TABLE mv_base_b DROP COLUMN y; +INSERT INTO mv_base_a VALUES + (1,10), + (2,20), + (3,30), + (4,40), + (5,50); +INSERT INTO mv_base_b VALUES + (1,101), + (2,102), + (3,103), + (4,104); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +ERROR: materialized view "mv_ivm_1" has not been populated +HINT: Use the REFRESH MATERIALIZED VIEW command. +REFRESH MATERIALIZED VIEW mv_ivm_1; +NOTICE: could not create an index on materialized view "mv_ivm_1" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 10 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 +(4 rows) + +-- REFRESH WITH NO DATA +BEGIN; +CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$ + BEGIN + RETURN NULL; + END +$$ language plpgsql; +CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT +ON mv_base_a FROM mv_ivm_1 FOR EACH ROW +EXECUTE PROCEDURE dummy_ivm_trigger_func(); +SELECT COUNT(*) +FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid +WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass; + count +------- + 17 +(1 row) + +REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA; +SELECT COUNT(*) +FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid +WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass; + count +------- + 1 +(1 row) + +ROLLBACK; +-- immediate maintenance +BEGIN; +INSERT INTO mv_base_b VALUES(5,105); +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 10 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 + 5 | 50 | 105 +(5 rows) + +UPDATE mv_base_a SET j = 0 WHERE i = 1; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 0 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 + 5 | 50 | 105 +(5 rows) + +DELETE FROM mv_base_b WHERE (i,k) = (5,105); +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 0 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 +(4 rows) + +ROLLBACK; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 10 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 +(4 rows) + +-- DISTINCT not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a; +ERROR: DISTINCT is not supported on incrementally maintainable materialized view +-- test for renaming column name to camel style +BEGIN; +ALTER TABLE mv_base_a RENAME i TO "I"; +ALTER TABLE mv_base_a RENAME j TO "J"; +UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + i | j | k +---+----+----- + 1 | 0 | 101 + 2 | 20 | 102 + 3 | 30 | 103 + 4 | 40 | 104 +(4 rows) + +ROLLBACK; +-- TRUNCATE a base table in join views +BEGIN; +TRUNCATE mv_base_a; +SELECT * FROM mv_ivm_1; + i | j | k +---+---+--- +(0 rows) + +ROLLBACK; +BEGIN; +TRUNCATE mv_base_b; +SELECT * FROM mv_ivm_1; + i | j | k +---+---+--- +(0 rows) + +ROLLBACK; +-- some query syntax +BEGIN; +CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql' + AS 'SELECT 1' IMMUTABLE; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func(); +NOTICE: could not create an index on materialized view "mv_ivm_func" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1; +NOTICE: could not create an index on materialized view "mv_ivm_no_tbl" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +ROLLBACK; +-- result of materialized view have duplicate result. +BEGIN; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a; +NOTICE: could not create an index on materialized view "mv_ivm_duplicate" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +INSERT INTO mv_base_a VALUES(6,20); +SELECT * FROM mv_ivm_duplicate ORDER BY 1; + j +---- + 10 + 20 + 20 + 30 + 40 + 50 +(6 rows) + +DELETE FROM mv_base_a WHERE (i,j) = (2,20); +SELECT * FROM mv_ivm_duplicate ORDER BY 1; + j +---- + 10 + 20 + 30 + 40 + 50 +(5 rows) + +ROLLBACK; +-- aggregate not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i; +ERROR: aggregate function is not supported on incrementally maintainable materialized view +-- support self join view and multiple change on the same table +BEGIN; +CREATE TABLE base_t (i int, v int); +INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30); +CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS + SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i; +NOTICE: could not create an index on materialized view "mv_self" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT * FROM mv_self ORDER BY v1; + v1 | v2 +----+---- + 10 | 10 + 20 | 20 + 30 | 30 +(3 rows) + +INSERT INTO base_t VALUES (4,40); +DELETE FROM base_t WHERE i = 1; +UPDATE base_t SET v = v*10 WHERE i=2; +SELECT * FROM mv_self ORDER BY v1; + v1 | v2 +-----+----- + 30 | 30 + 40 | 40 + 200 | 200 +(3 rows) + +WITH + ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1), + ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1), + upd_t AS (UPDATE base_t SET v = v + 100 RETURNING 1), + dlt_t AS (DELETE FROM base_t WHERE i IN (4,5) RETURNING 1) +SELECT NULL; + ?column? +---------- + +(1 row) + +SELECT * FROM mv_self ORDER BY v1; + v1 | v2 +-----+----- + 50 | 50 + 60 | 60 + 130 | 130 + 300 | 300 +(4 rows) + +--- with sub-transactions +SAVEPOINT p1; +INSERT INTO base_t VALUES (7,70); +RELEASE SAVEPOINT p1; +INSERT INTO base_t VALUES (7,77); +SELECT * FROM mv_self ORDER BY v1, v2; + v1 | v2 +-----+----- + 50 | 50 + 60 | 60 + 70 | 70 + 70 | 77 + 77 | 70 + 77 | 77 + 130 | 130 + 300 | 300 +(8 rows) + +ROLLBACK; +-- support simultaneous table changes +BEGIN; +CREATE TABLE base_r (i int, v int); +CREATE TABLE base_s (i int, v int); +INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30); +INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300); +CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS + SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i); +NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT * FROM mv ORDER BY v1; + v1 | v2 +----+----- + 10 | 100 + 20 | 200 + 30 | 300 +(3 rows) + +WITH + ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1), + ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1), + ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1), + upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1), + dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1) +SELECT NULL; + ?column? +---------- + +(1 row) + +SELECT * FROM mv ORDER BY v1; + v1 | v2 +------+----- + 10 | 100 + 11 | 100 + 1020 | 200 + 1020 | 222 +(4 rows) + +ROLLBACK; +-- support foreign reference constraints +BEGIN; +CREATE TABLE ri1 (i int PRIMARY KEY); +CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int); +INSERT INTO ri1 VALUES (1),(2),(3); +INSERT INTO ri2 VALUES (1),(2),(3); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS + SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i); +NOTICE: created index "mv_ri_index" on materialized view "mv_ri" +SELECT * FROM mv_ri ORDER BY i1; + i1 | i2 +----+---- + 1 | 1 + 2 | 2 + 3 | 3 +(3 rows) + +UPDATE ri1 SET i=10 where i=1; +DELETE FROM ri1 WHERE i=2; +SELECT * FROM mv_ri ORDER BY i2; + i1 | i2 +----+---- + 3 | 3 + 10 | 10 +(2 rows) + +ROLLBACK; +-- views including NULL +BEGIN; +CREATE TABLE base_t (i int, v int); +INSERT INTO base_t VALUES (1,10),(2, NULL); +CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t; +NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT * FROM mv ORDER BY i; + i | v +---+---- + 1 | 10 + 2 | +(2 rows) + +UPDATE base_t SET v = 20 WHERE i = 2; +SELECT * FROM mv ORDER BY i; + i | v +---+---- + 1 | 10 + 2 | 20 +(2 rows) + +ROLLBACK; +BEGIN; +CREATE TABLE base_t (i int); +CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t; +NOTICE: could not create an index on materialized view "mv" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT * FROM mv ORDER BY i; + i +--- +(0 rows) + +INSERT INTO base_t VALUES (1),(NULL); +SELECT * FROM mv ORDER BY i; + i +--- + 1 + +(2 rows) + +ROLLBACK; +-- IMMV containing user defined type +BEGIN; +CREATE TYPE mytype; +CREATE FUNCTION mytype_in(cstring) + RETURNS mytype AS 'int4in' + LANGUAGE INTERNAL STRICT IMMUTABLE; +NOTICE: return type mytype is only a shell +CREATE FUNCTION mytype_out(mytype) + RETURNS cstring AS 'int4out' + LANGUAGE INTERNAL STRICT IMMUTABLE; +NOTICE: argument type mytype is only a shell +LINE 1: CREATE FUNCTION mytype_out(mytype) + ^ +CREATE TYPE mytype ( + LIKE = int4, + INPUT = mytype_in, + OUTPUT = mytype_out +); +CREATE FUNCTION mytype_eq(mytype, mytype) + RETURNS bool AS 'int4eq' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE FUNCTION mytype_lt(mytype, mytype) + RETURNS bool AS 'int4lt' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE FUNCTION mytype_cmp(mytype, mytype) + RETURNS integer AS 'btint4cmp' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE OPERATOR = ( + leftarg = mytype, rightarg = mytype, + procedure = mytype_eq); +CREATE OPERATOR < ( + leftarg = mytype, rightarg = mytype, + procedure = mytype_lt); +CREATE OPERATOR CLASS mytype_ops + DEFAULT FOR TYPE mytype USING btree AS + OPERATOR 1 <, + OPERATOR 3 = , + FUNCTION 1 mytype_cmp(mytype,mytype); +CREATE TABLE t_mytype (x mytype); +CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS + SELECT * FROM t_mytype; +NOTICE: could not create an index on materialized view "mv_mytype" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +INSERT INTO t_mytype VALUES ('1'::mytype); +SELECT * FROM mv_mytype; + x +--- + 1 +(1 row) + +ROLLBACK; +-- outer join is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i; +ERROR: OUTER JOIN is not supported on incrementally maintainable materialized view +-- CTE is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv AS + WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i; +ERROR: CTE is not supported on incrementally maintainable materialized view +-- contain system column +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a; +ERROR: system column is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610'; +ERROR: system column is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a; +ERROR: system column is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a; +ERROR: system column is not supported on incrementally maintainable materialized view +-- contain subquery +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 ); +ERROR: subquery is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i; +ERROR: subquery is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a; +ERROR: subquery is not supported on incrementally maintainable materialized view +-- contain ORDER BY +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k; +ERROR: ORDER BY clause is not supported on incrementally maintainable materialized view +-- contain HAVING +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5; +ERROR: HAVING clause is not supported on incrementally maintainable materialized view +-- contain view or materialized view +CREATE VIEW b_view AS SELECT i,k FROM mv_base_b; +CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i; +ERROR: VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i; +ERROR: VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i; +ERROR: subquery is not supported on incrementally maintainable materialized view +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5; +ERROR: subquery is not supported on incrementally maintainable materialized view +-- contain mutable functions +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int; +ERROR: mutable function is not supported on incrementally maintainable materialized view +HINT: functions must be marked IMMUTABLE +-- LIMIT/OFFSET is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5; +ERROR: LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view +-- DISTINCT ON is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a; +ERROR: DISTINCT is not supported on incrementally maintainable materialized view +-- TABLESAMPLE clause is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50); +ERROR: TABLESAMPLE clause is not supported on incrementally maintainable materialized view +-- window functions are not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a; +ERROR: window functions are not supported on incrementally maintainable materialized view +-- inheritance parent is not supported +BEGIN; +CREATE TABLE parent (i int, v int); +CREATE TABLE child_a(options text) INHERITS(parent); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm21 AS SELECT * FROM parent; +ERROR: inheritance parent is not supported on incrementally maintainable materialized view +ROLLBACK; +-- UNION statement is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;; +ERROR: UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view +-- empty target list is not allowed with IVM +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm25 AS SELECT FROM mv_base_a; +ERROR: empty target list is not supported on incrementally maintainable materialized view +-- FOR UPDATE/SHARE is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE; +ERROR: FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view +-- tartget list cannot contain ivm column that start with '__ivm' +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a; +ERROR: column name __ivm_count__ is not supported on incrementally maintainable materialized view +-- expressions specified in GROUP BY must appear in the target list. +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i; +ERROR: aggregate function is not supported on incrementally maintainable materialized view +-- VALUES is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1); +ERROR: VALUES is not supported on incrementally maintainable materialized view +-- views containing base tables with Row Level Security +DROP USER IF EXISTS regress_ivm_admin; +NOTICE: role "regress_ivm_admin" does not exist, skipping +DROP USER IF EXISTS regress_ivm_user; +NOTICE: role "regress_ivm_user" does not exist, skipping +CREATE USER regress_ivm_admin; +CREATE USER regress_ivm_user; +--- create a table with RLS +SET SESSION AUTHORIZATION regress_ivm_admin; +CREATE TABLE rls_tbl(id int, data text, owner name); +INSERT INTO rls_tbl VALUES + (1,'foo','regress_ivm_user'), + (2,'bar','postgres'); +CREATE TABLE num_tbl(id int, num text); +INSERT INTO num_tbl VALUES + (1,'one'), + (2,'two'), + (3,'three'), + (4,'four'), + (5,'five'), + (6,'six'); +--- Users can access only their own rows +CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user); +ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY; +GRANT ALL on rls_tbl TO PUBLIC; +GRANT ALL on num_tbl TO PUBLIC; +--- create a view owned by regress_ivm_user +SET SESSION AUTHORIZATION regress_ivm_user; +CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls AS SELECT * FROM rls_tbl; +NOTICE: could not create an index on materialized view "ivm_rls" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; + id | data | owner +----+------+------------------ + 1 | foo | regress_ivm_user +(1 row) + +RESET SESSION AUTHORIZATION; +--- inserts rows owned by different users +INSERT INTO rls_tbl VALUES + (3,'baz','regress_ivm_user'), + (4,'qux','postgres'); +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; + id | data | owner +----+------+------------------ + 1 | foo | regress_ivm_user + 3 | baz | regress_ivm_user +(2 rows) + +--- combination of diffent kinds of commands +WITH + i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')), + u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1), + u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2) +SELECT; +-- +(1 row) + +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; + id | data | owner +----+-------+------------------ + 2 | bar | regress_ivm_user + 3 | baz | regress_ivm_user + 6 | corge | regress_ivm_user +(3 rows) + +--- +SET SESSION AUTHORIZATION regress_ivm_user; +CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id); +NOTICE: could not create an index on materialized view "ivm_rls2" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +RESET SESSION AUTHORIZATION; +WITH + x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)), + y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4)) +SELECT; +-- +(1 row) + +SELECT * FROM ivm_rls2 ORDER BY 1,2,3; + id | data | owner | num +----+-------+------------------+--------- + 2 | bar | regress_ivm_user | two + 3 | baz_2 | regress_ivm_user | three_2 + 6 | corge | regress_ivm_user | six +(3 rows) + +-- trigger updating the same table +BEGIN; +CREATE TABLE tbl_update_same (i int); +CREATE FUNCTION func_update_same() RETURNS TRIGGER AS + $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$ + LANGUAGE plpgsql; +CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW + EXECUTE FUNCTION func_update_same(); +CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same; +NOTICE: could not create an index on materialized view "mv_update_same" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +INSERT INTO tbl_update_same VALUES (1); +SELECT * FROM mv_update_same; + i +--- + 2 +(1 row) + +-- self-referential FKs +CREATE TABLE tbl_self_ref (a int primary key, + b int references tbl_self_ref(a) ON UPDATE CASCADE); +INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2); +CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref; +NOTICE: created index "mv_self_ref_index" on materialized view "mv_self_ref" +UPDATE tbl_self_ref set a = a + 10; +SELECT * FROM mv_self_ref ORDER BY a; + a | b +----+---- + 11 | + 12 | 11 + 13 | 12 +(3 rows) + +ROLLBACK; +-- automatic index creation +BEGIN; +CREATE TABLE base_a (i int primary key, j int); +CREATE TABLE base_b (i int primary key, j int); +--- with all pkey columns: create an index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b; +NOTICE: created index "mv_idx3_index" on materialized view "mv_idx3" +--- missing some pkey columns: no index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a; +NOTICE: could not create an index on materialized view "mv_idx4" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b; +NOTICE: could not create an index on materialized view "mv_idx5" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +--- with set-returning function: no index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10); +NOTICE: could not create an index on materialized view "mv_idx6" automatically +DETAIL: This target list does not have all the primary key columns. +HINT: Create an index on the materialized view for efficient incremental maintenance. +ROLLBACK; +-- type that doesn't have default operator class for access method btree +BEGIN; +CREATE TABLE table_json (j json); +CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json; +ERROR: data type json has no default operator class for access method "btree" +ROLLBACK; +-- cleanup +DROP TABLE rls_tbl CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to materialized view ivm_rls +drop cascades to materialized view ivm_rls2 +DROP TABLE num_tbl CASCADE; +DROP USER regress_ivm_user; +DROP USER regress_ivm_admin; +DROP TABLE mv_base_b CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to materialized view mv_ivm_1 +drop cascades to view b_view +drop cascades to materialized view b_mview +DROP TABLE mv_base_a CASCADE; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 8fa0a6c47fb..7caca5f64fd 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -77,6 +77,7 @@ test: brin_bloom brin_multi # Another group of parallel tests # ---------- test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual +test: incremental_matview # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other # psql depends on create_am diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql new file mode 100644 index 00000000000..7313ad82f3e --- /dev/null +++ b/src/test/regress/sql/incremental_matview.sql @@ -0,0 +1,407 @@ +-- create a table to use as a basis for views and materialized views in various combinations +CREATE TABLE mv_base_a (x int, i int, y int, j int); +CREATE TABLE mv_base_b (x int, i int, y int, k int); +-- test for base tables with dropped columns +ALTER TABLE mv_base_a DROP COLUMN x; +ALTER TABLE mv_base_a DROP COLUMN y; +ALTER TABLE mv_base_b DROP COLUMN x; +ALTER TABLE mv_base_b DROP COLUMN y; +INSERT INTO mv_base_a VALUES + (1,10), + (2,20), + (3,30), + (4,40), + (5,50); +INSERT INTO mv_base_b VALUES + (1,101), + (2,102), + (3,103), + (4,104); + +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +REFRESH MATERIALIZED VIEW mv_ivm_1; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + +-- REFRESH WITH NO DATA +BEGIN; +CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$ + BEGIN + RETURN NULL; + END +$$ language plpgsql; + +CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT +ON mv_base_a FROM mv_ivm_1 FOR EACH ROW +EXECUTE PROCEDURE dummy_ivm_trigger_func(); + +SELECT COUNT(*) +FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid +WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass; + +REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA; + +SELECT COUNT(*) +FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid +WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass; +ROLLBACK; + +-- immediate maintenance +BEGIN; +INSERT INTO mv_base_b VALUES(5,105); +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +UPDATE mv_base_a SET j = 0 WHERE i = 1; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +DELETE FROM mv_base_b WHERE (i,k) = (5,105); +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +ROLLBACK; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; + +-- DISTINCT not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a; + +-- test for renaming column name to camel style +BEGIN; +ALTER TABLE mv_base_a RENAME i TO "I"; +ALTER TABLE mv_base_a RENAME j TO "J"; +UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1; +SELECT * FROM mv_ivm_1 ORDER BY 1,2,3; +ROLLBACK; + + +-- TRUNCATE a base table in join views +BEGIN; +TRUNCATE mv_base_a; +SELECT * FROM mv_ivm_1; +ROLLBACK; + +BEGIN; +TRUNCATE mv_base_b; +SELECT * FROM mv_ivm_1; +ROLLBACK; + +-- some query syntax +BEGIN; +CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql' + AS 'SELECT 1' IMMUTABLE; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func(); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1; +ROLLBACK; + +-- result of materialized view have duplicate result. +BEGIN; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a; +INSERT INTO mv_base_a VALUES(6,20); +SELECT * FROM mv_ivm_duplicate ORDER BY 1; +DELETE FROM mv_base_a WHERE (i,j) = (2,20); +SELECT * FROM mv_ivm_duplicate ORDER BY 1; +ROLLBACK; + +-- aggregate not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i; + +-- support self join view and multiple change on the same table +BEGIN; +CREATE TABLE base_t (i int, v int); +INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30); +CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS + SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i; +SELECT * FROM mv_self ORDER BY v1; +INSERT INTO base_t VALUES (4,40); +DELETE FROM base_t WHERE i = 1; +UPDATE base_t SET v = v*10 WHERE i=2; +SELECT * FROM mv_self ORDER BY v1; +WITH + ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1), + ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1), + upd_t AS (UPDATE base_t SET v = v + 100 RETURNING 1), + dlt_t AS (DELETE FROM base_t WHERE i IN (4,5) RETURNING 1) +SELECT NULL; +SELECT * FROM mv_self ORDER BY v1; + +--- with sub-transactions +SAVEPOINT p1; +INSERT INTO base_t VALUES (7,70); +RELEASE SAVEPOINT p1; +INSERT INTO base_t VALUES (7,77); +SELECT * FROM mv_self ORDER BY v1, v2; + +ROLLBACK; + +-- support simultaneous table changes +BEGIN; +CREATE TABLE base_r (i int, v int); +CREATE TABLE base_s (i int, v int); +INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30); +INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300); +CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS + SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i); +SELECT * FROM mv ORDER BY v1; +WITH + ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1), + ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1), + ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1), + upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1), + dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1) +SELECT NULL; +SELECT * FROM mv ORDER BY v1; +ROLLBACK; + +-- support foreign reference constraints +BEGIN; +CREATE TABLE ri1 (i int PRIMARY KEY); +CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int); +INSERT INTO ri1 VALUES (1),(2),(3); +INSERT INTO ri2 VALUES (1),(2),(3); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS + SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i); +SELECT * FROM mv_ri ORDER BY i1; +UPDATE ri1 SET i=10 where i=1; +DELETE FROM ri1 WHERE i=2; +SELECT * FROM mv_ri ORDER BY i2; +ROLLBACK; + +-- views including NULL +BEGIN; +CREATE TABLE base_t (i int, v int); +INSERT INTO base_t VALUES (1,10),(2, NULL); +CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t; +SELECT * FROM mv ORDER BY i; +UPDATE base_t SET v = 20 WHERE i = 2; +SELECT * FROM mv ORDER BY i; +ROLLBACK; + +BEGIN; +CREATE TABLE base_t (i int); +CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t; +SELECT * FROM mv ORDER BY i; +INSERT INTO base_t VALUES (1),(NULL); +SELECT * FROM mv ORDER BY i; +ROLLBACK; + +-- IMMV containing user defined type +BEGIN; + +CREATE TYPE mytype; +CREATE FUNCTION mytype_in(cstring) + RETURNS mytype AS 'int4in' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE FUNCTION mytype_out(mytype) + RETURNS cstring AS 'int4out' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE TYPE mytype ( + LIKE = int4, + INPUT = mytype_in, + OUTPUT = mytype_out +); + +CREATE FUNCTION mytype_eq(mytype, mytype) + RETURNS bool AS 'int4eq' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE FUNCTION mytype_lt(mytype, mytype) + RETURNS bool AS 'int4lt' + LANGUAGE INTERNAL STRICT IMMUTABLE; +CREATE FUNCTION mytype_cmp(mytype, mytype) + RETURNS integer AS 'btint4cmp' + LANGUAGE INTERNAL STRICT IMMUTABLE; + +CREATE OPERATOR = ( + leftarg = mytype, rightarg = mytype, + procedure = mytype_eq); +CREATE OPERATOR < ( + leftarg = mytype, rightarg = mytype, + procedure = mytype_lt); + +CREATE OPERATOR CLASS mytype_ops + DEFAULT FOR TYPE mytype USING btree AS + OPERATOR 1 <, + OPERATOR 3 = , + FUNCTION 1 mytype_cmp(mytype,mytype); + +CREATE TABLE t_mytype (x mytype); +CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS + SELECT * FROM t_mytype; +INSERT INTO t_mytype VALUES ('1'::mytype); +SELECT * FROM mv_mytype; + +ROLLBACK; + +-- outer join is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i; +-- CTE is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv AS + WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i; +-- contain system column +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610'; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a; +-- contain subquery +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 ); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a; +-- contain ORDER BY +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k; +-- contain HAVING +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5; + +-- contain view or materialized view +CREATE VIEW b_view AS SELECT i,k FROM mv_base_b; +CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i; +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5; + +-- contain mutable functions +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int; + +-- LIMIT/OFFSET is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5; + +-- DISTINCT ON is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a; + +-- TABLESAMPLE clause is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50); + +-- window functions are not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a; + +-- inheritance parent is not supported +BEGIN; +CREATE TABLE parent (i int, v int); +CREATE TABLE child_a(options text) INHERITS(parent); +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm21 AS SELECT * FROM parent; +ROLLBACK; + +-- UNION statement is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;; + +-- empty target list is not allowed with IVM +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm25 AS SELECT FROM mv_base_a; + +-- FOR UPDATE/SHARE is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE; + +-- tartget list cannot contain ivm column that start with '__ivm' +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a; + +-- expressions specified in GROUP BY must appear in the target list. +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i; + +-- VALUES is not supported +CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1); + +-- views containing base tables with Row Level Security +DROP USER IF EXISTS regress_ivm_admin; +DROP USER IF EXISTS regress_ivm_user; +CREATE USER regress_ivm_admin; +CREATE USER regress_ivm_user; + +--- create a table with RLS +SET SESSION AUTHORIZATION regress_ivm_admin; +CREATE TABLE rls_tbl(id int, data text, owner name); +INSERT INTO rls_tbl VALUES + (1,'foo','regress_ivm_user'), + (2,'bar','postgres'); +CREATE TABLE num_tbl(id int, num text); +INSERT INTO num_tbl VALUES + (1,'one'), + (2,'two'), + (3,'three'), + (4,'four'), + (5,'five'), + (6,'six'); + +--- Users can access only their own rows +CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user); +ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY; +GRANT ALL on rls_tbl TO PUBLIC; +GRANT ALL on num_tbl TO PUBLIC; + +--- create a view owned by regress_ivm_user +SET SESSION AUTHORIZATION regress_ivm_user; + +CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls AS SELECT * FROM rls_tbl; +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; +RESET SESSION AUTHORIZATION; + +--- inserts rows owned by different users +INSERT INTO rls_tbl VALUES + (3,'baz','regress_ivm_user'), + (4,'qux','postgres'); +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; + +--- combination of diffent kinds of commands +WITH + i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')), + u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1), + u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2) +SELECT; +SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3; + +--- +SET SESSION AUTHORIZATION regress_ivm_user; +CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id); +RESET SESSION AUTHORIZATION; + +WITH + x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)), + y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4)) +SELECT; +SELECT * FROM ivm_rls2 ORDER BY 1,2,3; + +-- trigger updating the same table +BEGIN; +CREATE TABLE tbl_update_same (i int); +CREATE FUNCTION func_update_same() RETURNS TRIGGER AS + $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$ + LANGUAGE plpgsql; +CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW + EXECUTE FUNCTION func_update_same(); +CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same; +INSERT INTO tbl_update_same VALUES (1); +SELECT * FROM mv_update_same; + +-- self-referential FKs +CREATE TABLE tbl_self_ref (a int primary key, + b int references tbl_self_ref(a) ON UPDATE CASCADE); +INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2); +CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref; +UPDATE tbl_self_ref set a = a + 10; +SELECT * FROM mv_self_ref ORDER BY a; +ROLLBACK; + +-- automatic index creation +BEGIN; +CREATE TABLE base_a (i int primary key, j int); +CREATE TABLE base_b (i int primary key, j int); + +--- with all pkey columns: create an index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b; + +--- missing some pkey columns: no index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a; +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b; + +--- with set-returning function: no index +CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10); + +ROLLBACK; + +-- type that doesn't have default operator class for access method btree +BEGIN; +CREATE TABLE table_json (j json); +CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json; +ROLLBACK; + +-- cleanup + +DROP TABLE rls_tbl CASCADE; +DROP TABLE num_tbl CASCADE; +DROP USER regress_ivm_user; +DROP USER regress_ivm_admin; + +DROP TABLE mv_base_b CASCADE; +DROP TABLE mv_base_a CASCADE; -- 2.43.0 --Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM Content-Type: text/x-diff; name="v39-0006-Add-Incremental-View-Maintenance-support.patch" Content-Disposition: attachment; filename="v39-0006-Add-Incremental-View-Maintenance-support.patch" Content-Transfer-Encoding: 7bit ^ permalink raw reply [nested|flat] 6+ messages in thread
end of thread, other threads:[~2026-05-29 09:31 UTC | newest] Thread overview: 6+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2025-02-12 13:58 Re: TAP test command_fails versus command_fails_like Dagfinn Ilmari Mannsåker <[email protected]> 2025-02-12 15:40 ` Andrew Dunstan <[email protected]> 2025-02-12 16:58 ` Dagfinn Ilmari Mannsåker <[email protected]> 2025-02-12 17:18 ` Tom Lane <[email protected]> 2025-02-22 01:27 ` Peter Smith <[email protected]> 2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox