forked from sqlancer/sqlancer
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathClickHouseOptions.java
More file actions
267 lines (180 loc) · 32.9 KB
/
Copy pathClickHouseOptions.java
File metadata and controls
267 lines (180 loc) · 32.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
package sqlancer.clickhouse;
import java.util.Arrays;
import java.util.List;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import sqlancer.DBMSSpecificOptions;
@Parameters(separators = "=", commandDescription = "ClickHouse (default port: " + ClickHouseOptions.DEFAULT_PORT
+ ", default host: " + ClickHouseOptions.DEFAULT_HOST + ")")
public class ClickHouseOptions implements DBMSSpecificOptions<ClickHouseOracleFactory> {
public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 8123;
@Parameter(names = "--oracle")
public List<ClickHouseOracleFactory> oracle = Arrays.asList(ClickHouseOracleFactory.TLPWhere);
@Parameter(names = { "--test-joins" }, description = "Allow the generation of JOIN clauses", arity = 1)
public boolean testJoins = true;
@Parameter(names = { "--analyzer" }, description = "Enable analyzer in ClickHouse", arity = 1)
public boolean enableAnalyzer = true;
@Parameter(names = "--test-nullable-types", description = "Wrap a small fraction of generated column types in Nullable", arity = 1)
public boolean enableNullable = true;
@Parameter(names = "--test-lowcardinality-types", description = "Wrap a small fraction of generated column types in LowCardinality", arity = 1)
public boolean enableLowCardinality = true;
@Parameter(names = "--random-session-settings", description = "Apply a random subset of curated ClickHouse settings via SET on the per-database connection", arity = 1)
public boolean randomSessionSettings = false;
@Parameter(names = "--random-session-settings-budget", description = "Cap on the number of randomized session settings per database (0 = unbounded)")
public int randomSessionSettingsBudget = 5;
@Parameter(names = "--test-set-op-tlp", description = "Enable the set-operation TLP oracle (UNION ALL / UNION DISTINCT / INTERSECT / EXCEPT invariants)", arity = 1)
public boolean enableSetOpTLP = false;
@Parameter(names = "--test-aggregate-combinators", description = "Allow the expression generator to emit aggregate-combinator chains (sumIf, countIfArray, etc.)", arity = 1)
public boolean enableCombinators = false;
@Parameter(names = "--test-combinator-tlp", description = "Enable the combinator-identity oracle (sumIf/countIf/avgOrNull/... algebraic identities)", arity = 1)
public boolean enableCombinatorTLP = false;
@Parameter(names = "--test-array-join", description = "Enable ARRAY JOIN structural emission (no-op until Array column generation lands in type-system v2)", arity = 1)
public boolean enableArrayJoin = false;
@Parameter(names = "--semr-arity", description = "Number of SEMR settings to toggle together per query for the SEMRMulti oracle (>= 2)")
public int semrArity = 2;
@Parameter(names = "--tlp-groupby-strict", description = "Use UNION ALL (no outer canonicalisation) for TLPGroupBy. Surfaces partition-multiplicity false positives by design; default (off) collapses them via UNION DISTINCT.", arity = 1)
public boolean tlpGroupByStrict = false;
@Parameter(names = "--eet-26x-modes", description = "Enable the 26.x EET modes (COMPOUND_INTERVAL, OVERLAY_EQUIV, OVERLAY_SPLICE, NATURAL_SORT_KEY). Default-on since the 2026-06-10 convergence run (3h, 1.09M queries, 0 false positives from these modes); when off, pickMode() never returns them.", arity = 1)
public boolean eet26xModes = true;
@Parameter(names = "--variant-where-emission", description = "Emit Variant-typed predicate fragments in WHERE context (26.1 Variant-in-all-functions surface, PR #90900 + use_variant_as_common_type default-on, PR #90677). WHERE-only by design: the client-v2 RowBinary reader cannot decode a projected Variant column (R4), so the fragments are self-contained Boolean expressions and never reach a fetch column. Default-on since the 2026-06-10 convergence run (0 reader deaths, 0 false positives; the toInt64 constant-fallback wrap is load-bearing).", arity = 1)
public boolean variantWhereEmission = true;
@Parameter(names = "--text-search-predicate-emission", description = "Emit full-text-search predicates (hasToken/hasAllTokens/hasAnyTokens/startsWith/endsWith/multiSearchAny) over plain String columns in general WHERE context, from a fixed token vocabulary. Lets the whole oracle fleet (TLPWhere/NoREC/CODDTest/...) incidentally differential-test text-indexed columns against full scans. Restricted to startsWith/endsWith/multiSearchAny (the functions proven index==scan-equivalent across all tokenizers); hasToken/hasAllTokens/hasAnyTokens are NOT emitted here because they diverge index-vs-scan on array/ngrams/preprocessor (ClickHouse#107186), which the dedicated TextIndexDirectRead oracle targets instead.", arity = 1)
public boolean textSearchPredicateEmission = true;
@Parameter(names = "--persistent-view-emission", description = "Create plain VIEWs (named v<n>, so the schema reader marks them as views) as a DDL action during database generation, capped at 3 per database, so a VIEW can be picked as one relation of a multi-relation FROM list. Four open ClickHouse bugs need exactly that shape, including #114113 (LOGICAL_ERROR 'Left and right columns have same names' out of chooseJoinOrder for a three-way comma join whose middle relation is a view). Write-path generators and oracles filter views out, so this only widens the read surface.", arity = 1)
public boolean persistentViewEmission = true;
@Parameter(names = "--comma-join-emission", description = "Let the join generator emit genuine ON-less CROSS (comma) joins and chains of up to four relations, instead of always attaching an ON clause to a CROSS join (which silently degraded every CROSS into an INNER join). Required for the #114113 shape. Rate-limited to 10% of CROSS picks on purpose: at 50% a 40-minute dev-VM run spent about 40% of its thread budget on three- and four-way cartesian products that time out at max_execution_time, and throughput fell from ~100 to ~10 queries/s.", arity = 1)
public boolean commaJoinEmission = true;
@Parameter(names = "--truth-value-predicate-emission", description = "Emit boolean-position wrappers and SQL truth-value predicates in general WHERE context: NOT (NOT x), NOT x, x IS [NOT] TRUE/FALSE/UNKNOWN, x IS NOT DISTINCT FROM lit, nullIf/ifNull/coalesce(x, lit), and LIKE/ILIKE ... ESCAPE. Half the time the wrapper is compared against a numeric or float constant, which puts a boolean-valued expression in value position -- the shape KeyCondition's inversion pushdown mishandles (NOT (NOT key) collapses to bare key and prunes valid parts). Feeds the already-sound KeyCondition/NoREC/TLPWhere oracles; generator-only, no new comparison logic.", arity = 1)
public boolean truthValuePredicateEmission = true;
@Parameter(names = "--join-reorder-allow-dropped-key-ref", description = "Let the JoinReorder oracle build ON clauses that reference a key column dropped by a preceding SEMI/ANTI join. Default false, PERMANENTLY: ClickHouse#107073 was closed by the optimizer team as by-design non-determinism -- columns read from the eliminated side of a SEMI/ANTI join are ANY-like (filled from whichever matching row arrives first), so any plan change or physical row-order change legally flips the result and a differential oracle comparing such queries is unsound. The restriction is therefore a soundness rule, not a temporary known-bug pin. Set true only to demonstrate the documented non-determinism.", arity = 1)
public boolean joinReorderAllowDroppedKeyRef = false;
@Parameter(names = "--prewhere-equivalence-oracle", description = "PrewhereEquivalence oracle: WHERE == PREWHERE == WHERE+optimize_move_to_prewhere=0 over a MergeTree table read (multiset compare).", arity = 1)
public boolean prewhereEquivalenceOracle = true;
@Parameter(names = "--read-in-order-toggle-oracle", description = "ReadInOrderToggle oracle: optimize_read_in_order / optimize_aggregation_in_order / read_in_order_use_buffering all-on vs all-off must not change an ORDER BY LIMIT or non-float GROUP BY result.", arity = 1)
public boolean readInOrderToggleOracle = true;
@Parameter(names = "--count-optimization-oracle", description = "CountOptimization oracle: optimize_trivial_count_query / optimize_use_implicit_projections / optimize_use_projections on vs off (integer-exact count compares + countIf cross-check + GROUP-BY-key count; hardens #106573/#106125).", arity = 1)
public boolean countOptimizationOracle = true;
@Parameter(names = "--lazy-materialization-toggle-oracle", description = "LazyMaterializationToggle oracle: query_plan_optimize_lazy_materialization on vs off must not change an ORDER BY LIMIT read with heavy projections (positional compare).", arity = 1)
public boolean lazyMaterializationToggleOracle = true;
@Parameter(names = "--replacing-dedup-oracle", description = "ReplacingDedup oracle: ReplacingMergeTree(ver) FINAL == argMax(val, ver) GROUP BY key over a private merge-formed fixture with globally-unique versions.", arity = 1)
public boolean replacingDedupOracle = true;
@Parameter(names = "--quantile-consistency-oracle", description = "QuantileConsistency oracle: single-snapshot quantileExact==medianExact, quantilesExact[1]==quantileExact, monotone-in-level and Low<=Exact<=High over an integer column.", arity = 1)
public boolean quantileConsistencyOracle = true;
@Parameter(names = "--uniq-exactness-oracle", description = "UniqExactness oracle: uniqExact(c) == count(DISTINCT c) == length(groupUniqArray(c)) over integer/String columns (single snapshot).", arity = 1)
public boolean uniqExactnessOracle = true;
@Parameter(names = "--arg-extremum-oracle", description = "ArgExtremum oracle: argMax(v,k) / arraySort(groupArray(v)) / groupArraySorted(n)(v) against a Java ground truth over a private unique-key fixture.", arity = 1)
public boolean argExtremumOracle = true;
@Parameter(names = "--materialized-column-oracle", description = "MaterializedColumn oracle: each MATERIALIZED/ALIAS column's stored value == its defining expression recomputed in the same query (single-snapshot two-column compare).", arity = 1)
public boolean materializedColumnOracle = true;
@Parameter(names = "--grouping-decomposition-oracle", description = "GroupingDecomposition oracle: GROUP BY WITH ROLLUP detail rows (GROUPING(k)=0) == plain GROUP BY, super-aggregate row (GROUPING(k)=1) == grand count(), and sum of per-group counts == grand count(); integer aggregates + non-float keys only.", arity = 1)
public boolean groupingDecompositionOracle = true;
@Parameter(names = "--limit-ranking-oracle", description = "LimitRanking oracle: LIMIT a,b == LIMIT b OFFSET a, LIMIT n is a prefix of LIMIT n WITH TIES, and LIMIT n BY k yields <= n rows per distinct k. Deterministic total ORDER BY.", arity = 1)
public boolean limitRankingOracle = true;
@Parameter(names = "--window-frame-oracle", description = "WindowFrame oracle: over a unique-key fixture, default frame == explicit RANGE/ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and lagInFrame offsets match a one-preceding frame (single-snapshot column compares).", arity = 1)
public boolean windowFrameOracle = true;
@Parameter(names = "--semi-join-rewrite-oracle", description = "SemiJoinRewrite oracle: LEFT SEMI JOIN (preserved-side projection only, per #107073) == WHERE k IN (subquery), LEFT ANTI JOIN == NOT IN, and LEFT ANY JOIN cardinality == left row count.", arity = 1)
public boolean semiJoinRewriteOracle = true;
@Parameter(names = "--column-transformer-oracle", description = "ColumnTransformer oracle: SELECT * EXCEPT/APPLY/COLUMNS(regex) == the explicit column list, and DISTINCT ON (k) cardinality == count(DISTINCT k).", arity = 1)
public boolean columnTransformerOracle = true;
@Parameter(names = "--engine-equivalence-oracle", description = "EngineEquivalence oracle: an identical inserted multiset stored in MergeTree ORDER BY tuple() and an exact-multiset mirror (Memory/TinyLog/StripeLog/Log) must answer the same read-only query identically (multiset). Engine unavailability no-ops.", arity = 1)
public boolean engineEquivalenceOracle = true;
@Parameter(names = "--coalescing-final-oracle", description = "CoalescingFinal oracle: CoalescingMergeTree FINAL per key == argMaxIf(col, seq, isNotNull(col)) last-non-null ground truth over a merge-formed fixture with globally-unique seq. No-ops if CoalescingMergeTree is absent on head.", arity = 1)
public boolean coalescingFinalOracle = true;
@Parameter(names = "--join-get-set-oracle", description = "JoinGetSet oracle: x IN Set-engine table == x IN (subquery), and joinGet(Join-engine table, col, key) == the ANY LEFT JOIN lookup. No-ops if the Set/Join engines are absent.", arity = 1)
public boolean joinGetSetOracle = true;
@Parameter(names = "--remote-local-equivalence-oracle", description = "RemoteLocalEquivalence oracle: remote('127.0.0.1', db, t) == local table read (multiset, single-node distributed-read path), plus numbers(n) ground-truth checks.", arity = 1)
public boolean remoteLocalEquivalenceOracle = true;
@Parameter(names = "--map-tuple-container-oracle", description = "MapTupleContainer oracle: Map/Tuple/Array scalar extractions (mapKeys/mapValues/length/mapContains/tupleElement) toString-rendered == Java ground truth over a private fixture. All wire values are String/number (reader-safe).", arity = 1)
public boolean mapTupleContainerOracle = true;
@Parameter(names = "--geo-metamorphic-oracle", description = "GeoMetamorphic oracle: geo-function metamorphic identities (greatCircleDistance(p,p)==0, polygonArea>=0 and ==square area, pointInPolygon interior/outside, self-intersection area==self area) over inline integer coordinates, float-tolerance compares.", arity = 1)
public boolean geoMetamorphicOracle = true;
@Parameter(names = "--variant-subcolumn-oracle", description = "VariantSubcolumn oracle: Variant/Dynamic/JSON subcolumn roundtrip (toString-wrapped reads only; raw-column emission stays gated off). CAST/subcolumn-access roundtrip == inserted value. No-ops if the experimental types are unavailable.", arity = 1)
public boolean variantSubcolumnOracle = true;
@Parameter(names = "--aggregate-state-expansion-oracle", description = "AggregateStateExpansion oracle: finalizeAggregation(arrayReduce('<agg>State', groupArray(x))) == direct <agg>(x) for exact aggregates (sum/min/max/uniqExact/quantileExact/groupArray), plus an AggregatingMergeTree cross-part merge arm.", arity = 1)
public boolean aggregateStateExpansionOracle = true;
@Parameter(names = "--sequence-funnel-oracle", description = "SequenceFunnel oracle (DEFAULT OFF pending ground-truth rework): windowFunnel/sequenceCount/sequenceMatch/retention vs a Java model. Its windowFunnel monotonicity arm is inverted (windowFunnel is non-decreasing in step count, not non-increasing) and the exact-value Java models are unvalidated; both must be corrected and re-validated 1h-clean before flipping this default on.", arity = 1)
public boolean sequenceFunnelOracle = false;
@Parameter(names = "--partition-lifecycle-oracle", description = "PartitionLifecycle oracle: DETACH+ATTACH == identity, DROP PARTITION removes exactly that partition's rows, REPLACE PARTITION from identical copy == identity, MOVE PARTITION conserves rows; topology pinned via SYSTEM STOP MERGES.", arity = 1)
public boolean partitionLifecycleOracle = true;
@Parameter(names = "--alter-modify-consistency-oracle", description = "AlterModifyConsistency oracle: a data-preserving ALTER MODIFY COLUMN type-widen/CODEC/TTL/SETTING + MATERIALIZE must not change the visible row multiset (modulo a pre-applied widening cast).", arity = 1)
public boolean alterModifyConsistencyOracle = true;
@Parameter(names = "--ttl-determinism-oracle", description = "TtlDeterminism oracle: TTL DELETE + OPTIMIZE FINAL survivors == the non-expired bucket, using date buckets far from now() so the result is wall-clock-independent.", arity = 1)
public boolean ttlDeterminismOracle = true;
@Parameter(names = "--insert-dedup-oracle", description = "InsertDedup oracle: re-inserting a byte-identical block leaves the row count unchanged (insert_deduplicate default-on), while a distinct block grows the table; optional async-insert arm.", arity = 1)
public boolean insertDedupOracle = true;
@Parameter(names = "--token-bf-oracle", description = "TokenBf oracle: hasToken/=/IN with a tokenbf_v1 skip index == use_skip_indexes=0 scan (a bloom filter must never produce a false negative).", arity = 1)
public boolean tokenBfOracle = true;
@Parameter(names = "--vector-index-recall-oracle", description = "VectorIndexRecall oracle: vector_similarity (HNSW) index top-1 == exact brute-force top-1 (unique NN), and top-k containment (index max distance <= exact k-th distance); never exact set-equality for k>1. No-ops if the vector index is unavailable.", arity = 1)
public boolean vectorIndexRecallOracle = true;
@Parameter(names = "--sample-clause-oracle", description = "SampleClause oracle: query-level SAMPLE invariants on a table with a SAMPLE BY key -- SAMPLE 1 == full read (identity), SAMPLE k rows are a subset of the full read, and SAMPLE 1/k OFFSET i/k tiles are each a subset of the full read. Sound invariants only (SAMPLE is non-deterministic), so it never runs in the general fleet. Self-creates a sampleable fixture when no schema table has a sampling key.", arity = 1)
public boolean sampleClauseOracle = true;
@Parameter(names = "--sample-factor-arm", description = "Enable the SampleClause oracle's statistical _sample_factor reconstruction arm (sum(_sample_factor) over a sample ~= full count() within a tolerance band). Default false: this arm is approximate, not exact, and must be demonstrated 0-FP before being enabled.", arity = 1)
public boolean sampleFactorArm;
@Parameter(names = "--distributed-table-oracle", description = "DistributedTable oracle: a Distributed('default', db, local) wrapper over a local MergeTree must answer reads identically to the underlying table (multiset), route INSERTs through to the local table, and agree on exact-integer aggregates / non-float GROUP BY. Single-node, self-contained fixture.", arity = 1)
public boolean distributedTableOracle = true;
@Parameter(names = "--codec-roundtrip-oracle", description = "CodecRoundtrip oracle: a table whose columns carry random per-type CODEC(...) declarations and a CODEC(NONE) mirror holding the same inserted rows (including NaN, +/-inf, -0.0 and denormals) must answer the same read identically, still after OPTIMIZE ... FINAL, and still after an ALTER TABLE ... MODIFY COLUMN ... CODEC mutation. Lossy codecs are excluded from the equality arm by an explicit allowlist and only have their row count and NULL mask asserted.", arity = 1)
public boolean codecRoundtripOracle = true;
@Parameter(names = "--float-pruning-oracle", description = "FloatPruning oracle: over a private fixture whose Float32/Float64/Nullable(Float64) columns hold NaN, +/-inf, -0.0 and NULL across several parts (one part all-NaN), with float ORDER BY / PARTITION BY / minmax + bloom_filter skip indexes / materialized statistics, a negated float comparison must select the same key multiset with pruning enabled as with materialize() plus use_skip_indexes / allow_statistics_optimize / convert_query_to_cnf / optimize_move_to_prewhere all off, and count(P) + count(NOT P) + count(P IS NULL) must equal count(*). Row sets only, never a float aggregate, so the exact-integer-aggregate rule is not violated.", arity = 1)
public boolean floatPruningOracle = true;
@Parameter(names = "--distributed-plan-equivalence-oracle", description = "DistributedPlanEquivalence oracle: one generated read must return the same multiset under plain local execution, make_distributed_plan = 1, serialize_query_plan = 1, a cluster('default', ...) read with parallel_replicas_local_plan on and off, and enable_parallel_replicas + max_parallel_replicas > 1 over both the local and the Distributed relation. Self-contained multi-block fixture that includes a VIEW relation in a three-way comma join, the shape behind #111727.", arity = 1)
public boolean distributedPlanEquivalenceOracle = true;
@Parameter(names = "--with-fill-oracle", description = "WithFill oracle: ORDER BY x WITH FILL FROM f TO t STEP s over a private Int64 table whose inserted rows are a subset of the step grid must return exactly the full grid [f, t) in ascending order -- present rows are kept, absent grid points are synthesized, no duplicates, no off-grid rows.", arity = 1)
public boolean withFillOracle = true;
@Parameter(names = "--array-function-oracle", description = "ArrayFunction oracle: Array(Int64) scalar functions (has/indexOf/countEqual/length/empty/notEmpty/arraySort/arrayReverseSort/arrayReverse/arrayDistinct/arrayCompact/arrayConcat/arrayPushBack/arrayPushFront/arraySlice/arraySum/arrayMin/arrayMax/hasAll/hasAny) toString-rendered == Java ground truth over a private fixture. All results are exact-integer or deterministic-order arrays; no floats.", arity = 1)
public boolean arrayFunctionOracle = true;
@Parameter(names = "--aggregate-function-column-oracle", description = "AggregateFunctionColumn oracle: SimpleAggregateFunction column round-trip (insert literal, read back via finalizeAggregation or direct read) and AggregatingMergeTree state accumulation == direct aggregate over same data.", arity = 1)
public boolean aggregateFunctionColumnOracle = true;
@Parameter(names = "--array-join-oracle", description = "ArrayJoin oracle: ARRAY JOIN unnest == arrayJoin() scalar function == a lateral-like JOIN expansion, count of output rows == sum of array lengths.", arity = 1)
public boolean arrayJoinOracle = true;
@Parameter(names = "--asof-join-oracle", description = "AsofJoin oracle: ASOF LEFT JOIN nearest-predecessor lookup == Java model lower-bound scan over sorted fixture data (exact integer values).", arity = 1)
public boolean asofJoinOracle = true;
@Parameter(names = "--correlated-subquery-oracle", description = "CorrelatedSubquery oracle: correlated EXISTS/NOT EXISTS == IN/NOT IN rewrite (semijoin/antijoin equivalence) over non-nullable integer keys, reading only the preserved-side key. No-ops if allow_experimental_correlated_subqueries is unsupported.", arity = 1)
public boolean correlatedSubqueryOracle = true;
@Parameter(names = "--cube-grouping-sets-oracle", description = "CubeGroupingSets oracle: GROUP BY CUBE / GROUPING SETS == manual UNION ALL of the individual group-by combinations (exact-integer counts, no floats).", arity = 1)
public boolean cubeGroupingSetsOracle = true;
@Parameter(names = "--join-using-oracle", description = "JoinUsing oracle: JOIN USING(k) == JOIN ON a.k=b.k for INNER, LEFT, and a 3-table INNER chain. Multiset-exact via arraySort(groupArray(tuple)) for INNER/LEFT, exact-integer aggregate for the chain. Private fixtures with overlapping Int32 key domain and Int64 payload columns.", arity = 1)
public boolean joinUsingOracle = true;
@Parameter(names = "--paste-join-oracle", description = "PasteJoin oracle: PASTE JOIN positional row-zip == manually zipped Java model (exact integer values, ORDER BY both sides).", arity = 1)
public boolean pasteJoinOracle = true;
@Parameter(names = "--string-function-oracle", description = "StringFunction oracle: ASCII string function ground-truth (length/lengthUTF8/lower/upper/reverse/substring/position/countSubstrings/startsWith/endsWith/concat/repeat/replaceAll/empty/notEmpty) == Java model over a private fixture. ASCII-only inputs so byte length == char length and all mappings are trivial; replaceAll is literal.", arity = 1)
public boolean stringFunctionOracle = true;
@Parameter(names = "--timezone-datetime-oracle", description = "TimezoneDatetime oracle: datetime metamorphic identities (toStartOfInterval aliases, dateDiff antisymmetry/known deltas, UTC round-trip idempotency, monotone truncation) verified as zero-violation countIf checks over a numbers()-generated DateTime/Date32 set. No DDL; single-snapshot; exact integer result.", arity = 1)
public boolean timezoneDatetimeOracle = true;
@Parameter(names = "--window-frame-ground-truth-oracle", description = "WindowFrameGroundTruth oracle: window function results (row_number/rank/dense_rank/lag/lead/sum OVER) == Java ground truth computed from the sorted model data.", arity = 1)
public boolean windowFrameGroundTruthOracle = true;
@Parameter(names = "--bit-function-oracle", description = "BitFunction oracle: bitAnd/bitOr/bitXor/bitNot/bitShiftLeft/bitShiftRight/bitCount/bitTest vs Java unsigned-64-bit ground truth (SCALAR arm), and bitmapCardinality/bitmapAndCardinality vs Java distinct-count/set-intersection (BITMAP arm). All comparisons are exact integer; no floats.", arity = 1)
public boolean bitFunctionOracle = true;
@Parameter(names = "--setting-flip-oracle", description = "SettingFlip oracle: a single curated result-neutral setting (optimize_read_in_order / query_plan_* / compile_* / max_threads / group_by_two_level_threshold / ... ) flipped between two values must not change a ProjectionToggle-style integer-aggregate read. Data-driven catalog; deliberately excludes join-reorder and optimize_use_implicit_projections (known-unsound/known-buggy surfaces covered elsewhere).", arity = 1)
public boolean settingFlipOracle = true;
@Parameter(names = "--concurrent-mutation-oracle", description = "ConcurrentMutation oracle: while background threads (own connections) hammer multiset-preserving churn (OPTIMIZE FINAL / ALTER DELETE WHERE 0 / concurrent SELECTs) on a private multi-part MergeTree, repeated reads on the main connection must always equal the pre-churn baseline. Targets read-vs-merge/mutation race wrong-results unreachable by single-snapshot oracles.", arity = 1)
public boolean concurrentMutationOracle = true;
@Parameter(names = "--low-cardinality-equivalence-oracle", description = "LowCardinalityEquivalence oracle: over a private fixture with paired plain/LowCardinality columns (Int32, String, Nullable(Int32), FixedString(4)) holding identical values, any read (row projection / GROUP BY / uniqExact / predicate) over the plain columns must equal the same read over the LowCardinality twins.", arity = 1)
public boolean lowCardinalityEquivalenceOracle = true;
@Parameter(names = "--groups-window-frame-emission", description = "Let the window-function generator attach an explicit frame clause, including the GROUPS frame mode added by PR #108653 (offsets count peer groups, not rows). ROWS and RANGE frames are emitted too; before this the generator emitted no frame clause at all, so every window call used the implicit default frame. The WindowFrameGroundTruth oracle grows a matching GROUPS arm with a tie-forming fixture and a Java peer-group ground truth.", arity = 1)
public boolean groupsWindowFrameEmission = true;
@Parameter(names = "--negative-limit-emission", description = "Let the LimitRanking oracle emit the negative LIMIT forms (LIMIT -n, LIMIT -n BY k, LIMIT -n WITH TIES) added by PR #103222 / PR #100930 and rewritten by PR #106502. LIMIT -n BY k takes the LAST n rows per key, so the sound assertion is that it equals LIMIT n BY k over the reverse total order (one fixture, multiset compare).", arity = 1)
public boolean negativeLimitEmission = true;
@Parameter(names = "--comparison-chain-emission", description = "Emit long homogeneous predicate chains -- 'col LIKE a% OR col LIKE b% OR ...' and 'col != 1 AND col != 2 AND ... AND col < n' (sometimes with a deliberately conflicting conjunct) -- so that optimize_or_like_chain (default-on since PR #94517) and optimize_and_compare_chain (PR #99736) actually fire. Without a chain shape neither rewrite is reachable. The SettingFlip oracle gains a dedicated arm that toggles both plus convert_query_to_cnf over such a chain.", arity = 1)
public boolean comparisonChainEmission = true;
@Parameter(names = "--index-hint-emission", description = "Enable the KeyCondition oracle's indexHint arm: rows(P AND Q) must be a sub-multiset of rows(indexHint(P) AND Q), which in turn must be a sub-multiset of rows(Q). indexHint(P) does NOT evaluate P as a filter, but it is not result-neutral either -- it restricts the read to the granules index analysis selects for P, so a row outside those granules is legitimately dropped (measured on head 26.8.1.1471). The lower bound is the pruning-soundness assertion that matters: a row satisfying P AND Q that indexHint(P) AND Q loses means index analysis pruned a granule holding a matching row. Deliberately NOT emitted into the general fleet's generatePredicate: with granule-level semantics inside a TLP partition, P / NOT P / P IS NULL read different granule sets and their union is no longer the whole table.", arity = 1)
public boolean indexHintEmission = true;
@Parameter(names = "--sparse-column-emission", description = "Make sparse serialization actually engage in fuzzed tables: set ratio_of_defaults_for_sparse_serialization explicitly at a low value in CREATE TABLE about half the time, and bias a random subset of columns of plain-MergeTree tables overwhelmingly towards the type default on INSERT. Sparse columns have a separate read path, a separate default-filling path and (since PR #105890) separate pruning and trivial-count logic; every existing pruning/count/FINAL oracle then covers them for free. Never applied to a dedupe engine's table, so the C2 rule on key-domain degeneracy is untouched.", arity = 1)
public boolean sparseColumnEmission = true;
@Parameter(names = "--mixed-direction-sorting-key", description = "Let the table generator emit descending and mixed-direction sorting keys (ORDER BY (a, b DESC), ORDER BY a DESC). Read-in-order and aggregation-in-order only take their non-uniform code path for such a key, which is where #111901 (optimize_aggregation_in_order over (a, b DESC) collapses GROUP BY groups) lives. A DESC key suppresses the PRIMARY KEY prefix and SAMPLE BY clauses for that table, and is never emitted for a dedupe engine.", arity = 1)
public boolean mixedDirectionSortingKey = true;
@Parameter(names = "--text-index-second-wave", description = "Enable the second-wave text-index arms: the icu('<locale>') tokenizer, hasPhrase with a Java token-position ground truth (needs allow_experimental_text_index_phrase_search = 1), the trivial-count-from-text-index arm (query_plan_optimize_count_from_text_index on vs off vs use_skip_indexes = 0), and text index parameters supplied via table settings instead of inline index arguments. The Japanese/MeCab tokenizer is deliberately absent: it needs a server-side <tokenizer><japanese> dictionary that the fuzzer's container does not carry.", arity = 1)
public boolean textIndexSecondWave = true;
@Parameter(names = "--pipe-equivalence-oracle", description = "PipeEquivalence oracle: one generated single-relation read rendered in classic SQL and in pipe-operator syntax (PR #111151) must return the same rows. Second renderer over one AST, the MaterializedColumnVisitor pattern. Restricted to a single relation on purpose -- each pipe stage is wrapped in a subquery, so a qualified name from a multi-relation FROM list stops resolving after the first stage.", arity = 1)
public boolean pipeEquivalenceOracle = true;
@Parameter(names = "--ie-join-oracle", description = "IEJoin oracle: a join whose ON has two inequality comparisons (the shape that activates the IEJoin algorithm of PR #109920) must return the same rows as the equivalent CROSS JOIN + WHERE. Other join algorithms cannot answer that ON shape at all (INVALID_JOIN_ON_EXPRESSION), so the cross-join rewrite, not an algorithm sweep, is the reference arm. Small fixtures by construction, since a non-equi join is quadratic.", arity = 1)
public boolean ieJoinOracle = true;
@Parameter(names = "--tuple-final-aggregation-oracle", description = "TupleFinalAggregation oracle: per-element aggregation of Tuple columns in SummingMergeTree and CoalescingMergeTree (PR #98039, gated by the allow_tuple_element_aggregation table setting) == a Java element-wise ground truth, and query-time FINAL == the result after a physical OPTIMIZE ... FINAL. Integer tuple elements only (C3), full projections only. AggregatingMergeTree is excluded: a plain Tuple is not an aggregate state there, so its FINAL legitimately keeps the first row.", arity = 1)
public boolean tupleFinalAggregationOracle = true;
@Parameter(names = "--summing-subset-projection-arm", description = "Enable the TupleFinalAggregation oracle's subset-projection arm, which reads only some of a SummingMergeTree's summed columns under query-time FINAL. Default false: this is a positive-control detector for the still-open #106125 (query-time FINAL applies the all-zero-row-deletion rule over only the columns the query reads), which reproduces on every current head, so with the arm on the oracle asserts on essentially every iteration -- the FloatPruning/TextIndexDirectRead situation. Turn it on to demonstrate #106125, not for fleet runs.", arity = 1)
public boolean summingSubsetProjectionArm;
@Override
public List<ClickHouseOracleFactory> getTestOracleFactory() {
return oracle;
}
}