Skip to content

Commit 67529e6

Browse files
craig[bot]KeithChtbgspilchen
committed
153271: changefeedccl: implement db-level changefeed EXCLUDE TABLES syntax r=andyyang890,aerfrei a=KeithCh The syntax for EXCLUDE TABLES will be CREATE CHANGEFEED FOR DATABASE FOO EXCLUDE TABLES fizz,buzz; Resolves: #147423 Release note: none 153585: asim: add explanatory output to `assert` command r=tbg a=tbg I find that I have to check my understanding on this regularly, so perhaps this output can help understand that `balance` checks at each point in time that stores are close together, whereas `steady` checks that for each store, its min/max does not deviate from its mean (over time), in other words that the metric only changes within a small band. (Which does not imply any kind of convergence across the cluster; each store might settle on its own value for the metric). Epic: CRDB-49117 153667: sql: fix race in TestRollbackForeignKeyAddition r=spilchen a=spilchen The test flaked due to canceling the wrong job. Adding a foreign key creates two jobs (one per table). But only one gets suspended. The test could mistakenly cancel the non-suspended joib, causing a failure if the job had already completed. Now, it correctly selects the suspended job before canceling. Fixes #153570 Release note: none Epic: none Co-authored-by: Keith Chow <[email protected]> Co-authored-by: Tobias Grieger <[email protected]> Co-authored-by: Matt Spilchen <[email protected]>
4 parents 0b74d29 + bff6d51 + 21b183f + c25f350 commit 67529e6

File tree

13 files changed

+220
-35
lines changed

13 files changed

+220
-35
lines changed

docs/generated/sql/bnf/create_changefeed_stmt.bnf

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ create_changefeed_stmt ::=
44
| 'CREATE' 'CHANGEFEED' 'FOR' changefeed_table_target ( ( ',' changefeed_table_target ) )* 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
55
| 'CREATE' 'CHANGEFEED' 'FOR' changefeed_table_target ( ( ',' changefeed_table_target ) )* 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
66
| 'CREATE' 'CHANGEFEED' 'FOR' changefeed_table_target ( ( ',' changefeed_table_target ) )* 'INTO' sink
7-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
8-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
9-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
10-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
11-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option 'INTO' sink
7+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option db_level_changefeed_filter_option 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
8+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option db_level_changefeed_filter_option 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
9+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option db_level_changefeed_filter_option 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
10+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option db_level_changefeed_filter_option 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )*
11+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_option db_level_changefeed_filter_option 'INTO' sink
1212
| 'CREATE' 'CHANGEFEED' 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )* 'AS' 'SELECT' target_list 'FROM' changefeed_target_expr opt_where_clause
1313
| 'CREATE' 'CHANGEFEED' 'INTO' sink 'WITH' option ( ( ',' ( option '=' value | option | option '=' value | option ) ) )* 'AS' 'SELECT' target_list 'FROM' changefeed_target_expr opt_where_clause
1414
| 'CREATE' 'CHANGEFEED' 'INTO' sink 'WITH' option '=' value ( ( ',' ( option '=' value | option | option '=' value | option ) ) )* 'AS' 'SELECT' target_list 'FROM' changefeed_target_expr opt_where_clause

docs/generated/sql/bnf/stmt_block.bnf

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ create_stats_stmt ::=
643643

644644
create_changefeed_stmt ::=
645645
'CREATE' 'CHANGEFEED' 'FOR' changefeed_table_targets opt_changefeed_sink opt_with_options
646-
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_name opt_changefeed_sink opt_with_options
646+
| 'CREATE_CHANGEFEED_FOR_DATABASE' 'CHANGEFEED' 'FOR' 'DATABASE' database_name db_level_changefeed_filter_option opt_changefeed_sink opt_with_options
647647
| 'CREATE' 'CHANGEFEED' opt_changefeed_sink opt_with_options 'AS' 'SELECT' target_list 'FROM' changefeed_target_expr opt_where_clause
648648

649649
create_extension_stmt ::=
@@ -1951,6 +1951,10 @@ changefeed_table_targets ::=
19511951
opt_changefeed_sink ::=
19521952
'INTO' string_or_placeholder
19531953

1954+
db_level_changefeed_filter_option ::=
1955+
'EXCLUDE' 'TABLES' table_name_list
1956+
|
1957+
19541958
target_list ::=
19551959
( target_elem ) ( ( ',' target_elem ) )*
19561960

