@@ -50,6 +50,22 @@ defmodule ReplicationTest do
50
50
{ :noreply , [ reply ] , pid }
51
51
end
52
52
53
+ # This is part of the "stream_continuation" test and handles the COPY :done
54
+ # state. It will start another stream right away by starting the replication
55
+ # slot.
56
+ def handle_data ( :done , % { pid: pid , test: "stream_continuation" } ) do
57
+ send ( pid , { :done , System . unique_integer ( [ :monotonic ] ) } )
58
+ query = "START_REPLICATION SLOT postgrex_test LOGICAL 0/0 (proto_version '1', publication_names 'postgrex_example')"
59
+
60
+ { :stream , query , [ ] , pid }
61
+ end
62
+
63
+ # This is part of the "stream_continuation" test and handles the COPY results.
64
+ def handle_data ( msg , % { pid: pid , test: "stream_continuation" } = s ) do
65
+ send ( pid , { msg , System . unique_integer ( [ :monotonic ] ) } )
66
+ { :noreply , [ ] , s }
67
+ end
68
+
53
69
def handle_data ( msg , pid ) do
54
70
send ( pid , { msg , System . unique_integer ( [ :monotonic ] ) } )
55
71
{ :noreply , [ ] , pid }
@@ -80,6 +96,12 @@ defmodule ReplicationTest do
80
96
{ :query , query , { from , pid } }
81
97
end
82
98
99
+ # This is part of the "stream_continuation" test and handles call that
100
+ # triggers that chain of events.
101
+ def handle_call ( { :query , query , % { test: "stream_continuation" , next_query: _ } = opts } , from , pid ) do
102
+ { :query , query , Map . merge ( opts , % { from: from , pid: pid } ) }
103
+ end
104
+
83
105
@ impl true
84
106
def handle_call ( { :disconnect , reason } , _ , _ ) do
85
107
{ :disconnect , reason }
@@ -97,6 +119,12 @@ defmodule ReplicationTest do
97
119
{ :noreply , pid }
98
120
end
99
121
122
+ # Handles the result of the "stream_continuation" query call. It is the results of the slot creation.
123
+ def handle_result ( results , % { from: from , test: "stream_continuation" , next_query: next_query } = s ) do
124
+ Postgrex.ReplicationConnection . reply ( from , { :ok , results } )
125
+ { :stream , next_query , [ ] , Map . delete ( s , :next_query ) }
126
+ end
127
+
100
128
@ epoch DateTime . to_unix ( ~U[ 2000-01-01 00:00:00Z] , :microsecond )
101
129
defp current_time ( ) , do: System . os_time ( :microsecond ) - @ epoch
102
130
end
@@ -288,6 +316,24 @@ defmodule ReplicationTest do
288
316
# Can query after copy is done
289
317
{ :ok , [ % Postgrex.Result { } ] } = PR . call ( context . repl , { :query , "SELECT 1" } )
290
318
end
319
+
320
+ test "allow replication stream right after a COPY stream" , context do
321
+ P . query! ( context . pid , "INSERT INTO repl_test VALUES ($1, $2), ($3, $4)" , [ 42 , "42" , 1 , "1" ] )
322
+
323
+ query = "CREATE_REPLICATION_SLOT postgrex_test TEMPORARY LOGICAL pgoutput NOEXPORT_SNAPSHOT"
324
+ next_query = "COPY repl_test TO STDOUT"
325
+
326
+ PR . call (
327
+ context . repl ,
328
+ { :query , query , % { test: "stream_continuation" , next_query: next_query } }
329
+ )
330
+
331
+ assert_receive { "42\t 42\n " , i1 } , @ timeout
332
+ assert_receive { "1\t 1\n " , i2 } when i1 < i2 , @ timeout
333
+ assert_receive { :done , i3 } when i2 < i3 , @ timeout
334
+ # Prior to allowing one stream to start after another, this would fail
335
+ assert_receive << ?k , _ :: 64 , _ :: 64 , _ >> , @ timeout
336
+ end
291
337
end
292
338
293
339
defp start_replication ( repl ) do
0 commit comments