@@ -2856,6 +2860,9 @@ create_stats_option_list ::=
28562860
changefeed_table_target ::=
28572861
opt_table_prefix table_name opt_changefeed_family
28582862

2863+
table_name_list ::=
2864+
db_object_name_list
2865+
28592866
target_elem ::=
28602867
a_expr 'AS' target_name
28612868
| a_expr bare_col_label
@@ -2940,9 +2947,6 @@ row_or_rows ::=
29402947
table_index_name_list ::=
29412948
( table_index_name ) ( ( ',' table_index_name ) )*
29422949

2943-
table_name_list ::=
2944-
db_object_name_list
2945-
29462950
view_name_list ::=
29472951
db_object_name_list
29482952

@@ -3533,6 +3537,9 @@ opt_changefeed_family ::=
35333537
'FAMILY' family_name
35343538
|
35353539

3540+
db_object_name_list ::=
3541+
( db_object_name ) ( ( ',' db_object_name ) )*
3542+
35363543
target_name ::=
35373544
unrestricted_name
35383545

@@ -3606,9 +3613,6 @@ only_signed_fconst ::=
36063613
'+' 'FCONST'
36073614
| '-' 'FCONST'
36083615

3609-
db_object_name_list ::=
3610-
( db_object_name ) ( ( ',' db_object_name ) )*
3611-
36123616
inspect_option ::=
36133617
'INDEX' 'ALL'
36143618
| 'INDEX' '(' table_index_name_list ')'

pkg/ccl/changefeedccl/changefeed_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,35 @@ func TestDatabaseLevelChangefeedBasics(t *testing.T) {
224224
cdcTest(t, testFn)
225225
}
226226

227+
func TestDatabaseLevelChangefeedWithFilter(t *testing.T) {
228+
defer leaktest.AfterTest(t)()
229+
defer log.Scope(t).Close(t)
230+
231+
testFn := func(t *testing.T, s TestServer, f cdctest.TestFeedFactory) {
232+
expectSuccess := func(stmt string) {
233+
successfulFeed := feed(t, f, stmt)
234+
defer closeFeed(t, successfulFeed)
235+
_, err := successfulFeed.Next()
236+
require.NoError(t, err)
237+
}
238+
sqlDB := sqlutils.MakeSQLRunner(s.DB)
239+
sqlDB.Exec(t, `CREATE TABLE foo (a INT PRIMARY KEY, b STRING)`)
240+
sqlDB.Exec(t, `INSERT INTO foo VALUES (0, 'initial')`)
241+
sqlDB.Exec(t, `UPSERT INTO foo VALUES (0, 'updated')`)
242+
sqlDB.Exec(t, `CREATE TABLE foo2 (a INT PRIMARY KEY, b STRING)`)
243+
sqlDB.Exec(t, `INSERT INTO foo2 VALUES (0, 'initial')`)
244+
sqlDB.Exec(t, `UPSERT INTO foo2 VALUES (0, 'updated')`)
245+
246+
expectSuccess(`CREATE CHANGEFEED FOR DATABASE d EXCLUDE TABLES foo`)
247+
expectSuccess(`CREATE CHANGEFEED FOR DATABASE d EXCLUDE TABLES foo,foo2`)
248+
expectSuccess(`CREATE CHANGEFEED FOR DATABASE d EXCLUDE TABLES foo.bar.fizz, foo.foo2, foo`)
249+
expectErrCreatingFeed(t, f, `CREATE CHANGEFEED FOR DATABASE d EXCLUDE TABLES foo.*`,
250+
`at or near "*": syntax error`)
251+
// TODO(#147421): Assert payload once the filter works
252+
}
253+
cdcTest(t, testFn, feedTestEnterpriseSinks)
254+
}
255+
227256
func TestChangefeedBasicQuery(t *testing.T) {
228257
defer leaktest.AfterTest(t)()
229258
defer log.Scope(t).Close(t)

pkg/kv/kvserver/asim/assertion/assert.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ func (tht ThresholdType) String() string {
3434
case ExactBound:
3535
return "="
3636
case UpperBound:
37-
return "<"
37+
return ""
3838
case LowerBound:
39-
return ">"
39+
return ""
4040
default:
4141
panic("unknown threshold type")
4242
}
@@ -128,10 +128,28 @@ func (sa SteadyStateAssertion) Assert(
128128
max, _ := stats.Max(trimmedStoreStats)
129129
min, _ := stats.Min(trimmedStoreStats)
130130

131-
maxMean := math.Abs(max/mean - 1)
132-
minMean := math.Abs(min/mean - 1)
131+
var maxMean, minMean float64
132+
if mean == 0 {
133+
if min == 0 || max == 0 {
134+
// If the min is zero, all datapoints are nonnegative, so for the mean
135+
// to be zero, they must all be zero. If the max is zero, vice versa.
136+
// Define 0/0=1 to capture that they're equal, which is what matters
137+
// here (0/0 defaults to NaN in Go, but we don't want that here).
138+
maxMean = 0
139+
minMean = 0
140+
} else {
141+
// The datapoints cross zero, and their mean is zero, for example
142+
// [-1, 1]. The values here would also result from the "regular"
143+
// computation below, but it doesn't hurt to be explicit.
144+
minMean = math.Inf(1)
145+
maxMean = math.Inf(1)
146+
}
147+
} else {
148+
maxMean = math.Abs(max/mean - 1)
149+
minMean = math.Abs(min/mean - 1)
150+
}
133151

134-
if sa.Threshold.isViolated(maxMean) || sa.Threshold.isViolated(minMean) {
152+
if sa.Threshold.isViolated(maxMean) || sa.Threshold.isViolated(minMean) || math.IsNaN(maxMean) || math.IsNaN(minMean) {
135153
if holds {
136154
fmt.Fprintf(&buf, " %s\n", sa)
137155
holds = false

pkg/kv/kvserver/asim/tests/datadriven_simulation_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -580,23 +580,35 @@ func TestDataDriven(t *testing.T) {
580580
var ticks int
581581
scanMustExist(t, d, "type", &typ)
582582

583+
var buf strings.Builder
583584
switch typ {
584585
case "balance":
585586
scanMustExist(t, d, "stat", &stat)
586587
scanMustExist(t, d, "ticks", &ticks)
588+
threshold := scanThreshold(t, d)
587589
assertions = append(assertions, assertion.BalanceAssertion{
588590
Ticks: ticks,
589591
Stat: stat,
590-
Threshold: scanThreshold(t, d),
592+
Threshold: threshold,
591593
})
594+
_, _ = fmt.Fprintf(&buf, "asserting: max_{stores}(%s)/mean_{stores}(%s) %s %.2f at each of last %d ticks",
595+
stat, stat, threshold.ThresholdType, threshold.Value, ticks)
596+
// ^-- the max and mean are taken over the stores (with the tick fixed).
592597
case "steady":
593598
scanMustExist(t, d, "stat", &stat)
594599
scanMustExist(t, d, "ticks", &ticks)
600+
threshold := scanThreshold(t, d)
595601
assertions = append(assertions, assertion.SteadyStateAssertion{
596602
Ticks: ticks,
597603
Stat: stat,
598-
Threshold: scanThreshold(t, d),
604+
Threshold: threshold,
599605
})
606+
_, _ = fmt.Fprintf(&buf, "asserting: |%s(t)/mean_{T}(%s) - 1| %s %.2f ∀ t∈T and each store ("+
607+
"T=last %d ticks)",
608+
stat, stat, threshold.ThresholdType, threshold.Value, ticks)
609+
// ^-- the mean is taken over the ticks (and the check runs for each store).
610+
// These assertions are for "checking that change stops" (vs. balance
611+
// assertions, which verify that stores are close together on some metric).
600612
case "stat":
601613
var stores []int
602614
scanMustExist(t, d, "stat", &stat)
@@ -633,7 +645,7 @@ func TestDataDriven(t *testing.T) {
633645
default:
634646
panic("unknown assertion: " + typ)
635647
}
636-
return ""
648+
return buf.String()
637649
case "setting":
638650
// NB: delay could be supported for the below settings,
639651
// but it hasn't been needed yet.

pkg/kv/kvserver/asim/tests/testdata/non_rand/example_add_node.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_node
1919
# Assert that the replica counts balance within 5% of each other among stores.
2020
assertion type=balance stat=replicas ticks=6 upper_bound=1.05
2121
----
22+
asserting: max_{stores}(replicas)/mean_{stores}(replicas) ≤ 1.05 at each of last 6 ticks
2223

2324
# Update the replication factor for the keyspace to be 3, instead of the
2425
# initial replication factor of 1 set during generation.
@@ -35,7 +36,7 @@ replicas#1: first: [s1=301, s2=0, s3=0] (stddev=141.89, mean=100.33, sum=301)
3536
replicas#1: last: [s1=301, s2=271, s3=267] (stddev=15.17, mean=279.67, sum=839)
3637
artifacts[sma-count]: 866426beb5ad043b
3738
failed assertion sample 1
38-
balance stat=replicas threshold=(<1.05) ticks=6
39+
balance stat=replicas threshold=(1.05) ticks=6
3940
max/mean=1.08 tick=0
4041
max/mean=1.08 tick=1
4142
max/mean=1.08 tick=2

pkg/kv/kvserver/asim/tests/testdata/non_rand/example_multi_store.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ gen_load rate=7000 min_block=512 max_block=512
1313

1414
assertion stat=leases type=balance ticks=6 upper_bound=1
1515
----
16+
asserting: max_{stores}(leases)/mean_{stores}(leases) ≤ 1.00 at each of last 6 ticks
1617

17-
assertion stat=leases type=steady ticks=6 upper_bound=0
18+
assertion stat=leases type=steady ticks=6 exact_bound=0
1819
----
20+
asserting: |leases(t)/mean_{T}(leases) - 1| = 0.00 ∀ t∈T and each store (T=last 6 ticks)
1921

2022
eval duration=5m seed=42 metrics=(leases) cfgs=(sma-count,mma-only)
2123
----
@@ -26,7 +28,7 @@ leases#1: first: [s1=8, s2=3, s3=0, s4=0, s5=0, s6=0, s7=0, s8=0, s9=1, s10=0, s
2628
leases#1: last: [s1=4, s2=1, s3=0, s4=0, s5=0, s6=1, s7=0, s8=0, s9=1, s10=1, s11=1, s12=1, s13=2, s14=2] (stddev=1.07, mean=1.00, sum=14)
2729
artifacts[mma-only]: 3c31149bdddfe022
2830
failed assertion sample 1
29-
balance stat=leases threshold=(<1.00) ticks=6
31+
balance stat=leases threshold=(1.00) ticks=6
3032
max/mean=4.00 tick=0
3133
max/mean=4.00 tick=1
3234
max/mean=4.00 tick=2

pkg/kv/kvserver/asim/tests/testdata/non_rand/example_rebalancing.txt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ gen_load rate=7000 rw_ratio=0.95 access_skew=false min_block=128 max_block=256
2121
# seconds) the max/mean QPS of the cluster does not exceed 1.15.
2222
assertion stat=qps type=balance ticks=6 upper_bound=1.15
2323
----
24+
asserting: max_{stores}(qps)/mean_{stores}(qps) ≤ 1.15 at each of last 6 ticks
2425

2526
# The second is a steady state assertion. The steady state assertion requires
2627
# that during the last 6 ticks (60 seconds), the value of QPS per-store doesn't
@@ -31,6 +32,7 @@ assertion stat=qps type=balance ticks=6 upper_bound=1.15
3132
# to take a duration, not ticks.
3233
assertion stat=qps type=steady ticks=6 upper_bound=0.05
3334
----
35+
asserting: |qps(t)/mean_{T}(qps) - 1| ≤ 0.05 ∀ t∈T and each store (T=last 6 ticks)
3436

3537
# The generators are then called and 2 simulation runs, named samples are
3638
# created and evaluated. Each sample has a fixed duration of 3 minutes.
@@ -48,15 +50,15 @@ qps#1: last: [s1=3999, s2=1997, s3=0, s4=0, s5=0, s6=1003, s7=0] (stddev=1413.6
4850
qps#2: last: [s1=3996, s2=1996, s3=0, s4=0, s5=0, s6=1006, s7=0] (stddev=1412.60, mean=999.71, sum=6998)
4951
artifacts[mma-only]: c48e80aec15208d6
5052
failed assertion sample 1
51-
balance stat=qps threshold=(<1.15) ticks=6
53+
balance stat=qps threshold=(1.15) ticks=6
5254
max/mean=4.00 tick=0
5355
max/mean=4.00 tick=1
5456
max/mean=4.00 tick=2
5557
max/mean=4.00 tick=3
5658
max/mean=4.00 tick=4
5759
max/mean=4.00 tick=5
5860
failed assertion sample 2
59-
balance stat=qps threshold=(<1.15) ticks=6
61+
balance stat=qps threshold=(1.15) ticks=6
6062
max/mean=4.00 tick=0
6163
max/mean=4.00 tick=1
6264
max/mean=4.00 tick=2
@@ -88,15 +90,15 @@ qps#1: last: [s1=3995, s2=1998, s3=0, s4=0, s5=0, s6=1005, s7=0] (stddev=1412.5
8890
qps#2: last: [s1=4000, s2=1995, s3=0, s4=0, s5=0, s6=1004, s7=0] (stddev=1413.71, mean=999.86, sum=6999)
8991
artifacts[mma-only]: fc6f065395b9a390
9092
failed assertion sample 1
91-
balance stat=qps threshold=(<1.15) ticks=6
93+
balance stat=qps threshold=(1.15) ticks=6
9294
max/mean=4.00 tick=0
9395
max/mean=4.00 tick=1
9496
max/mean=4.00 tick=2
9597
max/mean=4.00 tick=3
9698
max/mean=4.00 tick=4
9799
max/mean=4.00 tick=5
98100
failed assertion sample 2
99-
balance stat=qps threshold=(<1.15) ticks=6
101+
balance stat=qps threshold=(1.15) ticks=6
100102
max/mean=4.00 tick=0
101103
max/mean=4.00 tick=1
102104
max/mean=4.00 tick=2

pkg/kv/kvserver/asim/tests/testdata/non_rand/example_splitting.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ setting split_qps_threshold=2500
2020

2121
# Assert that the number of replicas should not change at all during the last 6
2222
# ticks of the simulation.
23-
assertion stat=replicas type=steady ticks=6 upper_bound=0.00
23+
assertion stat=replicas type=steady ticks=6 exact_bound=0.00
2424
----
25+
asserting: |replicas(t)/mean_{T}(replicas) - 1| = 0.00 ∀ t∈T and each store (T=last 6 ticks)
2526

2627

2728
# Examine the number of replicas. Here there were 5 load based splits. This

pkg/sql/parser/sql.y

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,13 @@ func (u *sqlSymUnion) doBlockOptions() tree.DoBlockOptions {
959959
func (u *sqlSymUnion) doBlockOption() tree.DoBlockOption {
960960
return u.val.(tree.DoBlockOption)
961961
}
962+
func (u *sqlSymUnion) changefeedFilterOption() *tree.ChangefeedFilterOption {
963+
if filterOption, ok := u.val.(*tree.ChangefeedFilterOption); ok {
964+
return filterOption
965+
}
966+
return nil
967+
}
968+
962969
%}
963970

964971
// NB: the %token definitions must come before the %type definitions in this
@@ -1592,6 +1599,7 @@ func (u *sqlSymUnion) doBlockOption() tree.DoBlockOption {
15921599
%type <tree.ReturningClause> returning_clause
15931600
%type <tree.TableExprs> opt_using_clause
15941601
%type <tree.RefreshDataOption> opt_clear_data
1602+
%type <*tree.ChangefeedFilterOption> db_level_changefeed_filter_option
15951603

15961604
%type <tree.BatchParam> batch_param
15971605
%type <[]tree.BatchParam> batch_param_list
@@ -6257,12 +6265,13 @@ create_changefeed_stmt:
62576265
Level: tree.ChangefeedLevelTable,
62586266
}
62596267
}
6260-
| CREATE_CHANGEFEED_FOR_DATABASE CHANGEFEED FOR DATABASE database_name opt_changefeed_sink opt_with_options
6268+
| CREATE_CHANGEFEED_FOR_DATABASE CHANGEFEED FOR DATABASE database_name db_level_changefeed_filter_option opt_changefeed_sink opt_with_options
62616269
{
62626270
$$.val = &tree.CreateChangefeed{
62636271
DatabaseTarget: tree.ChangefeedDatabaseTarget($5),
6264-
SinkURI: $6.expr(),
6265-
Options: $7.kvOptions(),
6272+
FilterOption: $6.changefeedFilterOption(),
6273+
SinkURI: $7.expr(),
6274+
Options: $8.kvOptions(),
62666275
Level: tree.ChangefeedLevelDatabase,
62676276
}
62686277
}
@@ -6487,6 +6496,16 @@ opt_using_clause:
64876496
$$.val = tree.TableExprs{}
64886497
}
64896498

6499+
db_level_changefeed_filter_option:
6500+
EXCLUDE TABLES table_name_list
6501+
{
6502+
$$.val = &tree.ChangefeedFilterOption{Tables: $3.tableNames(), FilterType: tree.ExcludeFilter}
6503+
}
6504+
| /* EMPTY */
6505+
{
6506+
$$.val = nil
6507+
}
6508+
64906509

64916510
// %Help: DISCARD - reset the session to its initial state
64926511
// %Category: Cfg

0 commit comments

Comments
 (0)