From bde027b27a1b82bd6de58b7a2c9a2649b1cfd3f7 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Fri, 19 Jun 2026 19:20:56 -0700 Subject: [PATCH 1/7] [DBSP] Testing API to wait for all compactions to complete Signed-off-by: Mihai Budiu --- crates/dbsp/src/circuit/circuit_builder.rs | 72 ++++++++++ crates/dbsp/src/circuit/dbsp_handle.rs | 134 ++++++++++++++++++ crates/dbsp/src/circuit/operator_traits.rs | 6 + .../src/operator/dynamic/accumulate_trace.rs | 6 + .../operator/dynamic/multijoin/match_keys.rs | 4 + crates/dbsp/src/operator/dynamic/trace.rs | 6 + crates/dbsp/src/trace.rs | 5 + crates/dbsp/src/trace/spine_async.rs | 25 ++++ crates/dbsp/src/trace/test/test_batch.rs | 4 + 9 files changed, 262 insertions(+) diff --git a/crates/dbsp/src/circuit/circuit_builder.rs b/crates/dbsp/src/circuit/circuit_builder.rs index d4dc2c6012c..872c1918dc3 100644 --- a/crates/dbsp/src/circuit/circuit_builder.rs +++ b/crates/dbsp/src/circuit/circuit_builder.rs @@ -1102,6 +1102,9 @@ pub trait Node: Any { /// Call [`Operator::start_compaction`](super::operator_traits::Operator::start_compaction) on the operator this node encapsulates. fn start_compaction(&mut self); + /// Call [`Operator::is_compaction_complete`](super::operator_traits::Operator::is_compaction_complete) on the operator this node encapsulates. + fn is_compaction_complete(&self) -> bool; + /// Place operator in the replay mode. /// /// In the replay mode the operator streams its stored state to a temporary @@ -1885,6 +1888,10 @@ pub trait CircuitBase: 'static { fn rebalance(&self); fn start_compaction(&self); + + /// Returns `true` when all operators' background compaction has fully + /// converged. + fn is_compaction_complete(&self) -> bool; } /// The circuit interface. All DBSP computation takes place within a circuit. @@ -3595,6 +3602,15 @@ where Ok(()) }); } + + fn is_compaction_complete(&self) -> bool { + let mut complete = true; + let _ = self.map_local_nodes(&mut |node| { + complete &= node.is_compaction_complete(); + Ok(()) + }); + complete + } } impl Circuit for ChildCircuit @@ -4775,6 +4791,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -4926,6 +4946,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -5091,6 +5115,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -5249,6 +5277,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -5464,6 +5496,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -5655,6 +5691,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -5870,6 +5910,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -6059,6 +6103,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -6269,6 +6317,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -6464,6 +6516,10 @@ where self.operator.start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.clear_state() } @@ -6649,6 +6705,10 @@ where self.operator.borrow_mut().start_compaction() } + fn is_compaction_complete(&self) -> bool { + self.operator.borrow().is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.operator.borrow_mut().clear_state() } @@ -6816,6 +6876,10 @@ where fn start_compaction(&mut self) {} + fn is_compaction_complete(&self) -> bool { + true + } + fn clear_state(&mut self) -> Result<(), DbspError> { Ok(()) } @@ -7048,6 +7112,10 @@ where self.circuit.start_compaction(); } + fn is_compaction_complete(&self) -> bool { + self.circuit.is_compaction_complete() + } + fn clear_state(&mut self) -> Result<(), DbspError> { self.circuit .map_local_nodes_mut(&mut |node| node.clear_state()) @@ -7839,6 +7907,10 @@ impl CircuitHandle { pub fn start_compaction(&self) { self.circuit.start_compaction() } + + pub fn is_compaction_complete(&self) -> bool { + self.circuit.is_compaction_complete() + } } pin_project! { diff --git a/crates/dbsp/src/circuit/dbsp_handle.rs b/crates/dbsp/src/circuit/dbsp_handle.rs index d585ab7868b..d2e83f57efc 100644 --- a/crates/dbsp/src/circuit/dbsp_handle.rs +++ b/crates/dbsp/src/circuit/dbsp_handle.rs @@ -883,6 +883,15 @@ impl Runtime { return; } } + Ok(Command::IsCompactionComplete) => { + let complete = circuit.is_compaction_complete(); + if status_sender + .send(Ok(Response::IsCompactionComplete(complete))) + .is_err() + { + return; + } + } // Nothing to do: do some housekeeping and relinquish the CPU if there's none // left. Err(TryRecvError::Empty) => { @@ -976,6 +985,7 @@ enum Command { Rebalance, SetAutoRebalance(bool), StartCompaction, + IsCompactionComplete, } impl Debug for Command { @@ -1018,6 +1028,7 @@ impl Debug for Command { f.debug_tuple("SetAutoRebalance").field(enable).finish() } Command::StartCompaction => write!(f, "StartCompaction"), + Command::IsCompactionComplete => write!(f, "IsCompactionComplete"), } } } @@ -1027,6 +1038,7 @@ enum Response { Unit, CommitComplete(bool), BootstrapComplete(bool), + IsCompactionComplete(bool), CommitProgress(CommitProgress), ProfileDump(Graph), Profile(WorkerProfile), @@ -1740,6 +1752,58 @@ impl DBSPHandle { self.broadcast_command(Command::StartCompaction, |_, _| {})?; Ok(()) } + + /// Returns `true` when background compaction has fully converged on every + /// worker: all compaction requests have been processed, no merge is in + /// progress, and each spine has been reduced to at most one batch. + /// + /// This is a non-blocking point-in-time snapshot. Callers that need to + /// wait for compaction to finish should call + /// [`wait_for_compaction`](Self::wait_for_compaction) or poll this method. + pub fn is_compaction_complete(&mut self) -> Result { + let mut complete = true; + self.broadcast_command(Command::IsCompactionComplete, |_, response| { + if let Response::IsCompactionComplete(c) = response { + complete &= c; + } + })?; + Ok(complete) + } + + /// Block until background compaction has fully converged on every worker, + /// or until `timeout` elapses. This method is designed for use in tests. + /// + /// Polls [`is_compaction_complete`](Self::is_compaction_complete) with + /// exponential back-off, starting at 1 ms and doubling each iteration up + /// to a cap of 1 s. + /// + /// Returns `Ok(())` when compaction is complete, or + /// `Err(`[`DbspError::Constructor`]`)` when the timeout expires. + pub fn wait_for_compaction(&mut self, timeout: std::time::Duration) -> Result<(), DbspError> { + use std::thread; + use std::time::Instant; + + const INITIAL_SLEEP_MS: u64 = 1; + const MAX_SLEEP_MS: u64 = 1_000; + + let deadline = Instant::now() + timeout; + let mut sleep_ms = INITIAL_SLEEP_MS; + + loop { + if self.is_compaction_complete()? { + return Ok(()); + } + let remaining = deadline.saturating_duration_since(Instant::now()); + if remaining.is_zero() { + return Err(DbspError::Constructor(anyhow::anyhow!( + "timed out after {timeout:?} waiting for compaction to complete" + ))); + } + let sleep = std::time::Duration::from_millis(sleep_ms).min(remaining); + thread::sleep(sleep); + sleep_ms = (sleep_ms * 2).min(MAX_SLEEP_MS); + } + } } impl Drop for DBSPHandle { @@ -2651,4 +2715,74 @@ pub(crate) mod tests { dbsp.kill().unwrap(); } } + + /// `is_compaction_complete` / `wait_for_compaction` must converge after a + /// compaction sweep and verify actual merging occurred. + /// + /// Uses in-memory storage so the test finishes quickly. + #[test] + fn test_is_compaction_complete() { + use crate::circuit::GlobalNodeId; + use crate::circuit::metadata::{MetaItem, SPINE_BATCHES_COUNT}; + use crate::utils::Tup2; + use std::time::Duration; + + const BATCHES: usize = 30; + const RECORDS_PER_BATCH: i32 = 500; + + let (mut dbsp, input_handle) = + Runtime::init_circuit(CircuitConfig::with_workers(2), |circuit| { + let (stream, handle) = circuit.add_input_indexed_zset::(); + stream.shard().integrate_trace(); + Ok(handle) + }) + .unwrap(); + + // Feed enough batches to give each spine more than one batch to merge. + for batch in 0..BATCHES as i32 { + let mut tuples: Vec<_> = (0..RECORDS_PER_BATCH) + .map(|r| Tup2(batch * RECORDS_PER_BATCH + r, Tup2(r, 1))) + .collect(); + input_handle.append(&mut tuples); + dbsp.transaction().unwrap(); + } + + // Collect per-operator spine batch counts from the profile. + let batch_counts = |dbsp: &mut DBSPHandle| -> Vec { + let root = GlobalNodeId::root(); + dbsp.retrieve_profile() + .unwrap() + .worker_profiles + .iter() + .flat_map(|p| p.attribute_profile(&SPINE_BATCHES_COUNT)) + .filter_map(|(id, value)| { + (id != root).then(|| match value { + MetaItem::Count(n) => n, + other => panic!("unexpected MetaItem: {other:?}"), + }) + }) + .collect() + }; + + // Before compaction there must be at least one spine with more than one + // batch, confirming that actual merging work is needed. + let counts_before = batch_counts(&mut dbsp); + assert!( + counts_before.iter().any(|&n| n > 1), + "expected at least one spine with >1 batch before compaction, got {counts_before:?}" + ); + + // Request a full compaction and block until all spines converge. + dbsp.start_compaction().unwrap(); + dbsp.wait_for_compaction(Duration::from_secs(60)).unwrap(); + + // After convergence every spine must have at most one batch. + let counts_after = batch_counts(&mut dbsp); + assert!( + counts_after.iter().all(|&n| n <= 1), + "expected all spines to have <=1 batch after compaction, got {counts_after:?}" + ); + + dbsp.kill().unwrap(); + } } diff --git a/crates/dbsp/src/circuit/operator_traits.rs b/crates/dbsp/src/circuit/operator_traits.rs index 492b142a211..6a628b10bd1 100644 --- a/crates/dbsp/src/circuit/operator_traits.rs +++ b/crates/dbsp/src/circuit/operator_traits.rs @@ -312,6 +312,12 @@ pub trait Operator: 'static { /// /// Only defined for operators that support compaction. No-op for all other operators. fn start_compaction(&mut self) {} + + /// Returns `true` when the operator's background compaction has fully + /// converged. Operators without a trace always return `true`. + fn is_compaction_complete(&self) -> bool { + true + } } /// A source operator that injects data from the outside world or from the diff --git a/crates/dbsp/src/operator/dynamic/accumulate_trace.rs b/crates/dbsp/src/operator/dynamic/accumulate_trace.rs index f544dda92ff..05b869e1646 100644 --- a/crates/dbsp/src/operator/dynamic/accumulate_trace.rs +++ b/crates/dbsp/src/operator/dynamic/accumulate_trace.rs @@ -1107,6 +1107,12 @@ where trace.initiate_compaction() } } + + fn is_compaction_complete(&self) -> bool { + self.trace + .as_ref() + .is_none_or(|t| t.is_compaction_complete()) + } } impl StrictOperator for AccumulateZ1Trace diff --git a/crates/dbsp/src/operator/dynamic/multijoin/match_keys.rs b/crates/dbsp/src/operator/dynamic/multijoin/match_keys.rs index 3ad79e60d59..e8018808ef9 100644 --- a/crates/dbsp/src/operator/dynamic/multijoin/match_keys.rs +++ b/crates/dbsp/src/operator/dynamic/multijoin/match_keys.rs @@ -867,6 +867,10 @@ where fn start_compaction(&mut self) {} + fn is_compaction_complete(&self) -> bool { + true + } + fn eval<'a>( &'a mut self, ) -> Pin, SchedulerError>> + 'a>> { diff --git a/crates/dbsp/src/operator/dynamic/trace.rs b/crates/dbsp/src/operator/dynamic/trace.rs index 962ddc8cb18..57b1bd99de9 100644 --- a/crates/dbsp/src/operator/dynamic/trace.rs +++ b/crates/dbsp/src/operator/dynamic/trace.rs @@ -1175,6 +1175,12 @@ where trace.initiate_compaction() } } + + fn is_compaction_complete(&self) -> bool { + self.trace + .as_ref() + .is_none_or(|t| t.is_compaction_complete()) + } } impl StrictOperator for Z1Trace diff --git a/crates/dbsp/src/trace.rs b/crates/dbsp/src/trace.rs index 34afb765769..1a9e1818644 100644 --- a/crates/dbsp/src/trace.rs +++ b/crates/dbsp/src/trace.rs @@ -335,6 +335,11 @@ pub trait Trace: BatchReader { fn metadata(&self, _meta: &mut OperatorMeta) {} fn initiate_compaction(&self); + + /// Returns `true` when compaction has fully converged: all compaction + /// requests have been processed, no background merge is in progress, and + /// the trace has been reduced to at most one batch. + fn is_compaction_complete(&self) -> bool; } /// Where a batch is stored. diff --git a/crates/dbsp/src/trace/spine_async.rs b/crates/dbsp/src/trace/spine_async.rs index 692756c76fe..1ed606da5d2 100644 --- a/crates/dbsp/src/trace/spine_async.rs +++ b/crates/dbsp/src/trace/spine_async.rs @@ -438,6 +438,23 @@ where self.slots.iter().any(|slot| slot.merging_batches.is_some()) } + /// Returns `true` if compaction has fully converged: all compaction + /// requests have been processed, no merge is in progress, and the spine + /// has been reduced to at most one batch. + /// + /// A single batch (or zero batches) is the desired steady state after a + /// compaction sweep completes. Note that "ran out of fuel" is **not** + /// the same as complete: a spine with several batches and no pending work + /// may still need further merges once new batches arrive. + fn is_compaction_complete(&self) -> bool { + let all_requests_processed = self + .slots + .iter() + .all(|s| s.compaction_status == CompactionStatus::None); + let total_batches: usize = self.slots.iter().map(Slot::n_batches).sum(); + all_requests_processed && !self.is_merging() && total_batches <= 1 + } + /// Finishes up the ongoing merge at the given `level`, which completed in /// `elapsed` time over `n_steps` steps, with `new_batch` at `new_level` as /// the result. @@ -1080,6 +1097,10 @@ where let mut state = self.state.lock().unwrap(); state.initiate_compaction(); } + + fn is_compaction_complete(&self) -> bool { + self.state.lock().unwrap().is_compaction_complete() + } } impl Drop for AsyncMerger @@ -2120,6 +2141,10 @@ where fn initiate_compaction(&self) { self.merger.initiate_compaction(); } + + fn is_compaction_complete(&self) -> bool { + self.merger.is_compaction_complete() + } } impl Spine diff --git a/crates/dbsp/src/trace/test/test_batch.rs b/crates/dbsp/src/trace/test/test_batch.rs index 169dda50f4e..c35da1ed8dc 100644 --- a/crates/dbsp/src/trace/test/test_batch.rs +++ b/crates/dbsp/src/trace/test/test_batch.rs @@ -1407,6 +1407,10 @@ where } fn initiate_compaction(&self) {} + + fn is_compaction_complete(&self) -> bool { + true + } } /// Test random sampling methods. From a06e8f2000f8a70011c84f7ae30a33ee588dcd61 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Fri, 19 Jun 2026 19:21:33 -0700 Subject: [PATCH 2/7] [SQL] Java test support for the API that blocks for compaction Signed-off-by: Mihai Budiu --- crates/dbsp/src/circuit/dbsp_handle.rs | 15 +- .../compiler/sql/quidem/HrBaseTests.java | 7 + .../simple/IncrementalRegression2Tests.java | 27 +- .../sql/tools/BlockForCompaction.java | 9 + .../sql/tools/CompilerCircuitStream.java | 7 + .../compiler/sql/tools/IStreamCommand.java | 7 + .../compiler/sql/tools/InputOutputChange.java | 11 +- .../sql/tools/InputOutputChangeStream.java | 17 +- .../compiler/sql/tools/TestCase.java | 243 ++++++++++-------- 9 files changed, 216 insertions(+), 127 deletions(-) create mode 100644 sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/BlockForCompaction.java create mode 100644 sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/IStreamCommand.java diff --git a/crates/dbsp/src/circuit/dbsp_handle.rs b/crates/dbsp/src/circuit/dbsp_handle.rs index d2e83f57efc..faa9d95d86a 100644 --- a/crates/dbsp/src/circuit/dbsp_handle.rs +++ b/crates/dbsp/src/circuit/dbsp_handle.rs @@ -1771,15 +1771,18 @@ impl DBSPHandle { } /// Block until background compaction has fully converged on every worker, - /// or until `timeout` elapses. This method is designed for use in tests. + /// or until `timeout` elapses. /// /// Polls [`is_compaction_complete`](Self::is_compaction_complete) with /// exponential back-off, starting at 1 ms and doubling each iteration up /// to a cap of 1 s. /// - /// Returns `Ok(())` when compaction is complete, or - /// `Err(`[`DbspError::Constructor`]`)` when the timeout expires. - pub fn wait_for_compaction(&mut self, timeout: std::time::Duration) -> Result<(), DbspError> { + /// Returns `Ok(())` when compaction is complete, or an error if the + /// circuit fails or the timeout expires. + pub fn wait_for_compaction( + &mut self, + timeout: std::time::Duration, + ) -> Result<(), anyhow::Error> { use std::thread; use std::time::Instant; @@ -1795,9 +1798,7 @@ impl DBSPHandle { } let remaining = deadline.saturating_duration_since(Instant::now()); if remaining.is_zero() { - return Err(DbspError::Constructor(anyhow::anyhow!( - "timed out after {timeout:?} waiting for compaction to complete" - ))); + anyhow::bail!("timed out after {timeout:?} waiting for compaction to complete"); } let sleep = std::time::Duration::from_millis(sleep_ms).min(remaining); thread::sleep(sleep); diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HrBaseTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HrBaseTests.java index fecda80f817..ebb01fe77e3 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HrBaseTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HrBaseTests.java @@ -52,6 +52,13 @@ CREATE TABLE Department( --(30, 'Marketing', ARRAY()), --(40, 'HR', ARRAY[Employee(200, 20, 'Eric', 8000, 500)]) --; + + -- Postgres syntax + --INSERT INTO Depts VALUES + --(10, 'Sales', ARRAY[ROW(100, 10, 'Bill', 10000, 1000)::Employee, ROW(150, 10, 'Sebastian', 7000, null)::Employee]), + --(30, 'Marketing', ARRAY[]::Employee ARRAY), + --(40, 'HR', ARRAY[ROW(200, 20, 'Eric', 8000, 500)::Employee]) + --; """); } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/IncrementalRegression2Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/IncrementalRegression2Tests.java index 598c122c5aa..a57768a1831 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/IncrementalRegression2Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/IncrementalRegression2Tests.java @@ -690,7 +690,6 @@ public void rankTests() throws SQLException { } } - @Test public void testSumCase() { var ccs = this.getCCS(""" @@ -727,6 +726,32 @@ public void testSumCase() { 0 | 0 | 0 | -1"""); } + @Test + public void issue2808() { + // Check the API for blocking until compaction is completed + var ccs = this.getCCS(""" + CREATE TABLE T(id INT, bid INT, ts TIMESTAMP, ts0 TIMESTAMP, s INT); + CREATE VIEW V AS + SELECT id, bid, + SUM( + CASE + WHEN ts >= (ts0 - INTERVAL '180' DAY) + AND NOT s IS NULL THEN 1 + ELSE 0 + END + ) + FROM T GROUP BY id, bid; + """); + ccs.stepWeightOne("", """ + id | bid | sum + ----------------"""); + ccs.blockForCompaction(); + ccs.stepWeightOne("INSERT INTO T VALUES(1, 1, 0, 0, 0);", """ + id | bid | sum + ---------------- + 1 | 1 | 1"""); + ccs.blockForCompaction(); + } @Test public void issue6350a() { diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/BlockForCompaction.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/BlockForCompaction.java new file mode 100644 index 00000000000..c80c244390b --- /dev/null +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/BlockForCompaction.java @@ -0,0 +1,9 @@ +package org.dbsp.sqlCompiler.compiler.sql.tools; + +/** Emit a command to block for compaction */ +public class BlockForCompaction implements IStreamCommand { + @Override + public boolean compatible(IStreamCommand other) { + return true; + } +} diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/CompilerCircuitStream.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/CompilerCircuitStream.java index 1d8a96a9fa7..5d751538307 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/CompilerCircuitStream.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/CompilerCircuitStream.java @@ -76,6 +76,13 @@ public void step(String script, String expected) { this.stream.addPair(input, output); } + /** + * Block the circuit until compaction is finished. + */ + public void blockForCompaction() { + this.stream.addBlockForCompaction(); + } + /** Like step, but every record in the output has weight one, and the * weight column is omitted for the expected output. */ public void stepWeightOne(String script, String expected) { diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/IStreamCommand.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/IStreamCommand.java new file mode 100644 index 00000000000..d8909345e23 --- /dev/null +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/IStreamCommand.java @@ -0,0 +1,7 @@ +package org.dbsp.sqlCompiler.compiler.sql.tools; + +/** A command part of a stream of commands that a test supplies to a circuit */ +public interface IStreamCommand { + /** True if the two stream commands can be applied to the same circuit */ + boolean compatible(IStreamCommand other); +} diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChange.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChange.java index ce7f12f2081..005be0acbf6 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChange.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChange.java @@ -2,7 +2,7 @@ /** A pair of changes, one for inputs and the expected corresponding outputs, * used in a test. */ -public class InputOutputChange { +public class InputOutputChange implements IStreamCommand { /** An input value for every input table. */ public final Change inputs; /** An expected output value for every output view. */ @@ -25,8 +25,11 @@ public Change getOutputs() { return this.outputs; } - public boolean compatible(InputOutputChange change) { - return this.inputs.compatible(change.inputs) && - this.outputs.compatible(change.outputs); + public boolean compatible(IStreamCommand change) { + if (change instanceof InputOutputChange otherChange) { + return this.inputs.compatible(otherChange.inputs) && + this.outputs.compatible(otherChange.outputs); + } + return true; } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChangeStream.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChangeStream.java index 0ae8330c010..e2f75c85ffc 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChangeStream.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/InputOutputChangeStream.java @@ -16,28 +16,35 @@ public class InputOutputChangeStream { /** If non-empty it may be used to permute changes. * In this case outputs changes correspond to the views. */ public final List outputTables; - public final List changes; + public final List commands; public InputOutputChangeStream(List inputTables, List outputTables) { - this.changes = new ArrayList<>(); + this.commands = new ArrayList<>(); this.inputTables = inputTables; this.outputTables = outputTables; } public InputOutputChangeStream() { - this.changes = new ArrayList<>(); + this.commands = new ArrayList<>(); this.inputTables = new ArrayList<>(); this.outputTables = new ArrayList<>(); } + public InputOutputChangeStream addBlockForCompaction() { + // We don't expect "block" to be the first command + Utilities.enforce(! this.commands.isEmpty()); + this.commands.add(new BlockForCompaction()); + return this; + } + public InputOutputChangeStream addChange(InputOutputChange change) { - Utilities.enforce(this.changes.isEmpty() || this.changes.get(0).compatible(change), + Utilities.enforce(this.commands.isEmpty() || this.commands.get(0).compatible(change), () -> "Incompatible change"); Utilities.enforce(this.inputTables.isEmpty() || change.inputs.getSetCount() == this.inputTables.size(), () -> "Change does not have the same number of input tables as specified"); Utilities.enforce(this.outputTables.isEmpty() || change.outputs.getSetCount() == this.outputTables.size(), () -> "Change does not have the same number of output tables as specified"); - this.changes.add(change); + this.commands.add(change); return this; } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/TestCase.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/TestCase.java index 2f438fc65b9..537e8f9959a 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/TestCase.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/TestCase.java @@ -2,6 +2,7 @@ import org.dbsp.sqlCompiler.circuit.DBSPCircuit; import org.dbsp.sqlCompiler.circuit.operator.DBSPSinkOperator; +import org.dbsp.sqlCompiler.compiler.errors.InternalCompilerError; import org.dbsp.sqlCompiler.compiler.errors.UnimplementedException; import org.dbsp.sqlCompiler.compiler.frontend.TableData; import org.dbsp.sqlCompiler.compiler.frontend.calciteCompiler.ProgramIdentifier; @@ -10,21 +11,28 @@ import org.dbsp.sqlCompiler.ir.expression.DBSPApplyExpression; import org.dbsp.sqlCompiler.ir.expression.DBSPApplyMethodExpression; import org.dbsp.sqlCompiler.ir.expression.DBSPBlockExpression; +import org.dbsp.sqlCompiler.ir.expression.DBSPConstructorExpression; import org.dbsp.sqlCompiler.ir.expression.DBSPExpression; import org.dbsp.sqlCompiler.ir.expression.DBSPTupleExpression; import org.dbsp.sqlCompiler.ir.expression.DBSPVariablePath; +import org.dbsp.sqlCompiler.ir.expression.literal.DBSPI32Literal; +import org.dbsp.sqlCompiler.ir.expression.literal.DBSPLiteral; import org.dbsp.sqlCompiler.ir.expression.literal.DBSPStrLiteral; +import org.dbsp.sqlCompiler.ir.expression.literal.DBSPU64Literal; import org.dbsp.sqlCompiler.ir.expression.literal.DBSPUSizeLiteral; import org.dbsp.sqlCompiler.ir.statement.DBSPComment; +import org.dbsp.sqlCompiler.ir.statement.DBSPExpressionStatement; import org.dbsp.sqlCompiler.ir.statement.DBSPLetStatement; import org.dbsp.sqlCompiler.ir.statement.DBSPStatement; import org.dbsp.sqlCompiler.ir.type.DBSPType; +import org.dbsp.sqlCompiler.ir.type.DBSPTypeCode; import org.dbsp.sqlCompiler.ir.type.primitive.DBSPTypeAny; import org.dbsp.sqlCompiler.ir.type.derived.DBSPTypeTuple; import org.dbsp.sqlCompiler.ir.type.primitive.DBSPTypeBool; import org.dbsp.sqlCompiler.ir.type.primitive.DBSPTypeFP; import org.dbsp.sqlCompiler.ir.type.primitive.DBSPTypeString; import org.dbsp.sqlCompiler.ir.type.primitive.DBSPTypeVoid; +import org.dbsp.sqlCompiler.ir.type.user.DBSPTypeUser; import org.dbsp.util.ExplicitShuffle; import org.dbsp.util.IdShuffle; import org.dbsp.util.Linq; @@ -58,7 +66,7 @@ public class TestCase { } boolean hasData() { - return !this.ccs.stream.changes.isEmpty(); + return !this.ccs.stream.commands.isEmpty(); } /** @@ -88,7 +96,6 @@ List createTesterCode( DBSPLetStatement streams = new DBSPLetStatement("streams", cas.getVarReference().field(1)); list.add(streams); - int pair = 0; List inputOrder = this.ccs.stream.inputTables; Shuffle inputShuffle = new IdShuffle(this.ccs.circuit.getInputTables().size()); if (!inputOrder.isEmpty()) { @@ -103,119 +110,135 @@ List createTesterCode( outputShuffle = ExplicitShuffle.computePermutation(outputOrder, outputs); } - for (InputOutputChange changes : this.ccs.stream.changes) { - Change inputs = changes.getInputs(); - inputs = inputs.shuffle(inputShuffle); - // Use id before simplify - Long changeId = inputs.getId(); - inputs = inputs.simplify(this.ccs.compiler); - - TableData[] tableData = new TableData[inputs.getSetCount()]; - for (int i = 0; i < inputs.getSetCount(); i++) - tableData[i] = inputs.getSet(i); - String functionName = "input" + changeId; - DBSPFunction inputFunction = TableData.createInputFunction( - this.ccs.compiler, functionName, tableData, codeDirectory, executionDirectory); - if (!changeFunction.containsKey(changeId)) { - result.add(inputFunction); - changeFunction.put(changeId, inputFunction); - } - - String inputName = "input" + pair; - DBSPLetStatement in = new DBSPLetStatement(inputName, inputFunction.call()); - list.add(in); - - if (!useHandles) - throw new UnimplementedException("Testing for circuits with handles not yet implemented"); - - for (int i = 0; i < tableData.length; i++) { - String function; - DBSPExpression[] args; - var td = tableData[i]; - if (!td.hasPrimaryKey()) { - function = "append_to_collection_handle"; - args = new DBSPExpression[2]; - } else { - function = "append_to_map_handle"; - args = new DBSPExpression[3]; - args[2] = td.keyFunction(); + int pair = 0; + for (IStreamCommand command : this.ccs.stream.commands) { + if (command instanceof BlockForCompaction) { + var compact = new DBSPApplyMethodExpression( + "start_compaction", DBSPTypeAny.getDefault(), cas.getVarReference().field(0)) + .resultUnwrap(); + list.add(new DBSPExpressionStatement(compact)); + var durationType = new DBSPTypeUser(CalciteObject.EMPTY, DBSPTypeCode.USER, "std::time::Duration", false); + var deadline = durationType.constructor("from_secs", new DBSPU64Literal(CalciteObject.EMPTY, 60L, false)); + var block = new DBSPApplyMethodExpression( + "wait_for_compaction", DBSPTypeAny.getDefault(), cas.getVarReference().field(0), deadline) + .resultUnwrap(); + list.add(new DBSPExpressionStatement(block)); + } else if (command instanceof InputOutputChange change) { + Change inputs = change.getInputs(); + inputs = inputs.shuffle(inputShuffle); + // Use id before simplify + Long changeId = inputs.getId(); + inputs = inputs.simplify(this.ccs.compiler); + + TableData[] tableData = new TableData[inputs.getSetCount()]; + for (int i = 0; i < inputs.getSetCount(); i++) + tableData[i] = inputs.getSet(i); + String functionName = "input" + changeId; + DBSPFunction inputFunction = TableData.createInputFunction( + this.ccs.compiler, functionName, tableData, codeDirectory, executionDirectory); + if (!changeFunction.containsKey(changeId)) { + result.add(inputFunction); + changeFunction.put(changeId, inputFunction); } - args[0] = in.getVarReference().field(i).borrow(); - args[1] = streams.getVarReference().field(i).borrow(); - list.add(new DBSPApplyExpression(function, DBSPTypeAny.getDefault(), args).toStatement()); - } - DBSPLetStatement step = - new DBSPLetStatement("_", new DBSPApplyMethodExpression( - "transaction", DBSPTypeAny.getDefault(), cas.getVarReference().field(0)).resultUnwrap()); - list.add(step); - - boolean skipSystemViews = changes.outputs.getSetCount() < this.ccs.circuit.getOutputCount(); - int skippedOutputs = 0; - List sinks = Linq.list(this.ccs.circuit.sinkOperators.values()); - for (int i = 0; i < changes.outputs.getSetCount(); i++) { - for (;;) { - DBSPSinkOperator sink = sinks.get(i + skippedOutputs); - // Skip over system views if we are not checking these - if (!sink.metadata.system || !skipSystemViews) - break; - skippedOutputs++; + + String inputName = "input" + pair; + DBSPLetStatement in = new DBSPLetStatement(inputName, inputFunction.call()); + list.add(in); + + if (!useHandles) + throw new UnimplementedException("Testing for circuits with handles not yet implemented"); + + for (int i = 0; i < tableData.length; i++) { + String function; + DBSPExpression[] args; + var td = tableData[i]; + if (!td.hasPrimaryKey()) { + function = "append_to_collection_handle"; + args = new DBSPExpression[2]; + } else { + function = "append_to_map_handle"; + args = new DBSPExpression[3]; + args[2] = td.keyFunction(); + } + args[0] = in.getVarReference().field(i).borrow(); + args[1] = streams.getVarReference().field(i).borrow(); + list.add(new DBSPApplyExpression(function, DBSPTypeAny.getDefault(), args).toStatement()); } - String message = System.lineSeparator() + - "mvn test -Dtest=" + this.javaTestName + - System.lineSeparator() + this.name; - - Change outputs = changes.getOutputs().shuffle(outputShuffle).simplify(this.ccs.compiler); - DBSPType rowType = outputs.getSetElementType(i); - boolean foundFp = false; - DBSPExpression[] converted = null; - DBSPVariablePath var = null; - if (rowType.is(DBSPTypeTuple.class)) { - // Convert FP values to strings to ensure deterministic comparisons - DBSPTypeTuple tuple = rowType.to(DBSPTypeTuple.class); - converted = new DBSPExpression[tuple.size()]; - var = new DBSPVariablePath("t", tuple.ref()); - for (int index = 0; index < tuple.size(); index++) { - DBSPType fieldType = tuple.getFieldType(index); - if (fieldType.is(DBSPTypeFP.class)) { - String converterFunction = "to_string_" + fieldType.to(DBSPTypeFP.class).shortName() + - fieldType.nullableUnderlineSuffix(); - converted[index] = new DBSPApplyExpression( - converterFunction, DBSPTypeString.varchar(fieldType.mayBeNull), - var.deref().field(index)); - foundFp = true; - } else { - converted[index] = var.deref().field(index).applyCloneIfNeeded(); + DBSPLetStatement step = + new DBSPLetStatement("_", new DBSPApplyMethodExpression( + "transaction", DBSPTypeAny.getDefault(), cas.getVarReference().field(0)).resultUnwrap()); + list.add(step); + + boolean skipSystemViews = change.outputs.getSetCount() < this.ccs.circuit.getOutputCount(); + int skippedOutputs = 0; + List sinks = Linq.list(this.ccs.circuit.sinkOperators.values()); + for (int i = 0; i < change.outputs.getSetCount(); i++) { + for (;;) { + DBSPSinkOperator sink = sinks.get(i + skippedOutputs); + // Skip over system views if we are not checking these + if (!sink.metadata.system || !skipSystemViews) + break; + skippedOutputs++; + } + String message = System.lineSeparator() + + "mvn test -Dtest=" + this.javaTestName + + System.lineSeparator() + this.name; + + Change outputs = change.getOutputs().shuffle(outputShuffle).simplify(this.ccs.compiler); + DBSPType rowType = outputs.getSetElementType(i); + boolean foundFp = false; + DBSPExpression[] converted = null; + DBSPVariablePath var = null; + if (rowType.is(DBSPTypeTuple.class)) { + // Convert FP values to strings to ensure deterministic comparisons + DBSPTypeTuple tuple = rowType.to(DBSPTypeTuple.class); + converted = new DBSPExpression[tuple.size()]; + var = new DBSPVariablePath("t", tuple.ref()); + for (int index = 0; index < tuple.size(); index++) { + DBSPType fieldType = tuple.getFieldType(index); + if (fieldType.is(DBSPTypeFP.class)) { + String converterFunction = "to_string_" + fieldType.to(DBSPTypeFP.class).shortName() + + fieldType.nullableUnderlineSuffix(); + converted[index] = new DBSPApplyExpression( + converterFunction, DBSPTypeString.varchar(fieldType.mayBeNull), + var.deref().field(index)); + foundFp = true; + } else { + converted[index] = var.deref().field(index).applyCloneIfNeeded(); + } } } + // else: TODO: handle Vec<> values with FP values inside. + // Currently we don't have any tests with this case. + + TableData expected = outputs.getSet(i); + DBSPExpression viewContents = expected.createOutput(this.ccs.compiler, "out" + testNumber, + codeDirectory, executionDirectory); + DBSPExpression actual = new DBSPApplyExpression("read_output_spine", DBSPTypeAny.getDefault(), + streams.getVarReference().field(change.inputs.getSetCount() + i + skippedOutputs).borrow()); + var produced = new DBSPLetStatement("produced_result", actual); + list.add(produced); + list.add(new DBSPComment("println!(\"result={:?}\", produced_result);")); + actual = produced.getVarReference(); + + if (foundFp) { + DBSPExpression convertedValue = new DBSPTupleExpression(converted); + DBSPExpression converter = convertedValue.closure(var); + DBSPVariablePath converterVar = new DBSPVariablePath("converter", DBSPTypeAny.getDefault()); + list.add(new DBSPLetStatement(converterVar.variable, converter)); + viewContents = new DBSPApplyExpression("zset_map", convertedValue.getType(), viewContents.borrow(), converterVar); + actual = new DBSPApplyExpression("zset_map", convertedValue.getType(), actual.borrow(), converterVar); + } + DBSPStatement compare = + new DBSPApplyExpression("assert!", DBSPTypeVoid.INSTANCE, + new DBSPApplyExpression("must_equal", + new DBSPTypeBool(CalciteObject.EMPTY, false), + actual.borrow(), viewContents.borrow()), + new DBSPStrLiteral(message, true)).toStatement(); + list.add(compare); } - // else: TODO: handle Vec<> values with FP values inside. - // Currently we don't have any tests with this case. - - TableData expected = outputs.getSet(i); - DBSPExpression viewContents = expected.createOutput(this.ccs.compiler, "out" + testNumber, - codeDirectory, executionDirectory); - DBSPExpression actual = new DBSPApplyExpression("read_output_spine", DBSPTypeAny.getDefault(), - streams.getVarReference().field(changes.inputs.getSetCount() + i + skippedOutputs).borrow()); - var produced = new DBSPLetStatement("produced_result", actual); - list.add(produced); - list.add(new DBSPComment("println!(\"result={:?}\", produced_result);")); - actual = produced.getVarReference(); - - if (foundFp) { - DBSPExpression convertedValue = new DBSPTupleExpression(converted); - DBSPExpression converter = convertedValue.closure(var); - DBSPVariablePath converterVar = new DBSPVariablePath("converter", DBSPTypeAny.getDefault()); - list.add(new DBSPLetStatement(converterVar.variable, converter)); - viewContents = new DBSPApplyExpression("zset_map", convertedValue.getType(), viewContents.borrow(), converterVar); - actual = new DBSPApplyExpression("zset_map", convertedValue.getType(), actual.borrow(), converterVar); - } - DBSPStatement compare = - new DBSPApplyExpression("assert!", DBSPTypeVoid.INSTANCE, - new DBSPApplyExpression("must_equal", - new DBSPTypeBool(CalciteObject.EMPTY, false), - actual.borrow(), viewContents.borrow()), - new DBSPStrLiteral(message, true)).toStatement(); - list.add(compare); + } else { + throw new InternalCompilerError("Unexpected test command"); } pair++; } From 20121b59b482291c1c8c396919ff21e7a33a4de9 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Sat, 20 Jun 2026 22:18:36 -0700 Subject: [PATCH 3/7] [SQL] Use the nicer formatting function for test outputs where possible Signed-off-by: Mihai Budiu --- .../sqlCompiler/compiler/sql/WindowTests.java | 4 +- .../compiler/sql/functions/FunctionsTest.java | 98 ++--- .../compiler/sql/mysql/DateFormatsTests.java | 4 +- .../sql/mysql/TimestampDiffTests.java | 20 +- .../compiler/sql/mysql/VarbinaryTests.java | 18 +- .../sql/postgres/PostgresAggregatesTests.java | 6 +- .../sql/postgres/PostgresArrayTests.java | 4 +- .../sql/postgres/PostgresBoolTests.java | 26 +- .../sql/postgres/PostgresCaseTests.java | 16 +- .../sql/postgres/PostgresCollateTests.java | 7 +- .../sql/postgres/PostgresDateTests.java | 271 +++++-------- .../sql/postgres/PostgresFloat4Tests.java | 4 +- .../postgres/PostgresFloat8Part2Tests.java | 6 +- .../sql/postgres/PostgresFloat8Tests.java | 8 +- .../postgres/PostgresGroupingSetsTests.java | 2 +- .../sql/postgres/PostgresInt2Tests.java | 2 +- .../sql/postgres/PostgresInt4Tests.java | 2 +- .../sql/postgres/PostgresInt8Tests.java | 4 +- .../sql/postgres/PostgresIntervalTests.java | 26 +- .../sql/postgres/PostgresLimitTests.java | 4 +- .../sql/postgres/PostgresNumericTests.java | 8 +- .../sql/postgres/PostgresStringTests.java | 43 ++- .../sql/postgres/PostgresTimeTests.java | 8 +- .../sql/postgres/PostgresWindowTests.java | 64 +-- .../compiler/sql/quidem/AggScottTests.java | 40 +- .../compiler/sql/quidem/AggTests.java | 230 +++++------ .../compiler/sql/quidem/AsofTests.java | 6 +- .../compiler/sql/quidem/BigQueryTests.java | 42 +- .../compiler/sql/quidem/CalciteJdbcTests.java | 78 ++-- .../compiler/sql/quidem/FoodmartTests.java | 19 +- .../compiler/sql/quidem/HRWinAggTests.java | 4 +- .../compiler/sql/quidem/MiscTests.java | 10 +- .../compiler/sql/quidem/OperatorTests.java | 20 +- .../compiler/sql/quidem/OuterTests.java | 244 ++++++------ .../compiler/sql/quidem/PostgresTests.java | 4 +- .../compiler/sql/quidem/RedshiftTests.java | 8 +- .../compiler/sql/quidem/SelectTests.java | 2 +- .../compiler/sql/quidem/SortHrTests.java | 10 +- .../compiler/sql/quidem/SortTests.java | 98 ++--- .../compiler/sql/quidem/StreamTests.java | 126 +++--- .../compiler/sql/quidem/StructTests.java | 20 +- .../compiler/sql/quidem/SubQueryTests.java | 64 +-- .../compiler/sql/quidem/WinAggPostTests.java | 364 +++++++++--------- .../compiler/sql/quidem/WinAggTests.java | 4 +- .../compiler/sql/simple/AggregateTests.java | 22 +- .../sql/simple/ArrayFunctionsTests.java | 58 +-- .../sql/simple/CalciteSqlOperatorTest.java | 11 +- .../compiler/sql/simple/CastTests.java | 18 +- .../sql/simple/DateArithmeticTests.java | 12 +- .../sql/simple/LateralAliasTests.java | 2 +- .../compiler/sql/simple/OuterJoinTests.java | 12 +- .../compiler/sql/simple/PivotTests.java | 76 ++-- .../compiler/sql/simple/Regression1Tests.java | 13 +- .../compiler/sql/simple/Regression2Tests.java | 14 +- .../compiler/sql/simple/Regression3Tests.java | 6 +- .../compiler/sql/simple/RegressionTests.java | 2 +- .../compiler/sql/simple/StringTests.java | 2 +- .../compiler/sql/simple/StructTests.java | 6 +- .../sql/simple/TimeArithmeticTests.java | 8 +- .../compiler/sql/simple/TimeTests.java | 2 +- .../compiler/sql/simple/TinyintTests.java | 2 +- .../sql/simple/TrigonometryTests.java | 48 +-- .../compiler/sql/simple/VariantTests.java | 4 +- .../compiler/sql/tools/SqlIoTest.java | 4 + 64 files changed, 1144 insertions(+), 1226 deletions(-) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/WindowTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/WindowTests.java index 2902d472540..5e32b59472d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/WindowTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/WindowTests.java @@ -159,7 +159,7 @@ public void testQ0() { PermutationTest test = q0.createTest(); List permutations = test.generateAll(); for (var t : permutations) { - this.qs(t, TestOptimizations.Optimized); + this.qst(t, TestOptimizations.Optimized); } } @@ -168,7 +168,7 @@ public void testQ1() { PermutationTest test = q1.createTest(); List permutations = test.generateAll(); for (var t : permutations) { - this.qs(t, TestOptimizations.Optimized); + this.qst(t, TestOptimizations.Optimized); } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/functions/FunctionsTest.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/functions/FunctionsTest.java index 7f44b6b58b8..02e2f2fdee1 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/functions/FunctionsTest.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/functions/FunctionsTest.java @@ -35,25 +35,25 @@ public void testTypeError() { @Test public void testBround() { - this.qs(""" + this.qst(""" SELECT BROUND(1.123, 0), BROUND(1.123, 1), BROUND(1.123, 2), BROUND(1.123, 3); a | b | c | d ------------------------ 1 | 1.1 | 1.12 | 1.123 (1 row) - + SELECT BROUND(1.15, 1), BROUND(1.25, 1), BROUND(1.55, 1); a | b | c ----------------- 1.2 | 1.2 | 1.6 (1 row) - + SELECT BROUND(11.15, -1), BROUND(15.25, -1), BROUND(25.55, -1); a | b | c -------------- 10 | 20 | 30 (1 row) - + SELECT BROUND(11, -4), BROUND(11.25e0, 1), BROUND(0, CAST(1 AS TINYINT)); a | b | c ---------------- @@ -63,7 +63,7 @@ public void testBround() { @Test public void testBetween() { - this.qs(""" + this.qst(""" SELECT TIMESTAMP '2020-02-02 10:00:00' between TIMESTAMP '2020-02-02 09:00:00' and TIMESTAMP '2020-02-02 11:00:00'; result -------- @@ -126,7 +126,7 @@ public void testIssue1450() { @Test public void issue1520() { - this.qs(""" + this.qst(""" select 3.456::decimal(25, 3) + 1.123::decimal(4, 0); ?column? ---------- @@ -228,7 +228,7 @@ public void unicodeStringTests() { @Test public void testLeft() { - this.qs(""" + this.qst(""" SELECT LEFT('string', 1); result --------- @@ -246,13 +246,13 @@ public void testLeft() { --------- string (1 row) - + SELECT LEFT('string', -2); result --------- \s (1 row) - + SELECT LEFT('string', NULL); result --------- @@ -262,7 +262,7 @@ public void testLeft() { @Test public void testRight() { - this.qs(""" + this.qst(""" SELECT RIGHT('string', 1); result --------- @@ -280,13 +280,13 @@ public void testRight() { --------- string (1 row) - + SELECT RIGHT('string', -2); result --------- \s (1 row) - + SELECT RIGHT('string', NULL); result --------- @@ -296,13 +296,13 @@ public void testRight() { @Test public void testBinaryCast() { - this.qs(""" + this.qst(""" SELECT CAST('1234567890' AS VARBINARY) as val; val ----- 31323334353637383930 (1 row) - + SELECT '1234567890'::VARBINARY as val; val ----- @@ -328,7 +328,7 @@ public void issue1192() { // INT::MIN % -1 instead of just returning 0 @Test public void issue1187modulo() { - this.qs( + this.qst( """ SELECT (-128)::tinyint % (-1)::tinyint as x; x @@ -493,7 +493,7 @@ public void testLeftNull() { @Test public void testConcat() { - this.qs(""" + this.qst(""" SELECT CONCAT('string', 1); result --------- @@ -539,7 +539,7 @@ public void testCoalesce() { // Calcite rounds differently from Postgres and other databases @Test public void testRounding() { - this.qs(""" + this.qst(""" select CAST((CAST('1234.1264' AS DECIMAL(8, 4))) AS DECIMAL(6, 2)); cast ------ @@ -683,7 +683,7 @@ public void testDecimalErrors() { @Test public void testLn() { - this.qs(""" + this.qst(""" SELECT ROUND(ln(2e0), 12); ln ---- @@ -701,7 +701,7 @@ public void testLn() { @Test public void testIsInf() { - this.qs( + this.qst( """ SELECT IS_INF(null); is_inf @@ -770,7 +770,7 @@ public void testIsInf() { @Test public void testIsInfReal() { - this.qs(""" + this.qst(""" -- f64::MAX SELECT is_inf(1.7976931348623157e308::real); real @@ -790,7 +790,7 @@ public void testIsInfReal() { @Test public void testIsNan() { - this.qs(""" + this.qst(""" SELECT is_nan(null); is_nan -------- @@ -838,7 +838,7 @@ public void testIsNan() { @Test public void testPower() { - this.qs(""" + this.qst(""" SELECT power(2e0, 2); power ------- @@ -904,7 +904,7 @@ public void testPower() { @Test public void testSqrtDouble() { - this.qs(""" + this.qst(""" SELECT sqrt(9e0); sqrt ------ @@ -928,7 +928,7 @@ public void testRoundDecimalDecimal() { @Test public void testRound() { - this.qs(""" + this.qst(""" select round(15.1); round(15.1) ------------ @@ -1450,7 +1450,7 @@ public void testRound() { @Test public void testTruncate() { - this.qs(""" + this.qst(""" select truncate(5678.123451); truncate(5678.123451) ----- @@ -1746,7 +1746,7 @@ public void testTruncate() { @Test public void testRoundTruncateEdgeCases() { // Calcite normalizes the sign here - this.qs(""" + this.qst(""" select truncate(-0.00123::DOUBLE, 2); truncate ---------- @@ -1794,7 +1794,7 @@ public void testRoundBigInt() { @Test public void testExp() { - this.qs(""" + this.qst(""" SELECT EXP(0.0); exp ----- @@ -1830,7 +1830,7 @@ public void testExp() { @Test public void testExpEdgeCase() { - this.qs(""" + this.qst(""" -- changed the type from numeric to double -- therefore the value has also slightly changed -- cases that used to generate inaccurate results in Postgres @@ -1845,7 +1845,7 @@ public void testExpEdgeCase() { @Test public void testGunzip() { - this.qs(""" + this.qst(""" SELECT GUNZIP(x'1f8b08000000000000ff4b4bcd49492d4a0400218115ac07000000'::bytea); gunzip ------------ @@ -1881,13 +1881,13 @@ public void testGunzip() { @Test public void testNulls() { - this.qs(""" + this.qst(""" SELECT sign(null); sign ------------ null (1 row) - + SELECT st_distance(null, st_point(0,0)); sign ------------ @@ -1898,7 +1898,7 @@ public void testNulls() { @Test public void testMD5() { - this.qs(""" + this.qst(""" SELECT MD5(x'0123456789ABCDEF'); md5 ------------ @@ -1934,7 +1934,7 @@ public void testGunzipRuntimeFail() { @Test public void testIssue1505() { - this.qs(""" + this.qst(""" SELECT ROUND(123.1234::DOUBLE, 2); round ------- @@ -1964,7 +1964,7 @@ public void testIssue1505() { @Test public void testRlike() { - this.qs(""" + this.qst(""" SELECT RLIKE('string', 's..i.*'); rlike ------- @@ -2004,7 +2004,7 @@ public void testRlike() { @Test public void testSequence() { - this.qs(""" + this.qst(""" SELECT SEQUENCE(1, 10); sequence ---------- @@ -2088,7 +2088,7 @@ public void testSequence() { @Test public void testCeilInt() { - this.qs(""" + this.qst(""" SELECT ceil(2::tinyint); ceil ------ @@ -2148,7 +2148,7 @@ public void testCeilInt() { @Test public void testFloorInt() { - this.qs(""" + this.qst(""" SELECT floor(2::tinyint); floor ------ @@ -2208,44 +2208,44 @@ public void testFloorInt() { @Test public void testBlackboxFunction() { - this.qs(""" + this.qst(""" SELECT blackbox(1); blackbox ---------- 1 (1 row) - + SELECT blackbox('blah'); blackbox ---------- blah (1 row) - + SELECT blackbox(true); blackbox ---------- true (1 row) - + SELECT blackbox(1e0); blackbox ---------- 1e0 (1 row) - + SELECT blackbox(1.0); blackbox ---------- 1.0 (1 row) - + SELECT blackbox(vals) from arr_table; blackbox ---------- {1,2,3} {1,2,3} (2 rows) - + SELECT blackbox(1.0) as c0, blackbox(true) as c1; c0 | c1 -----+----- @@ -2257,25 +2257,25 @@ public void testBlackboxFunction() { @Test public void testInitcapSpaces() { - this.qs(""" + this.qst(""" SELECT INITCAP_SPACES('hi man'); r --- Hi Man (1 row) - + SELECT INITCAP_SPACES('hi THOMAS-SON'); r --- Hi Thomas-son (1 row) - + SELECT INITCAP_SPACES(NULL); r --- NULL (1 row) - + SELECT INITCAP('ggj12341jhg12341=-012341asdf'); r --- @@ -2287,7 +2287,7 @@ public void testInitcapSpaces() { public void issue4559() { var ccs = this.getCCS(""" CREATE TABLE str_tbl(id INT, str VARCHAR); - + CREATE MATERIALIZED VIEW trim_legal AS SELECT TRIM(trailing 'い' from str) FROM str_tbl;"""); diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/DateFormatsTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/DateFormatsTests.java index 63faa11842c..22f2cd957cc 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/DateFormatsTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/DateFormatsTests.java @@ -38,7 +38,7 @@ public void testFormat() { @Test public void testParseDate() { - this.qs(""" + this.qst(""" SELECT PARSE_DATE(' %Y-%m-%d', ' 2020-10-01'); d --- @@ -110,7 +110,7 @@ public void testFormat2() { public void testCorners() { // Year 0 is not legal, replaced with year 1 // %Y in MySql is %y - this.qs(""" + this.qst(""" SELECT format_date('%Y-%m', DATE '2020-10-10'); valid_date ------------ diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/TimestampDiffTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/TimestampDiffTests.java index 130fb272ab7..6423ba0a4ef 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/TimestampDiffTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/TimestampDiffTests.java @@ -25,7 +25,7 @@ public void issue4651() { @Test public void issue4610() { - this.qs(""" + this.qst(""" SELECT CAST(TIME '10:00:00' AS TIMESTAMP); t --- @@ -49,7 +49,7 @@ public void issue4610() { // https://github.com/mysql/mysql-server/blob/mysql-test/r/func_time.result#L715 @Test public void testTimestampDiff0() { - this.qs(""" + this.qst(""" select timestampdiff(MONTH, DATE '2001-02-01', DATE '2001-05-01') as a; a ----- @@ -102,7 +102,7 @@ public void testTimestampDiff0() { @Test public void testDateDiff() { // same as testTimestampDiff0 above, but using DATEDIFF as a function - this.qs(""" + this.qst(""" select datediff(MONTH, DATE '2001-02-01', DATE '2001-05-01') as a; a ----- @@ -155,7 +155,7 @@ public void testDateDiff() { @Test public void testDateAdd() { // This is manually written and validated using MySQL - this.qs(""" + this.qst(""" select timestampadd(MONTH, 3, DATE '2001-02-01') as a; a ----- @@ -207,7 +207,7 @@ public void testDateAdd() { @Test public void testDateDayDiff() { - this.qs(""" + this.qst(""" select timestampdiff(SQL_TSI_DAY, DATE '1986-02-01', DATE '1986-03-01') as a1, timestampdiff(SQL_TSI_DAY, DATE '1900-02-01', DATE '1900-03-01') as a2, timestampdiff(SQL_TSI_DAY, DATE '1996-02-01', DATE '1996-03-01') as a3, @@ -220,7 +220,7 @@ select timestampdiff(SQL_TSI_DAY, DATE '1986-02-01', DATE '1986-03-01') as a1, @Test public void testTimestampDiff() { - this.qs(""" + this.qst(""" select timestampdiff(SQL_TSI_MINUTE, TIMESTAMP '2001-02-01 12:59:59', TIMESTAMP '2001-05-01 12:58:59') as a; a ----- @@ -380,7 +380,7 @@ public void testTimestampDiff() { @Test public void testMonthDiff() { - this.qs(""" + this.qst(""" select timestampdiff(month, DATE '2004-09-11', DATE '2004-09-11'); timestampdiff(month, DATE '2004-09-11', DATE '2004-09-11') ----- @@ -487,7 +487,7 @@ public void testMonthDiff() { @Test public void diffTests() { - this.qs(""" + this.qst(""" select (DATE '2024-01-01' - DATE '2023-12-31') DAYS; days ------ @@ -509,7 +509,7 @@ public void diffTests() { @Test public void diffTests2() { - this.qs(""" + this.qst(""" select TIMESTAMPDIFF(DAY, DATE '2024-01-01', DATE '2023-12-31'); days ------ @@ -532,7 +532,7 @@ public void diffTests2() { @Test public void issue5986() { - this.qs(""" + this.qst(""" SELECT CONVERT_TIMEZONE('America/New_York', 'America/Los_Angeles', TIMESTAMP '2008-03-05 12:25:29'); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/VarbinaryTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/VarbinaryTests.java index 8c46606e3e5..251a65d817a 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/VarbinaryTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/mysql/VarbinaryTests.java @@ -116,7 +116,7 @@ public void testToInt() { @Test public void testConcatBinary() { - this.qs(""" + this.qst(""" SELECT x'0a' || x'bc'; result ------ @@ -145,7 +145,7 @@ public void testConcatBinary() { // While Postgres doesn't allow negative "overlay from" value, we treat it as 0 @Test public void testOverlay() { - this.qs(""" + this.qst(""" SELECT overlay(x'1234567890'::bytea placing x'0203' from 2 for 3); overlay --------- @@ -186,7 +186,7 @@ public void testOverlay() { @Test public void testIntToBinaryCasts() { - this.qs(""" + this.qst(""" SELECT CAST(10 AS BINARY(4)); r --- @@ -256,7 +256,7 @@ public void testIntToBinaryCasts() { @Test public void testCast() { - this.qs(""" + this.qst(""" SELECT CAST('abcd1234' AS VARBINARY); r --- @@ -278,7 +278,7 @@ public void testCast() { @Test public void testLeftAndRight() { - this.qs(""" + this.qst(""" SELECT right(x'ABCdef', 1); result ------- @@ -349,7 +349,7 @@ public void testLeftAndRight() { // Tested on Postgres @Test public void testSubstring() { - this.qs(""" + this.qst(""" SELECT substring(x'123456', 0); substring ----------- @@ -389,7 +389,7 @@ public void testSubstring() { @Test public void testSubstringFail() { - this.qs(""" + this.qst(""" SELECT substring(x'123456', 3, -1); result ------ @@ -399,7 +399,7 @@ public void testSubstringFail() { @Test public void testOctetLength() { - this.qs(""" + this.qst(""" SELECT octet_length(x'123456'::bytea); length -------- @@ -429,7 +429,7 @@ public void testOctetLength() { @Test public void testPosition() { - this.qs(""" + this.qst(""" SELECT position(x'20' IN x'102023'::bytea); position ---------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresAggregatesTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresAggregatesTests.java index 9548a18267e..0a6737ad704 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresAggregatesTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresAggregatesTests.java @@ -34,7 +34,7 @@ CREATE TABLE bool_test( @Test public void testBitAggs() { - this.qs(""" + this.qst(""" -- empty case SELECT BIT_AND(i2), @@ -43,7 +43,7 @@ public void testBitAggs() { FROM (SELECT * FROM bitwise_test WHERE FALSE); a | o | x ---+---+--- - | | \s + | | (1 row) SELECT @@ -74,7 +74,7 @@ public void testBitAggs() { @Test public void testBoolAgg() { - this.qs(""" + this.qst(""" -- empty case SELECT BOOL_AND(b1) AS "n0", diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresArrayTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresArrayTests.java index 8d01e4b1511..9823ce08f0c 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresArrayTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresArrayTests.java @@ -9,7 +9,7 @@ public class PostgresArrayTests extends SqlIoTest { @Test public void testSplit() { // Renamed 'string_to_array' to 'split' - this.qs(""" + this.qst(""" select split('1|2|3', '|'); split ----------------- @@ -82,7 +82,7 @@ public void testSplit() { @Test public void testArrayToString() { // In Calcite array_to_string requires all arguments to be strings - this.qs(""" + this.qst(""" select array_to_string(NULL::TEXT ARRAY, ',') IS NULL; ?column? ---------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresBoolTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresBoolTests.java index 083b0f19587..54290b769b4 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresBoolTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresBoolTests.java @@ -82,7 +82,7 @@ public void testFalse() { @Test public void testIs() { - this.q(""" + this.qst(""" SELECT d, b IS TRUE AS istrue, @@ -94,15 +94,16 @@ public void testIs() { FROM booltbl3; d | istrue | isnottrue | isfalse | isnotfalse | isunknown | isnotunknown -------+--------+-----------+---------+------------+-----------+-------------- - true| t | f | f | t | f | t - false| f | t | t | f | f | t - null| f | t | f | t | t | f"""); + true | t | f | f | t | f | t + false | f | t | t | f | f | t + null | f | t | f | t | t | f + (3 rows)"""); } @Test public void testShortcut() { // This is not from Postgres - this.q(""" + this.qst(""" SELECT v0, v1, v0 OR v1 FROM (SELECT b AS v0 FROM BOOLTBL3) CROSS JOIN (SELECT b as v1 FROM BOOLTBL3); v0 | v1 | v0 OR v1 -------------------- @@ -114,8 +115,9 @@ public void testShortcut() { null| f |null t |null| t f |null|null - null|null|null"""); - this.q(""" + null|null|null + (9 rows) + SELECT v0, v1, v0 AND v1 FROM (SELECT b AS v0 FROM BOOLTBL3) CROSS JOIN (SELECT b as v1 FROM BOOLTBL3); v0 | v1 | v0 AND v1 -------------------- @@ -127,19 +129,21 @@ public void testShortcut() { null| f | f t |null|null f |null| f - null|null|null"""); - this.q(""" + null|null|null + (9 rows) + SELECT v0, NOT v0 FROM (SELECT b AS v0 FROM BOOLTBL3); v0 | NOT v0 --------------- t | f f | t - null|null"""); + null|null + (3 rows)"""); } @Test public void testBool() { - this.qs(""" + this.qst(""" SELECT istrue AND isnul AND istrue FROM booltbl4; ?column? ---------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCaseTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCaseTests.java index ae00a4b4f1d..04cb44d0e4c 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCaseTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCaseTests.java @@ -32,14 +32,14 @@ CREATE TABLE CASE2_TBL ( @Test public void testCase() { - this.qs(""" + this.qst(""" SELECT '3' AS "One", CASE WHEN 1 < 2 THEN 3 END AS "Simple WHEN"; One | Simple WHEN -----+------------- - 3| 3 + 3 | 3 (1 row) SELECT '' AS "One", @@ -48,7 +48,7 @@ public void testCase() { END AS "Simple default"; One | Simple default --------+---------------- - | \s + | (1 row) SELECT '3' AS "One", @@ -58,7 +58,7 @@ public void testCase() { END AS "Simple ELSE"; One | Simple ELSE -----+------------- - 3| 3 + 3 | 3 (1 row) SELECT '4' AS "One", @@ -68,7 +68,7 @@ public void testCase() { END AS "ELSE default"; One | ELSE default -----+-------------- - 4| 4 + 4 | 4 (1 row) SELECT '6' AS "One", @@ -79,7 +79,7 @@ public void testCase() { END AS "Two WHEN with default"; One | Two WHEN with default -----+----------------------- - 6| 6 + 6 | 6 (1 row) SELECT '7' AS "None", @@ -87,7 +87,7 @@ public void testCase() { END AS "NULL on no matches"; None | NULL on no matches ------+-------------------- - 7| \s + 7 | (1 row) -- Constant-expression folding shouldn't evaluate unreachable subexpressions @@ -107,7 +107,7 @@ public void testCase() { @Test public void testCases2() { // changed error to null output - this.qs(""" + this.qst(""" SELECT CASE WHEN i > 100 THEN 1/0 ELSE 0 END FROM case_tbl; case ------ diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCollateTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCollateTests.java index c2f70adefab..b4bc937200f 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCollateTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresCollateTests.java @@ -23,11 +23,12 @@ CREATE TABLE collate_test10 ( @Test public void testUpperLower() { - this.q(""" + this.qst(""" SELECT a, lower(x), lower(y), upper(x), upper(y), initcap(x), initcap(y) FROM collate_test10; a | lower | lower | upper | upper | initcap | initcap ---+-------+-------+-------+-------+---------+--------- - 1 | hij| hij| HIJ| HIJ| Hij| Hij - 2 | hij| hij| HIJ| HIJ| Hij| Hij"""); + 1 | hij | hij | HIJ | HIJ | Hij | Hij + 2 | hij | hij | HIJ | HIJ | Hij | Hij + (2 rows)"""); } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresDateTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresDateTests.java index 98c0c28782b..db8870bf81d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresDateTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresDateTests.java @@ -244,101 +244,68 @@ public void testExtract() { } @Test - public void testEpoch() { - this.q(""" + public void testExtract1() { + this.qst(""" SELECT EXTRACT(EPOCH FROM DATE '1970-01-01'); extract --------- - 0"""); - } + 0 + (1 row) - @Test - public void testCentury() { - this.q(""" SELECT EXTRACT(CENTURY FROM DATE '0001-01-01'); extract --------- - 1"""); - } - - @Test - public void testCentury1() { - this.q(""" + 1 + (1 row) + SELECT EXTRACT(CENTURY FROM DATE '1900-12-31'); extract --------- - 19"""); - } - - @Test - public void testCentury2() { - this.q(""" + 19 + (1 row) + SELECT EXTRACT(CENTURY FROM DATE '1901-01-01'); extract --------- - 20"""); - } + 20 + (1 row) - @Test - public void testCentury3() { - this.q(""" SELECT EXTRACT(CENTURY FROM DATE '2000-12-31'); extract --------- - 20"""); - } + 20 + (1 row) - @Test - public void testCentury4() { - this.q(""" SELECT EXTRACT(CENTURY FROM DATE '2001-01-01'); extract --------- - 21"""); - } - - @Test - public void testMillennium() { - this.q(""" + 21 + (1 row) + SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01'); extract --------- - 1"""); - } + 1 + (1 row) - @Test - public void testMillennium1() { - this.q(""" SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31'); extract --------- - 1"""); - } + 1 + (1 row) - @Test - public void testMillennium2() { - this.q(""" SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31'); extract --------- - 2"""); - } - - // CURRENT_DATE not supported - // SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True; -- true - - @Test - public void testMillennium3() { - this.q(""" + 2 + (1 row) + SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01'); extract --------- - 3"""); - } + 3 + (1 row) - @Test - public void testDecade() { - this.qs(""" SELECT EXTRACT(DECADE FROM DATE '1994-12-25'); extract --------- @@ -355,205 +322,139 @@ public void testDecade() { extract --------- 0 - (1 row)"""); - } - - @Test - public void testMicroseconds() { - this.q(""" + (1 row) + SELECT EXTRACT(MICROSECOND FROM DATE '2020-08-11'); extract --------- - 0"""); - } + 0 + (1 row) - @Test - public void testMilliseconds() { - this.q(""" SELECT EXTRACT(MILLISECOND FROM DATE '2020-08-11'); extract --------- - 0"""); - } - - @Test - public void testSeconds() { - this.q(""" + 0 + (1 row) + SELECT EXTRACT(SECOND FROM DATE '2020-08-11'); extract --------- - 0"""); - } + 0 + (1 row) - @Test - public void testSeconds0() { - this.q(""" SELECT SECOND(DATE '2020-08-11'); extract --------- - 0"""); - } - - @Test - public void testMinutes() { - this.q(""" + 0 + (1 row) + SELECT EXTRACT(MINUTE FROM DATE '2020-08-11'); extract --------- - 0"""); - } - - @Test - public void testMinutes1() { - this.q(""" + 0 + (1 row) + SELECT MINUTE(DATE '2020-08-11'); extract --------- - 0"""); - } - - @Test - public void testHour() { - this.q(""" + 0 + (1 row) + SELECT EXTRACT(HOUR FROM DATE '2020-08-11'); extract --------- - 0"""); - } - - @Test - public void testHour1() { - this.q(""" + 0 + (1 row) + SELECT HOUR(DATE '2020-08-11'); extract --------- - 0"""); - } + 0 + (1 row) - @Test - public void testDay() { - this.q(""" SELECT EXTRACT(DAY FROM DATE '2020-08-11'); extract --------- - 11"""); - } + 11 + (1 row) - @Test - public void testDay1() { - this.q(""" SELECT DAYOFMONTH(DATE '2020-08-11'); extract --------- - 11"""); - } + 11 + (1 row) - @Test - public void testMonth() { - this.q(""" SELECT EXTRACT(MONTH FROM DATE '2020-08-11'); extract --------- - 8"""); - } + 8 + (1 row) - @Test - public void testMonth1() { - this.q(""" SELECT MONTH(DATE '2020-08-11'); extract --------- - 8"""); - } - - @Test - public void testYear() { - this.q(""" + 8 + (1 row) + SELECT EXTRACT(YEAR FROM DATE '2020-08-11'); extract --------- - 2020"""); - } + 2020 + (1 row) - @Test - public void testYear1() { - this.q(""" SELECT YEAR(DATE '2020-08-11'); extract --------- - 2020"""); - } + 2020 + (1 row) - @Test - public void testDecade5() { - this.q(""" SELECT EXTRACT(DECADE FROM DATE '2020-08-11'); extract --------- - 202"""); - } + 202 + (1 row) - @Test - public void testCentury5() { - this.q(""" SELECT EXTRACT(CENTURY FROM DATE '2020-08-11'); extract --------- - 21"""); - } - - @Test - public void testMillennium5() { - this.q(""" + 21 + (1 row) + SELECT EXTRACT(MILLENNIUM FROM DATE '2020-08-11'); extract --------- - 3"""); - } - - @Test - public void testIsoYear() { - this.q(""" + 3 + (1 row) + SELECT EXTRACT(ISOYEAR FROM DATE '2020-08-11'); extract --------- - 2020"""); - } - - @Test - public void testQuarter() { - this.q(""" + 2020 + (1 row) + SELECT EXTRACT(QUARTER FROM DATE '2020-08-11'); extract --------- - 3"""); - } - - @Test - public void testWeek() { - this.q(""" + 3 + (1 row) + SELECT EXTRACT(WEEK FROM DATE '2020-08-11'); extract --------- - 33"""); - } + 33 + (1 row) - @Test - public void testDow() { - this.q(""" SELECT EXTRACT(DOW FROM DATE '2020-08-11'); extract --------- - 3"""); - } + 3 + (1 row) - @Test - public void testDow2() { - this.q(""" SELECT DAYOFWEEK(DATE '2020-08-11'); extract --------- - 3"""); + 3 + (1 row)"""); } /* @@ -599,7 +500,7 @@ public void testDoy() { public void testDateTrunc() { // In the BigQuery library there is a DATE_TRUNC, but arguments are swapped // I added many more tests - this.qs(""" + this.qst(""" SELECT DATE_TRUNC(DATE '1970-03-20', MILLENNIUM); date_trunc -------------------------- @@ -693,7 +594,7 @@ public void testDateTrunc() { @Test public void testLimitTimestamps() { - this.qs(""" + this.qst(""" SELECT TIMESTAMP '9999-12-12 23:59:59', TIMESTAMP '0001-01-01 00:00:00'; ts0 | ts1 ----------- @@ -704,7 +605,7 @@ public void testLimitTimestamps() { @Test public void testTimeststampTrunc() { // Not in Postgres - this.qs(""" + this.qst(""" SELECT timestamp_trunc(TIMESTAMP '1970-03-20 04:30:00.00000', MILLENNIUM); timestamp_trunc -------------------------- @@ -763,7 +664,7 @@ public void testTimeststampTrunc() { @Test public void testTimeTrunc() { // Not in Postgres - this.qs(""" + this.qst(""" SELECT time_trunc(time '12:34:56.78', hour); trunc -------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat4Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat4Tests.java index 8da1edd8579..52d2254a804 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat4Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat4Tests.java @@ -149,7 +149,7 @@ public void testFPTable() { @Test public void testComp() { - this.qs(""" + this.qst(""" SELECT f.* FROM FLOAT4_TBL f WHERE f.f1 <> '1004.3'; f1 --------------- @@ -203,7 +203,7 @@ public void testComp() { @Test public void testFPArithmetic() { // Skipped the unary 'abs' Postgres operator written as '@' - this.qs("SELECT f.f1, f.f1 * '-10' AS x FROM FLOAT4_TBL f\n" + + this.qst("SELECT f.f1, f.f1 * '-10' AS x FROM FLOAT4_TBL f\n" + " WHERE f.f1 > '0.0';\n" + " f1 | x \n" + "---------------+----------------\n" + diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Part2Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Part2Tests.java index 3818367b9fd..405b44dfb9a 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Part2Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Part2Tests.java @@ -24,7 +24,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void testSelect() { - this.qs(""" + this.qst(""" SELECT * FROM FLOAT8_TBL; f1 ----------------------- @@ -46,7 +46,7 @@ public void testSelect() { @Test public void testsThatFailInPostgres() { - this.qs(""" + this.qst(""" -- this fails in Postgres with overflow but we return -inf SELECT f.f1 * '1e200' from FLOAT8_TBL f; f1 @@ -95,7 +95,7 @@ public void testsThatFailInPostgres() { // https://github.com/feldera/feldera/issues/1363 @Test public void testLn() { - this.qs(""" + this.qst(""" -- postgres doesn't allow ln(0) SELECT log10(f.f1) from FLOAT8_TBL f where f.f1 = '0.0'; f1 diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Tests.java index 798edd20d73..b088e6e5e23 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresFloat8Tests.java @@ -31,7 +31,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void testSelect() { - this.qs(""" + this.qst(""" -- special inputs SELECT 'NaN'::float8; float8 @@ -843,7 +843,7 @@ SELECT power(f.f1, '2.0'::DOUBLE) AS square_f1 // Postgres gives a runtime error, but rust returns inf @Test public void testPower2() { - this.qs(""" + this.qst(""" SELECT power('0'::DOUBLE, '-inf'::DOUBLE); power ------- @@ -874,7 +874,7 @@ public void castToInt() { @Test public void nonPostgresTests() { - this.qs(""" + this.qst(""" SELECT ln(1); ln ---- @@ -1092,7 +1092,7 @@ WITH v(x) AS (VALUES(0E0),(1E0),(-1E0),(4.2E0),(CAST ('Infinity' AS DOUBLE)),(CA @Test public void testModulo() { - this.qs(""" + this.qst(""" select 1.12::DOUBLE % 0.3::DOUBLE; ?column? ---------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresGroupingSetsTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresGroupingSetsTests.java index 01647cb30b6..0c75e3bed39 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresGroupingSetsTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresGroupingSetsTests.java @@ -17,7 +17,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void testRollup() { // commented out order by - this.qs(""" + this.qst(""" select a, b, grouping(a,b), sum(v), count(*), max(v) from gstest1 group by rollup (a,b); a | b | grouping | sum | count | max diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt2Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt2Tests.java index 4f3628a5011..8217d5c76f9 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt2Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt2Tests.java @@ -23,7 +23,7 @@ INSERT INTO INT2_TBL(f1) VALUES @Test public void testSelect() { - this.qs( + this.qst( """ SELECT * FROM INT2_TBL; f1 diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt4Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt4Tests.java index a2decf4ba6c..5e71382e850 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt4Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt4Tests.java @@ -23,7 +23,7 @@ INSERT INTO INT4_TBL(f1) VALUES @Test public void testSelect() { - this.qs( + this.qst( """ SELECT i.* FROM INT4_TBL i WHERE i.f1 <> '0'::INT2; f1 diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt8Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt8Tests.java index cd8452eb8d5..680a36f2daa 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt8Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresInt8Tests.java @@ -24,7 +24,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void precisionLossTest() { - this.qs(""" + this.qst(""" SELECT CAST('36854775807.0'::float4 AS int64); int8 ------------- @@ -34,7 +34,7 @@ public void precisionLossTest() { @Test public void testSelect() { - this.qs( + this.qst( """ SELECT * FROM INT8_TBL; q1 | q2 diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresIntervalTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresIntervalTests.java index b04a218dca5..d22cc560c9d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresIntervalTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresIntervalTests.java @@ -40,7 +40,7 @@ public void testInterval() { // Had to add the symbolic intervals by hand in many places // Postgres allows individual signs on fragments, the // standard doesn't - this.qs(""" + this.qst(""" SELECT INTERVAL '01:00' HOUR TO MINUTE AS "One hour"; One hour ---------- @@ -94,7 +94,7 @@ public void testInterval() { @Test public void testIntervalOperators() { - this.qs(""" + this.qst(""" SELECT * FROM SHORT_INTERVAL_TBL; i --- @@ -174,7 +174,7 @@ public void testIntervalOperators() { @Test public void testIntervalOperations() { - this.qs(""" + this.qst(""" SELECT r1.*, r2.* FROM SHORT_INTERVAL_TBL r1, SHORT_INTERVAL_TBL r2 WHERE r1.i > r2.i; @@ -227,7 +227,7 @@ public void testLimits() { @Test public void testLimitsPositive() { // Our limits are smaller than postgres, so this has been adapted - this.qs(""" + this.qst(""" SELECT -(INTERVAL -2147483 months); ?column? ------------------------ @@ -249,7 +249,7 @@ public void testLimitsPositive() { @Test public void testIntervalSub() { - this.qs(""" + this.qst(""" SELECT i - i FROM SHORT_INTERVAL_TBL; ?column? ---------- @@ -271,7 +271,7 @@ public void testOverflows() { @Test public void literals() { - this.qs(""" + this.qst(""" SELECT interval '999' second; -- oversize leading field is ok interval ---------- @@ -398,7 +398,7 @@ public void literals() { @Test public void testCast() { // Have to check the spec for the expected result - this.qs(""" + this.qst(""" SELECT CAST(i AS INTERVAL YEAR) FROM LONG_INTERVAL_TBL; i --- @@ -413,7 +413,7 @@ public void testCast() { @Test public void checkExtract() { // I think our definition of EXTRACT(EPOCH) is saner than Postgres - this.qs(""" + this.qst(""" SELECT i, EXTRACT(MICROSECOND FROM i) AS MICROSECOND, EXTRACT(MILLISECOND FROM i) AS MILLISECOND, @@ -459,7 +459,7 @@ public void checkExtract() { @Test public void testLongExtract() { - this.qs(""" + this.qst(""" SELECT EXTRACT(DECADE FROM INTERVAL '100' years); extract --------- @@ -512,7 +512,7 @@ public void testLongExtract() { @Test public void testCastString() { // These are not from postgres - this.qs(""" + this.qst(""" SELECT CAST(INTERVAL 1 YEARS AS VARCHAR); x --- @@ -552,7 +552,7 @@ public void testCastString() { @Test public void doubleCastTest() { - this.qs(""" + this.qst(""" SELECT CAST(CAST(INTERVAL '1 02:03:04.5' DAYS TO SECONDS AS INTERVAL DAYS) AS VARCHAR); x --- @@ -616,7 +616,7 @@ public void doubleCastTest() { @Test public void testCastShortIntervalToString() { - this.qs(""" + this.qst(""" SELECT CAST(INTERVAL '1 02:03:04.5' DAYS TO SECONDS AS VARCHAR); x --- @@ -729,7 +729,7 @@ public void testCastShortIntervalToString() { @Test public void testCastToInterval() { // These are not from postgres - this.qs(""" + this.qst(""" SELECT CAST(1 AS INTERVAL YEARS); x --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresLimitTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresLimitTests.java index 32c938c7c89..c2892900ceb 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresLimitTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresLimitTests.java @@ -43,7 +43,7 @@ CREATE TABLE onek ( @Test public void testLimit() { // removed empty columns from test. - this.qs(""" + this.qst(""" SELECT unique1, unique2, stringu1 FROM onek WHERE unique1 > 50 ORDER BY unique1 LIMIT 2; @@ -77,7 +77,7 @@ public void testLimit() { @Test public void testOffset() { - this.qs(""" + this.qst(""" SELECT unique1, unique2, stringu1 FROM onek WHERE unique1 > 100 ORDER BY unique1 LIMIT 3 OFFSET 20; diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresNumericTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresNumericTests.java index 4aebb8506f7..4b7db65d397 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresNumericTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresNumericTests.java @@ -773,7 +773,7 @@ public void testDivByZero() { // this is not a postgres test @Test public void testModuloMinusOne() { - this.qs(""" + this.qst(""" SELECT 2::DECIMAL % -1::DECIMAL; decimal --------- @@ -791,7 +791,7 @@ public void testModuloMinusOne() { @Test public void testModulo() { - this.qs(""" + this.qst(""" select 1.12 % 0.3; ?column? ---------- @@ -873,7 +873,7 @@ SELECT x, sqrt(x) @Test public void testExp() { - this.qs(""" + this.qst(""" -- -- Tests for EXP() -- @@ -920,7 +920,7 @@ public void testExp() { @Test public void testSqrtError() { - this.qs(""" + this.qst(""" SELECT sqrt('-1'::numeric), sqrt(-1e0); d | d ----------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresStringTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresStringTests.java index 2438a622d40..032181fbfba 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresStringTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresStringTests.java @@ -222,7 +222,7 @@ public void testCharTbl() { @Test public void testTrimConstant() { - this.qs(""" + this.qst(""" SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks"; bunch o blanks ---------------- @@ -251,7 +251,7 @@ public void testTrimConstant() { @Test public void testTrim() { - this.qs(""" + this.qst(""" SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks"; bunch o blanks ---------------- @@ -283,7 +283,7 @@ public void testTrimArg() { @Test public void testSubstring() { - this.qs(""" + this.qst(""" SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890"; 34567890 ---------- @@ -381,7 +381,7 @@ public void testOverlay() { @Test @Ignore("regexp_replace with 4 arguments not implemented") public void testRegexpReplace() { - this.qs(""" + this.qst(""" SELECT regexp_replace('1112223333', E'(\\\\d{3})(\\\\d{3})(\\\\d{4})', E'(\\\\1) \\\\2-\\\\3'); regexp_replace ---------------- @@ -491,7 +491,7 @@ public void testRegexpReplace() { @Test public void testLike2() { - this.qs(""" + this.qst(""" SELECT 'hawkeye' LIKE 'h%' AS "true"; true ------ @@ -580,7 +580,7 @@ public void testLike2() { @Test public void testRlike() { // This is not a postgres operator - this.qs(""" + this.qst(""" SELECT 'hawkeye' RLIKE 'h.*' AS "true"; true ------ @@ -867,36 +867,41 @@ public void testILike2() { @Test public void testLikeCombinations() { - this.q(""" + this.qs(""" SELECT 'foo' LIKE '_%' as t, 'f' LIKE '_%' as t0, '' LIKE '_%' as f; t | t0 | f ---+----+--- - t | t | f"""); - this.q(""" + t | t | f + (1 row) + SELECT 'foo' LIKE '%_' as t, 'f' LIKE '%_' as t0, '' LIKE '%_' as f; t | t0 | f ---+----+--- - t | t | f"""); - this.q(""" + t | t | f + (1 row) + SELECT 'foo' LIKE '__%' as t, 'foo' LIKE '___%' as t0, 'foo' LIKE '____%' as f; t | t0 | f ---+----+--- - t | t | f"""); - this.q(""" + t | t | f + (1 row) + SELECT 'foo' LIKE '%__' as t, 'foo' LIKE '%___' as t0, 'foo' LIKE '%____' as f; t | t0 | f ---+----+--- - t | t | f"""); - this.q(""" + t | t | f + (1 row) + SELECT 'jack' LIKE '%____%' AS t; t --- - t"""); + t + (1 row)"""); } @Test public void testLikeNull() { - this.qs(""" + this.qst(""" SELECT NULL LIKE '%'; result ------- @@ -986,7 +991,7 @@ public void testConcatConversions() { @Test public void testLength() { // added a few more aliases supported from other dialects - this.qs(""" + this.qst(""" SELECT char_length('abcdef') AS "length_6"; length_6 ---------- @@ -1069,7 +1074,7 @@ public void testReplace() { @Test public void testSplitPart() { - this.qs(""" + this.qst(""" SELECT split_part('abc~@~def~@~ghi', '~@~', 1) AS result; result ------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresTimeTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresTimeTests.java index 58b0e07c0f5..0e31e26fa7d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresTimeTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresTimeTests.java @@ -26,7 +26,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void testTime() { - this.qs(""" + this.qst(""" SELECT f1 AS "Time" FROM TIME_TBL; Time ------------- @@ -85,7 +85,7 @@ public void testTime() { @Test public void testConstants() { - this.qs(""" + this.qst(""" -- Check edge cases SELECT '23:59:59.999999'::time; time @@ -123,7 +123,7 @@ public void testFailPlus() { public void testUnits() { // Removed dates // Extract second and millisecond return integers in Calcite instead of DECIMAL - this.qs(""" + this.qst(""" SELECT EXTRACT(MICROSECOND FROM TIME '13:30:25.575401'); extract ---------- @@ -180,7 +180,7 @@ public void illegalUnits() { @Test public void testDatePart() { - this.qs(""" + this.qst(""" SELECT date_part(microsecond, TIME '13:30:25.575401'); date_part ----------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresWindowTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresWindowTests.java index 6dd0df2ec88..e08b9514a47 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresWindowTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/postgres/PostgresWindowTests.java @@ -113,29 +113,29 @@ CREATE TABLE tenk1_1_small ( @Test public void testWindow() { - this.qs(""" + this.qst(""" SELECT depname, empno, salary, sum(salary) OVER (PARTITION BY depname) FROM empsalary -- ORDER BY depname, salary ; depname | empno | salary | sum -----------+-------+--------+------- - develop| 7 | 4200 | 25100 - develop| 9 | 4500 | 25100 - develop| 11 | 5200 | 25100 - develop| 10 | 5200 | 25100 - develop| 8 | 6000 | 25100 - personnel| 5 | 3500 | 7400 - personnel| 2 | 3900 | 7400 - sales| 3 | 4800 | 14600 - sales| 4 | 4800 | 14600 - sales| 1 | 5000 | 14600 + develop | 7 | 4200 | 25100 + develop | 9 | 4500 | 25100 + develop | 11 | 5200 | 25100 + develop | 10 | 5200 | 25100 + develop | 8 | 6000 | 25100 + personnel | 5 | 3500 | 7400 + personnel | 2 | 3900 | 7400 + sales | 3 | 4800 | 14600 + sales | 4 | 4800 | 14600 + sales | 1 | 5000 | 14600 (10 rows)"""); } @Test public void testLeadLag() { - this.qs(""" + this.qst(""" SELECT lag(ten) OVER (PARTITION BY four ORDER BY ten), ten, four FROM tenk1_2_small WHERE unique2 < 10; lag | ten | four @@ -206,7 +206,7 @@ SELECT lead(ten * 2, 1, -1) OVER (PARTITION BY four ORDER BY ten), ten, four @Test public void testPreceding() { - this.qs(""" + this.qst(""" SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding), unique1, four FROM tenk1_1_small WHERE unique1 < 10; @@ -245,7 +245,7 @@ SELECT sum(unique1) over (partition by four order by unique1 range between 5::in @Test public void testWindowDescOrder() { - this.qs(""" + this.qst(""" SELECT sum(unique1) over (order by four desc range between 2::int8 preceding and 1::int2 preceding), unique1, four FROM tenk1_1_small WHERE unique1 < 10; @@ -268,7 +268,7 @@ SELECT sum(unique1) over (order by four desc range between 2::int8 preceding and public void dateWindow() { // around line 1534 // Converted INTERVAL 1 YEAR to INTERVAL 365 DAYS - this.qs(""" + this.qst(""" select sum(salary) OVER (order by enroll_date range between INTERVAL 365 DAYS preceding and INTERVAL 365 DAYS following), salary, enroll_date FROM empsalary; @@ -308,7 +308,7 @@ select sum(salary) @Test public void degenerateCases() { - this.qs(""" + this.qst(""" select f1, sum(f1) over (partition by f1 order by f2 range between 1 preceding and 1 following) from t1 where f1 = f2; @@ -339,7 +339,7 @@ select f1, sum(f1) over (partition by f1, f2 order by f2 @Test public void testTopK() { - this.qs(""" + this.qst(""" SELECT * FROM (SELECT empno, row_number() OVER (ORDER BY empno) rn @@ -431,12 +431,12 @@ public void testTopK() { WHERE rn < 3; empno | depname | rn -------+-----------+---- - 7 | develop| 1 - 8 | develop| 2 - 2 | personnel| 1 - 5 | personnel| 2 - 1 | sales| 1 - 3 | sales| 2 + 7 | develop | 1 + 8 | develop | 2 + 2 | personnel | 1 + 5 | personnel | 2 + 1 | sales | 1 + 3 | sales | 2 (6 rows) SELECT * FROM @@ -448,21 +448,21 @@ public void testTopK() { WHERE c <= 3; empno | depname | salary | c -------+-----------+--------+--- - 8 | develop| 6000 | 1 - 10 | develop| 5200 | 3 - 11 | develop| 5200 | 3 - 2 | personnel| 3900 | 1 - 5 | personnel| 3500 | 2 - 1 | sales| 5000 | 1 - 4 | sales| 4800 | 3 - 3 | sales| 4800 | 3 + 8 | develop | 6000 | 1 + 10 | develop | 5200 | 3 + 11 | develop | 5200 | 3 + 2 | personnel | 3900 | 1 + 5 | personnel | 3500 | 2 + 1 | sales | 5000 | 1 + 4 | sales | 4800 | 3 + 3 | sales | 4800 | 3 (8 rows) """); } @Test @Ignore("Lead with variable amounts not supported") public void testLeadLagVariable() { - this.qs(""" + this.qst(""" select x, lag(x, 1) over (order by x), lead(x, 3) over (order by x) from series; x | lag | lead diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggScottTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggScottTests.java index fb3bf46b6c1..45ed29e47dc 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggScottTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggScottTests.java @@ -8,7 +8,7 @@ public class AggScottTests extends ScottBaseTests { @Test public void testCalcite6403() { - this.qs(""" + this.qst(""" SELECT COUNT(*), COUNT(DISTINCT deptno) FROM emp WHERE false; c0 | c1 --------- @@ -18,7 +18,7 @@ public void testCalcite6403() { @Test public void testPairs() { - this.qs(""" + this.qst(""" select comm, (comm, comm) in ((500, 500), (300, 300), (0, 0)) from emp; comm | in ----------- @@ -42,7 +42,7 @@ public void testPairs() { @Test @Ignore("Cannot decorrelate LATERAL join") public void testLateral() { - this.qs(""" + this.qst(""" SELECT deptno, ename FROM (SELECT DISTINCT deptno FROM emp) t1, @@ -435,7 +435,7 @@ group by grouping sets ((job, deptno, comm is null), @Test public void testSimple() { - this.qs(""" + this.qst(""" -- [KYLIN-751] Max on negative double values is not working -- [CALCITE-735] Primitive.DOUBLE.min should be large and negative select max(v) as x, min(v) as n @@ -513,7 +513,7 @@ SELECT SUM( @Test @Ignore("fusion, collect not yet implemented") public void testFusion() { - this.qs(""" + this.qst(""" -- FUSION rolled up using CARDINALITY select cardinality(fusion(empnos)) as f_empnos_length from ( @@ -611,7 +611,7 @@ select deptno, collect(empno) filter (where empno < 7550) as empnos @Test public void testConditionalAggregate() { - this.qs(""" + this.qst(""" -- Aggregate FILTER select deptno, sum(sal) filter (where job = 'CLERK') c_sal, @@ -665,7 +665,7 @@ public void testConditionalAggregate() { // select the ordered field is compiled incorrectly @Test public void testOrderByFilter() { - this.qs(""" + this.qst(""" -- Aggregate FILTER with ORDER BY select deptno from emp @@ -683,7 +683,7 @@ public void testOrderByFilter() { @Test public void testAggregates() { - this.qs(""" + this.qst(""" -- Aggregate FILTER with JOIN select dept.deptno, sum(sal) filter (where 1 < 2) as s, @@ -797,7 +797,7 @@ select count(*) filter (where (x = 0) is false) as c @Test public void testCompositeCount() { - this.qs(""" + this.qst(""" -- Composite COUNT and FILTER select count(*) as c, count(*) filter (where z > 1) as cf, @@ -816,7 +816,7 @@ select count(*) as c, @Test public void testAggregates2() { - this.qs(""" + this.qst(""" select count(distinct deptno) as cd, count(*) as c from emp group by deptno; @@ -832,7 +832,7 @@ select count(distinct deptno) as cd, count(*) as c @Test public void testDistinctAggregates() { - this.qs(""" + this.qst(""" select deptno, count(distinct deptno) as c from emp group by deptno; @@ -860,7 +860,7 @@ select count(distinct deptno) as c @Test public void testCubeDistinct() { - this.qs(""" + this.qst(""" select count(distinct deptno) as cd, count(*) as c from emp group by cube(deptno); @@ -878,7 +878,7 @@ select count(distinct deptno) as cd, count(*) as c @Test public void testDistinctCount() { // These tests cannot be run without optimizations. - this.qs(""" + this.qst(""" -- Multiple distinct count and non-distinct aggregates select deptno, count(distinct job) as dj, @@ -926,7 +926,7 @@ select count(distinct job) as dj, @Test public void testAvg() { - this.qs(""" + this.qst(""" select avg(comm) as a, count(comm) as c from emp where empno < 7844; +-------------------+---+ @@ -939,7 +939,7 @@ select avg(comm) as a, count(comm) as c from @Test public void testAggregates3() { - this.qs(""" + this.qst(""" -- [CALCITE-846] Push aggregate with FILTER through UNION ALL select deptno, count(*) filter (where job = 'CLERK') as cf, count(*) as c from ( @@ -1177,7 +1177,7 @@ select sum(m.sal) as s @Test public void testNestedOrderby() { - this.qs(""" + this.qst(""" -- Collation of LogicalAggregate ([CALCITE-783] and [CALCITE-822]) select sum(x) as sum_cnt, count(distinct y) as cnt_dist @@ -1206,7 +1206,7 @@ select sum(x) as sum_cnt, @Test public void testAggregates4() { - this.qs(""" + this.qst(""" -- [CALCITE-938] Aggregate row count select empno, d.deptno from emp @@ -1641,7 +1641,7 @@ SELECT job, AVG(avg_sal) AS avg_sal2 @Test public void testAgg4() { - this.qs(""" + this.qst(""" -- [CALCITE-1930] AggregateExpandDistinctAggregateRules should handle multiple aggregate calls with same input ref select count(distinct EMPNO), COUNT(SAL), MIN(SAL), MAX(SAL) from emp; +--------+--------+--------+---------+ @@ -1693,7 +1693,7 @@ public void testAgg4() { @Test @Ignore("Several not-implemented aggregation functions") public void testRegrValue() { - this.qs(""" + this.qst(""" -- [CALCITE-1776, CALCITE-2402] REGR_COUNT SELECT regr_count(COMM, SAL) as "REGR_COUNT(COMM, SAL)", regr_count(EMPNO, SAL) as "REGR_COUNT(EMPNO, SAL)" @@ -1736,7 +1736,7 @@ SELECT regr_count(COMM, SAL) as "REGR_COUNT(COMM, SAL)", @Test public void bitTests() { - this.qs(""" + this.qst(""" -- BIT_AND, BIT_OR, BIT_XOR aggregate functions select bit_and(deptno), bit_or(deptno), bit_xor(deptno) from emp; +--------+--------+--------+ diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggTests.java index 54ed3a28ffe..7b4f66695cd 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AggTests.java @@ -16,26 +16,26 @@ left join dept as s on (select true from emp)""", @Test public void calciteIssue6520() { - this.qs(""" + this.qst(""" SELECT ENAME, ENAME in ('Adam', 'Alice', 'Eve') FROM EMP; ename | expr -------------- - Adam| true - Alice| true - Bob| false - Eric| false - Eve| true - Grace| false - Jane| false - Susan| false - Wilma| false + Adam | true + Alice | true + Bob | false + Eric | false + Eve | true + Grace | false + Jane | false + Susan | false + Wilma | false --------------- (9 rows)"""); } @Test public void testCompositeCount() { - this.qs(""" + this.qst(""" -- composite count select count(deptno, ename, 1, deptno) as c from emp; +---+ @@ -67,9 +67,9 @@ public void testCompositeCount() { +----+---+ | M | C | +----+---+ - | 0 | F| + | 0 | F | | 10 |NULL| - | 0 | M| + | 0 | M | +----+---+ (3 rows) @@ -93,7 +93,7 @@ public void testCompositeCount() { @Test public void testAggregates() { - this.qs(""" + this.qst(""" -- count(*) returns number of rows in table select count(ename) as c from emp; +---+ @@ -194,7 +194,7 @@ select distinct count(*) as c from emp group by deptno order by 1 desc @Test public void issue1901() { - this.qs(""" + this.qst(""" select stddev(value) FROM (VALUES (.1e0), (.1e0), (.1e0)) t1(value) WHERE true; result ------ @@ -204,7 +204,7 @@ public void issue1901() { @Test public void stddevTests() { - this.qs(""" + this.qst(""" -- Our own test, for denominator of 0 in SAMP select stddev_samp(deptno) as s from emp WHERE deptno = 60; +----+ @@ -263,8 +263,8 @@ public void stddevTests() { +--------+----+----+----+---+ | GENDER | P | S | SS | C | +--------+----+----+----+---+ - | F| 17 | 19 | 19 | 5 | - | M| 17 | 20 | 20 | 3 | + | F | 17 | 19 | 19 | 5 | + | M | 17 | 20 | 20 | 3 | +--------+----+----+----+---+ (2 rows)"""); } @@ -272,7 +272,7 @@ public void stddevTests() { @Test @Ignore("multiset not yet implemented") public void testIntersection() { - this.qs(""" + this.qst(""" -- [CALCITE-3815] Add missing SQL standard aggregate -- functions: EVERY, SOME, INTERSECTION select some(deptno = 100), every(deptno > 0), intersection(multiset[1, 2]) from emp; @@ -286,7 +286,7 @@ public void testIntersection() { @Test public void testEvery() { - this.qs(""" + this.qst(""" select some(deptno > 100), every(deptno > 0) from emp where deptno > 1000; +--------+--------+ | EXPR$0 | EXPR$1 | @@ -299,16 +299,16 @@ public void testEvery() { @Test public void simpleTests() { - this.qs(""" + this.qst(""" select city, gender as c from emps; +---------------+---+ | CITY | C | +---------------+---+ - | Vancouver| F| - | San Francisco| M| - |NULL|NULL| - | Vancouver| M| - |NULL| F| + | Vancouver | F | + | San Francisco | M | + |NULL |NULL| + | Vancouver | M | + |NULL | F | +---------------+---+ (5 rows) @@ -317,11 +317,11 @@ public void simpleTests() { +---------------+--------+ | CITY | GENDER | +---------------+--------+ - |NULL|NULL| - | Vancouver| M| - |NULL| F| - | San Francisco| M| - | Vancouver| F| + |NULL |NULL | + | Vancouver | M | + |NULL | F | + | San Francisco | M | + | Vancouver | F | +---------------+--------+ (5 rows) @@ -344,7 +344,7 @@ C BIGINT(19) NOT NULL @Test public void testGroupingSets() { - this.qs(""" + this.qst(""" -- Basic GROUPING SETS select deptno, count(*) as c from emps group by grouping sets ((), (deptno)); +--------+---+ @@ -385,7 +385,7 @@ public void testGroupingSets() { @Test public void testRollup() { - this.qs(""" + this.qst(""" -- CUBE select deptno + 1, count(*) as c from emp group by cube(deptno, gender); +--------+---+ @@ -435,21 +435,21 @@ public void testRollup() { +--------+--------+---+ | GENDER | EXPR$1 | C | +--------+--------+---+ - | M| 21 | 1 | - | F| 11 | 1 | - | F| 31 | 2 | - | F| 51 | 1 | - | F| 61 | 1 | - | F| | 1 | - | M| 11 | 1 | - | M| 51 | 1 | - |NULL| 11 | 2 | - |NULL| 21 | 1 | - |NULL| 31 | 2 | - |NULL| 51 | 2 | - |NULL| 61 | 1 | - |NULL| | 1 | - |NULL| | 9 | + | M | 21 | 1 | + | F | 11 | 1 | + | F | 31 | 2 | + | F | 51 | 1 | + | F | 61 | 1 | + | F | | 1 | + | M | 11 | 1 | + | M | 51 | 1 | + |NULL | 11 | 2 | + |NULL | 21 | 1 | + |NULL | 31 | 2 | + |NULL | 51 | 2 | + |NULL | 61 | 1 | + |NULL | | 1 | + |NULL | | 9 | +--------+--------+---+ (15 rows) @@ -461,9 +461,9 @@ select gender, count(*) as c +--------+---+ | GENDER | C | +--------+---+ - | F| 6 | - | M| 3 | - |NULL| 9 | + | F | 6 | + | M | 3 | + |NULL | 9 | +--------+---+ (3 rows) @@ -476,9 +476,9 @@ group by rollup(gender) +--------+---+ | GENDER | C | +--------+---+ - |NULL| 9 | - | F| 6 | - | M| 3 | + |NULL | 9 | + | F | 6 | + | M | 3 | +--------+---+ (3 rows) @@ -605,18 +605,18 @@ group by rollup(deptno) +--------+--------+--------+ | DEPTNO | GENDER | EXPR$2 | +--------+--------+--------+ - | 20 | M| 1 | - | 20 | M| 1 | - | 20 | M| 1 | - | 20 | M| 1 | - | 20 | M| 1 | - | 20 | M| 1 | - | 20 | M| 1 | - | 20 |NULL| 1 | - | 20 |NULL| 1 | - | 20 |NULL| 1 | - | | M| 1 | - | |NULL| 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 | M | 1 | + | 20 |NULL | 1 | + | 20 |NULL | 1 | + | 20 |NULL | 1 | + | | M | 1 | + | |NULL | 1 | +--------+--------+--------+ (12 rows) @@ -625,17 +625,17 @@ group by rollup(deptno) +--------+--------+--------+ | DEPTNO | GENDER | EXPR$2 | +--------+--------+--------+ - | 20 | M| 1 | - | 20 |NULL| 1 | - | | M| 1 | - | |NULL| 1 | + | 20 | M | 1 | + | 20 |NULL | 1 | + | | M | 1 | + | |NULL | 1 | +--------+--------+--------+ (4 rows)"""); } @Test public void testCornerCases() { - this.qs(""" + this.qst(""" -- GROUP BY over empty columns select count(*) from emp where deptno = 20 group by (); +--------+ @@ -666,7 +666,7 @@ public void testCornerCases() { @Test public void testGrouping() { - this.qs(""" + this.qst(""" -- CUBE and JOIN select e.deptno, e.gender, min(e.ename) as min_name from emp as e join dept as d using (deptno) @@ -675,10 +675,10 @@ group by cube(e.deptno, d.deptno, e.gender) +--------+--------+----------+ | DEPTNO | GENDER | MIN_NAME | +--------+--------+----------+ - | 10 | M| Bob| - | 10 | M| Bob| - | | F| Alice| - | |NULL| Alice| + | 10 | M | Bob | + | 10 | M | Bob | + | | F | Alice | + | |NULL | Alice | +--------+--------+----------+ (4 rows) @@ -785,11 +785,11 @@ select deptno, gender, grouping_id(deptno, gender, deptno), count(*) as c +--------+--------+--------+---+ | DEPTNO | GENDER | EXPR$2 | C | +--------+--------+--------+---+ - | 10 | F| 0 | 1 | - | 10 | M| 0 | 1 | - | | F| 5 | 1 | - | | M| 5 | 1 | - | |NULL| 7 | 2 | + | 10 | F | 0 | 1 | + | 10 | M | 0 | 1 | + | | F | 5 | 1 | + | | M | 5 | 1 | + | |NULL | 7 | 2 | +--------+--------+--------+---+ (5 rows) @@ -819,30 +819,30 @@ select deptno, gender, grouping(deptno) gd, grouping(gender) gg, +--------+--------+----+----+----+----+-----+---+ | DEPTNO | GENDER | GD | GG | DG | GD | GID | C | +--------+--------+----+----+----+----+-----+---+ - | 10 | F| 0 | 0 | 0 | 0 | 0 | 1 | - | 10 | M| 0 | 0 | 0 | 0 | 0 | 1 | - | 20 | M| 0 | 0 | 0 | 0 | 0 | 1 | - | 30 | F| 0 | 0 | 0 | 0 | 0 | 2 | - | 50 | F| 0 | 0 | 0 | 0 | 0 | 1 | - | 50 | M| 0 | 0 | 0 | 0 | 0 | 1 | - | 60 | F| 0 | 0 | 0 | 0 | 0 | 1 | - | | F| 0 | 0 | 0 | 0 | 0 | 1 | - | |NULL| 1 | 1 | 3 | 3 | 0 | 9 | - | 10 |NULL| 0 | 1 | 1 | 2 | 0 | 2 | - | 20 |NULL| 0 | 1 | 1 | 2 | 0 | 1 | - | 30 |NULL| 0 | 1 | 1 | 2 | 0 | 2 | - | 50 |NULL| 0 | 1 | 1 | 2 | 0 | 2 | - | 60 |NULL| 0 | 1 | 1 | 2 | 0 | 1 | - | | F| 1 | 0 | 2 | 1 | 0 | 6 | - | | M| 1 | 0 | 2 | 1 | 0 | 3 | - | |NULL| 0 | 1 | 1 | 2 | 0 | 1 | + | 10 | F | 0 | 0 | 0 | 0 | 0 | 1 | + | 10 | M | 0 | 0 | 0 | 0 | 0 | 1 | + | 20 | M | 0 | 0 | 0 | 0 | 0 | 1 | + | 30 | F | 0 | 0 | 0 | 0 | 0 | 2 | + | 50 | F | 0 | 0 | 0 | 0 | 0 | 1 | + | 50 | M | 0 | 0 | 0 | 0 | 0 | 1 | + | 60 | F | 0 | 0 | 0 | 0 | 0 | 1 | + | | F | 0 | 0 | 0 | 0 | 0 | 1 | + | |NULL | 1 | 1 | 3 | 3 | 0 | 9 | + | 10 |NULL | 0 | 1 | 1 | 2 | 0 | 2 | + | 20 |NULL | 0 | 1 | 1 | 2 | 0 | 1 | + | 30 |NULL | 0 | 1 | 1 | 2 | 0 | 2 | + | 50 |NULL | 0 | 1 | 1 | 2 | 0 | 2 | + | 60 |NULL | 0 | 1 | 1 | 2 | 0 | 1 | + | | F | 1 | 0 | 2 | 1 | 0 | 6 | + | | M | 1 | 0 | 2 | 1 | 0 | 3 | + | |NULL | 0 | 1 | 1 | 2 | 0 | 1 | +--------+--------+----+----+----+----+-----+---+ (17 rows)"""); } @Test public void testAgg() { - this.qs(""" + this.qst(""" -- [CALCITE-1781] Allow expression in CUBE and ROLLUP select deptno + 1 as d1, deptno + 1 - 1 as d0, count(*) as c from emp @@ -866,16 +866,16 @@ select mod(deptno, 20) as d, count(*) as c, gender as g +----+---+---+ | D | C | G | +----+---+---+ - | 0 | 1 | F| - | 0 | 1 | M| + | 0 | 1 | F | + | 0 | 1 | M | | 0 | 2 |NULL| - | 10 | 2 | M| - | 10 | 4 | F| + | 10 | 2 | M | + | 10 | 4 | F | | 10 | 6 |NULL| - | | 1 | F| + | | 1 | F | | | 1 |NULL| - | | 3 | M| - | | 6 | F| + | | 3 | M | + | | 6 | F | | | 9 |NULL| +----+---+---+ (11 rows) @@ -886,13 +886,13 @@ select mod(deptno, 20) as d, count(*) as c, gender as g +----+---+---+ | D | C | G | +----+---+---+ - | 0 | 1 | F| - | 0 | 1 | M| + | 0 | 1 | F | + | 0 | 1 | M | | 0 | 2 |NULL| - | 10 | 2 | M| - | 10 | 4 | F| + | 10 | 2 | M | + | 10 | 4 | F | | 10 | 6 |NULL| - | | 1 | F| + | | 1 | F | | | 1 |NULL| | | 9 |NULL| +----+---+---+ @@ -926,13 +926,13 @@ select count(*) as c } @Test public void t0() { - this.qs(""" + this.qst(""" select distinct '1' from (values (1,2),(3,4)); +--------+ | EXPR$0 | +--------+ - | 1| + | 1 | +--------+ (1 row) @@ -960,7 +960,7 @@ select nullif(count(distinct '1'),0) TODO: setup more tests @Test public void testAggregates() { - this.qs(""" + this.qst(""" !use orinoco -- FLOOR to achieve a 2-hour window @@ -1357,7 +1357,7 @@ select deptno, ename, MODE(gender) as m @Test public void testRowNumber() { - this.qs(""" + this.qst(""" -- Test case for [CALCITE-5388] tempList expression inside EnumerableWindow.getPartitionIterator should be unoptimized with CTE1(rownr1, val1) as ( select ROW_NUMBER() OVER(ORDER BY id ASC), id from (values (1), (2)) as Vals1(id) ), diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AsofTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AsofTests.java index 5b937e37ee8..cf1743bbae3 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AsofTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/AsofTests.java @@ -8,7 +8,7 @@ public class AsofTests extends StreamingTestBase { @Test @Ignore("Only left implemented") public void testAsof() { - this.qs(""" + this.qst(""" SELECT * FROM (VALUES (NULL, 0), (1, NULL), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 3), (3, 4)) AS t1(k, t) ASOF JOIN (VALUES (1, NULL), (1, 2), (1, 3), (2, 10), (2, 0)) AS t2(k, t) @@ -86,7 +86,7 @@ ASOF JOIN (VALUES (1, NULL), (1, 2), (1, 3), (2, 10), (2, 0)) AS t2(k, t) @Test public void testLeftAsofGE() { - this.qs(""" + this.qst(""" SELECT * FROM (VALUES (NULL, 0), (1, NULL), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 3), (3, 4)) AS t1(k, t) LEFT ASOF JOIN (VALUES (1, NULL), (1, 2), (1, 3), (2, 10), (2, 0)) AS t2(k, t) @@ -110,7 +110,7 @@ LEFT ASOF JOIN (VALUES (1, NULL), (1, 2), (1, 3), (2, 10), (2, 0)) AS t2(k, t) @Test @Ignore("Not all comparisons supported") public void testLeftAsof() { - this.qs(""" + this.qst(""" SELECT * FROM (VALUES (NULL, 0), (1, NULL), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 3), (3, 4)) AS t1(k, t) LEFT ASOF JOIN (VALUES (1, NULL), (1, 2), (1, 3), (2, 10), (2, 0)) AS t2(k, t) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/BigQueryTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/BigQueryTests.java index be2cc649667..62b10359b95 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/BigQueryTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/BigQueryTests.java @@ -7,7 +7,7 @@ public class BigQueryTests extends SqlIoTest { @Test public void testSafeCast() { - this.qs(""" + this.qst(""" -- SAFE_CAST(x AS type) -- Identical to CAST(), except it returns NULL instead of raising an error. WITH Casted AS ( @@ -23,11 +23,11 @@ SELECT SAFE_CAST(0 as BOOLEAN), 0, 'boolean' +------------+-------------+------------+ | casted | input | as | +------------+-------------+------------+ - |NULL | a| int| - | a| a| varchar(1)| - | 2023-03-07| 2023-03-07| date| - |NULL | 2023-03-07a| date| - | FALSE| 0| boolean| + |NULL | a | int | + | a | a | varchar(1) | + | 2023-03-07 | 2023-03-07 | date | + |NULL | 2023-03-07a | date | + | FALSE | 0 | boolean | +------------+-------------+------------+ (5 rows) @@ -42,8 +42,8 @@ SELECT SAFE_CAST('12:12:11a' as TIME), '12:12:11a', 'time' +----------+-----------+-----+ | casted | input | as | +----------+-----------+-----+ - | 12:12:11 | 12:12:11| time| - | | 12:12:11a| time| + | 12:12:11 | 12:12:11 | time| + | | 12:12:11a | time| +----------+-----------+-----+ (2 rows) @@ -59,8 +59,8 @@ SELECT SAFE_CAST(FALSE as BOOLEAN) as casted, 'false' as input, +--------+-------+--------+ | casted | input | as | +--------+-------+--------+ - | true | true| boolean| - | false | false| boolean| + | true | true | boolean| + | false | false | boolean| +--------+-------+--------+ (2 rows) @@ -78,9 +78,9 @@ SELECT SAFE_CAST(null as interval year), 'null', 'interval year' +--------+------------------+--------------+ | casted | input | as | +--------+------------------+--------------+ - | 1 year | interval 1 month| interval year| - | | a| interval year| - | | null| interval year| + | 1 year | interval 1 month | interval year| + | | a | interval year | + | | null | interval year| +--------+------------------+--------------+ (3 rows) @@ -97,8 +97,8 @@ SELECT SAFE_CAST('a' as interval minute to second), +---------------+-----------------------------+--------------------------+ | casted | input | as | +---------------+-----------------------------+--------------------------+ - | 61 mins | interval 1:1 hour to minute| interval minute to second| - | | a| interval minute to second| + | 61 mins | interval 1:1 hour to minute | interval minute to second| + | | a | interval minute to second| +---------------+-----------------------------+--------------------------+ (2 rows) @@ -116,16 +116,16 @@ SELECT SAFE_CAST(1 as BIGINT), '1', 'bigint' -- UNION ALL +--------+-------+-------+ | casted | input | as | +--------+-------+-------+ - | | true| bigint| - | 1 | 1.0| bigint| - | 1 | 1| bigint| + | | true | bigint| + | 1 | 1.0 | bigint| + | 1 | 1 | bigint| +--------+-------+-------+ (3 rows)"""); } @Test public void testRegexpReplace() { - this.qs(""" + this.qst(""" -- REGEXP_REPLACE(value, regexp, replacement) -- -- Returns a STRING where all substrings of value that match regexp are replaced with replacement. @@ -166,7 +166,7 @@ public void negativeTestParseDate() { // pattern insufficient for hour this.qf("SELECT PARSE_TIMESTAMP('%a %b %e %I:%M:%S %Y', 'Thu Dec 25 07:30:00 2008')", "Invalid format in PARSE_TIMESTAMP"); - this.qs(""" + this.qst(""" -- 30 hour is out of range SELECT PARSE_TIME('%S:%I:%M', '07:30:00'); r @@ -212,7 +212,7 @@ public void negativeTestParseDate() { @Test public void testParseDate() { // These have been adapted, since these functions are not compatible with BigQuery. - this.qs(""" + this.qst(""" SELECT PARSE_DATE('%A %b %e %Y', 'Thursday Dec 25 2008'); +------------+ | EXPR$0 | diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/CalciteJdbcTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/CalciteJdbcTests.java index ab67366249e..ed6138de114 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/CalciteJdbcTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/CalciteJdbcTests.java @@ -8,16 +8,16 @@ public class CalciteJdbcTests extends HrBaseTests { // validated on Postgres @Test public void testWinAggFirstValue() { - this.qs(""" + this.qst(""" select deptno, empid, commission, first_value(commission) over (partition by deptno order by empid) as r from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | 1000 - 10 | 110 | 250 | 1000 - 10 | 150 | null | 1000 - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | 1000 + 10 | 110 | 250 | 1000 + 10 | 150 | null | 1000 + 20 | 200 | 500 | 500 (4 rows) select deptno, empid, commission, @@ -40,10 +40,10 @@ public void testWinAggFirstValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | 1000 - 10 | 110 | 250 | 1000 - 10 | 150 | null | 1000 - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | 1000 + 10 | 110 | 250 | 1000 + 10 | 150 | null | 1000 + 20 | 200 | 500 | 500 (4 rows) -- same query with different explicit bounds @@ -55,10 +55,10 @@ public void testWinAggFirstValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | 1000 - 10 | 110 | 250 | 1000 - 10 | 150 | null | 1000 - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | 1000 + 10 | 110 | 250 | 1000 + 10 | 150 | null | 1000 + 20 | 200 | 500 | 500 (4 rows) -- same query with range explicit bounds @@ -70,10 +70,10 @@ public void testWinAggFirstValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | 1000 - 10 | 110 | 250 | 1000 - 10 | 150 | null | 1000 - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | 1000 + 10 | 110 | 250 | 1000 + 10 | 150 | null | 1000 + 20 | 200 | 500 | 500 (4 rows) -- same query with a different explicit bounds @@ -85,17 +85,17 @@ public void testWinAggFirstValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | 1000 - 10 | 110 | 250 | 1000 - 10 | 150 | null | 1000 - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | 1000 + 10 | 110 | 250 | 1000 + 10 | 150 | null | 1000 + 20 | 200 | 500 | 500 (4 rows)"""); } @Test public void testWinAggLastValue() { // validated on postgres - this.qs(""" + this.qst(""" -- same query with different explicit bounds select deptno, empid, commission, last_value(commission) over ( @@ -105,10 +105,10 @@ public void testWinAggLastValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | NULL - 10 | 110 | 250 | NULL - 10 | 150 | null | NULL - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | NULL + 10 | 110 | 250 | NULL + 10 | 150 | null | NULL + 20 | 200 | 500 | 500 (4 rows) -- same query with range explicit bounds @@ -120,10 +120,10 @@ public void testWinAggLastValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | NULL - 10 | 110 | 250 | NULL - 10 | 150 | null | NULL - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | NULL + 10 | 110 | 250 | NULL + 10 | 150 | null | NULL + 20 | 200 | 500 | 500 (4 rows) -- same query with a different explicit bounds @@ -135,10 +135,10 @@ public void testWinAggLastValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | NULL - 10 | 110 | 250 | NULL - 10 | 150 | null | NULL - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | NULL + 10 | 110 | 250 | NULL + 10 | 150 | null | NULL + 20 | 200 | 500 | 500 (4 rows) -- same query with a different explicit bounds @@ -150,16 +150,16 @@ public void testWinAggLastValue() { from emps; deptno | empid | commission | R --------------------------------- - 10 | 100 | 1000 | NULL - 10 | 110 | 250 | NULL - 10 | 150 | null | NULL - 20 | 200 | 500 | 500 + 10 | 100 | 1000 | NULL + 10 | 110 | 250 | NULL + 10 | 150 | null | NULL + 20 | 200 | 500 | 500 (4 rows)"""); } @Test @Ignore("FIRST_VALUE with bounded range not supported") public void testBoundedFirstValue() { - this.qs(""" + this.qst(""" select deptno, empid, commission, first_value(commission) over (partition by deptno order by empid desc range between 1000 preceding and 999 preceding) as r diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/FoodmartTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/FoodmartTests.java index 9c59e1f3eb3..cf82c454802 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/FoodmartTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/FoodmartTests.java @@ -16,19 +16,20 @@ public void testQualify() { @Test public void testSelect() { - this.q(""" + this.qst(""" SELECT * FROM DEPT; - DEPT NO | DNAME | LOC - --------------------- - 10 | ACCOUNTING| NEW YORK - 20 | RESEARCH| DALLAS - 30 | SALES| CHICAGO - 40 | OPERATIONS| BOSTON"""); + DEPT NO | DNAME | LOC + --------------------------------- + 10 | ACCOUNTING | NEW YORK + 20 | RESEARCH | DALLAS + 30 | SALES | CHICAGO + 40 | OPERATIONS | BOSTON + (4 rows)"""); } @Test public void testScalar() { - this.qs(""" + this.qst(""" select deptno, (select min(empno) from emp where deptno = dept.deptno) as x from dept; +--------+------+ | DEPTNO | X | @@ -143,7 +144,7 @@ public void testScalar() { @Test @Ignore("Cannot be decorrelated (generates LATERAL)") public void limitTests() { - this.qs(""" + this.qst(""" select deptno, (select sum(empno) from emp where deptno = dept.deptno limit 1) as x from dept; +--------+----------------------+ | DEPTNO | X | diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HRWinAggTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HRWinAggTests.java index 6c10ec841dc..83cfb3e6493 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HRWinAggTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/HRWinAggTests.java @@ -8,7 +8,7 @@ public class HRWinAggTests extends HrBaseTests { @Test @Ignore("ORDER BY strings not supported https://github.com/feldera/feldera/issues/457, first_value") public void testWin() { - this.qs(""" + this.qst(""" -- [CALCITE-2081] Two windows under a JOIN select a.deptno, a.r as ar, b.r as br from ( @@ -56,7 +56,7 @@ window w as (partition by "deptno" order by "commission")) b @Test public void test1() { - this.qs(""" + this.qst(""" select * from ( select "empid", count(*) over () c from "emps" diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/MiscTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/MiscTests.java index e0f838cc6af..e745d6b9df2 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/MiscTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/MiscTests.java @@ -7,7 +7,7 @@ public class MiscTests extends ScottBaseTests { @Test public void uuidTests() { - this.qs(""" + this.qst(""" SELECT UUID '123e4567-e89b-12d3-a456-426655440000'; +--------------------------------------+ | EXPR$0 | @@ -72,7 +72,7 @@ public void uuidTests() { @Test public void rowTests() { - this.qs(""" + this.qst(""" -- Implicit ROW select deptno, (empno, deptno) as r from emp; @@ -133,7 +133,7 @@ select deptno, row (empno, deptno) as r @Test @Ignore("Requires MULTISET") public void testRowCoalesce() { - this.qs(""" + this.qst(""" -- [CALCITE-877] Allow ROW as argument to COLLECT select deptno, collect(r) as empnos from (select deptno, (empno, deptno) as r @@ -152,7 +152,7 @@ select deptno, collect(r) as empnos @Test public void intervalTests() { // Added tests with decimal and FP - this.qs(""" + this.qst(""" -- [CALCITE-922] Value of INTERVAL literal select deptno * interval '2' day as d2, deptno * interval -'3' hour as h3, @@ -212,7 +212,7 @@ public void intervalTests() { @Test public void intervalDivision() { // Tested on Postgres, the long interval results differ, since postgres computes on days - this.qs(""" + this.qst(""" select interval '2' day / deptno as d2, interval -'3' hour / deptno as h3, interval -'-4' hour / deptno as h4, diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OperatorTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OperatorTests.java index cdcd7fca996..bc23bd7ada1 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OperatorTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OperatorTests.java @@ -7,7 +7,7 @@ public class OperatorTests extends SqlIoTest { @Test public void testRow() { - this.qs(""" + this.qst(""" select T.X[1] as x1 from (VALUES (ROW(ROW(3, 7), ROW(4, 8)))) as T(x, y); +----+ | X1 | @@ -43,7 +43,7 @@ public void testRow() { @Test public void testFloor() { - this.qs(""" + this.qst(""" select floor(timestamp '2025-01-01 10:00:00.123456' to millisecond), floor(timestamp '1950-01-01 10:00:00.123456' to millisecond); t1 | t2 @@ -55,7 +55,7 @@ select floor(timestamp '2025-01-01 10:00:00.123456' to millisecond), @Test public void testIntervalToString() { // Test that months are formatted with two digits - this.qs(""" + this.qst(""" SELECT CAST((INTERVAL '-2-8' YEAR TO MONTH / 2.583) AS VARCHAR); r --- @@ -72,7 +72,7 @@ public void testIntervalToString() { @Test public void testCeilFloor() { // From Calcite operator.iq - this.qs(""" + this.qst(""" select v, case when b then 'ceil' else 'floor' end as op, case when b then ceil(v to year) else floor(v to year) end as y, @@ -85,8 +85,8 @@ case when b then ceil(v to day) else floor(v to day) end as d +------------+-------+------------+------------+------------+------------+------------+ | V | OP | Y | Q | M | W | D | +------------+-------+------------+------------+------------+------------+------------+ - | 2019-07-05 | ceil| 2020-01-01 | 2019-10-01 | 2019-08-01 | 2019-07-07 | 2019-07-05 | - | 2019-07-05 | floor| 2019-01-01 | 2019-07-01 | 2019-07-01 | 2019-06-30 | 2019-07-05 | + | 2019-07-05 | ceil | 2020-01-01 | 2019-10-01 | 2019-08-01 | 2019-07-07 | 2019-07-05 | + | 2019-07-05 | floor | 2019-01-01 | 2019-07-01 | 2019-07-01 | 2019-06-30 | 2019-07-05 | +------------+-------+------------+------------+------------+------------+------------+ (2 rows) @@ -105,8 +105,8 @@ case when b then ceil(v to second) else floor(v to second) end as s +---------------------+-------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+ | V | OP | Y | Q | M | W | D | H | MI | S | +---------------------+-------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+ - | 2019-07-05 12:34:56 | ceil| 2020-01-01 00:00:00 | 2019-10-01 00:00:00 | 2019-08-01 00:00:00 | 2019-07-07 00:00:00 | 2019-07-06 00:00:00 | 2019-07-05 13:00:00 | 2019-07-05 12:35:00 | 2019-07-05 12:34:56 | - | 2019-07-05 12:34:56 | floor| 2019-01-01 00:00:00 | 2019-07-01 00:00:00 | 2019-07-01 00:00:00 | 2019-06-30 00:00:00 | 2019-07-05 00:00:00 | 2019-07-05 12:00:00 | 2019-07-05 12:34:00 | 2019-07-05 12:34:56 | + | 2019-07-05 12:34:56 | ceil | 2020-01-01 00:00:00 | 2019-10-01 00:00:00 | 2019-08-01 00:00:00 | 2019-07-07 00:00:00 | 2019-07-06 00:00:00 | 2019-07-05 13:00:00 | 2019-07-05 12:35:00 | 2019-07-05 12:34:56 | + | 2019-07-05 12:34:56 | floor | 2019-01-01 00:00:00 | 2019-07-01 00:00:00 | 2019-07-01 00:00:00 | 2019-06-30 00:00:00 | 2019-07-05 00:00:00 | 2019-07-05 12:00:00 | 2019-07-05 12:34:00 | 2019-07-05 12:34:56 | +---------------------+-------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+ (2 rows) @@ -120,8 +120,8 @@ case when b then ceil(v to second) else floor(v to second) end as s +------------+-------+------------+------------+------------+ | V | OP | H | MI | S | +------------+-------+------------+------------+------------+ - | 12:34:56.7 | ceil| 13:00:00.0 | 12:35:00.0 | 12:34:57.0 | - | 12:34:56.7 | floor| 12:00:00.0 | 12:34:00.0 | 12:34:56.0 | + | 12:34:56.7 | ceil | 13:00:00.0 | 12:35:00.0 | 12:34:57.0 | + | 12:34:56.7 | floor | 12:00:00.0 | 12:34:00.0 | 12:34:56.0 | +------------+-------+------------+------------+------------+ (2 rows)"""); } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OuterTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OuterTests.java index 68a9832a10f..43b090288a3 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OuterTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/OuterTests.java @@ -6,203 +6,203 @@ public class OuterTests extends PostBaseTests { @Test public void testOuter() { - this.qs(""" + this.qst(""" select * from emp; +-------+--------+--------+ | ENAME | DEPTNO | GENDER | +-------+--------+--------+ - | Jane| 10 | F| - | Bob| 10 | M| - | Eric| 20 | M| - | Susan| 30 | F| - | Alice| 30 | F| - | Adam| 50 | M| - | Eve| 50 | F| - | Grace| 60 | F| - | Wilma| | F| + | Jane | 10 | F | + | Bob | 10 | M | + | Eric | 20 | M | + | Susan | 30 | F | + | Alice | 30 | F | + | Adam | 50 | M | + | Eve | 50 | F | + | Grace | 60 | F | + | Wilma | | F | +-------+--------+--------+ (9 rows) - + select * from emp join dept on emp.deptno = dept.deptno; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Bob| 10 | M| 10 | Sales| - | Eric| 20 | M| 20 | Marketing| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| + | Jane | 10 | F | 10 | Sales | + | Bob | 10 | M | 10 | Sales | + | Eric | 20 | M | 20 | Marketing | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | +-------+--------+--------+---------+-------------+ (5 rows) - + select * from emp join dept on emp.deptno = dept.deptno and emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Alice| 30 | F| 30 | Engineering| - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| + | Alice | 30 | F | 30 | Engineering | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | +-------+--------+--------+---------+-------------+ (3 rows) - + select * from emp join dept on emp.deptno = dept.deptno where emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | +-------+--------+--------+---------+-------------+ (3 rows) - + select * from (select * from emp where gender ='F') as emp join dept on emp.deptno = dept.deptno; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | +-------+--------+--------+---------+-------------+ (3 rows) - + select * from emp left join dept on emp.deptno = dept.deptno and emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Adam| 50 | M| |NULL | - | Alice| 30 | F| 30 | Engineering| - | Bob| 10 | M| |NULL | - | Eric| 20 | M| |NULL | - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Wilma| | F| |NULL | + | Adam | 50 | M | |NULL | + | Alice | 30 | F | 30 | Engineering | + | Bob | 10 | M | |NULL | + | Eric | 20 | M | |NULL | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Wilma | | F | |NULL | +-------+--------+--------+---------+-------------+ (9 rows) - + select * from emp left join dept on emp.deptno = dept.deptno where emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Wilma| | F| |NULL | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Wilma | | F | |NULL | +-------+--------+--------+---------+-------------+ (6 rows) - + select * from (select * from emp where gender ='F') as emp left join dept on emp.deptno = dept.deptno; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Wilma| | F| |NULL | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Wilma | | F | |NULL | +-------+--------+--------+---------+-------------+ (6 rows) - + select * from emp right join dept on emp.deptno = dept.deptno and emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Alice| 30 | F| 30 | Engineering| - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - |NULL | |NULL| 20 | Marketing| - |NULL | |NULL| 40 | Empty| + | Alice | 30 | F | 30 | Engineering | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + |NULL | |NULL | 20 | Marketing | + |NULL | |NULL | 40 | Empty | +-------+--------+--------+---------+-------------+ (5 rows) - + select * from emp right join dept on emp.deptno = dept.deptno where emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | +-------+--------+--------+---------+-------------+ (3 rows) - + select * from (select * from emp where gender ='F') as emp right join dept on emp.deptno = dept.deptno; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - |NULL | |NULL| 20 | Marketing| - |NULL | |NULL| 40 | Empty| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + |NULL | |NULL | 20 | Marketing | + |NULL | |NULL | 40 | Empty | +-------+--------+--------+---------+-------------+ (5 rows) - + select * from emp full join dept on emp.deptno = dept.deptno and emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Adam| 50 | M| |NULL | - | Alice| 30 | F| 30 | Engineering| - | Bob| 10 | M| |NULL | - | Eric| 20 | M| |NULL | - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Wilma| | F| |NULL | - |NULL | |NULL| 20 | Marketing| - |NULL | |NULL| 40 | Empty| + | Adam | 50 | M | |NULL | + | Alice | 30 | F | 30 | Engineering | + | Bob | 10 | M | |NULL | + | Eric | 20 | M | |NULL | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Wilma | | F | |NULL | + |NULL | |NULL | 20 | Marketing | + |NULL | |NULL | 40 | Empty | +-------+--------+--------+---------+-------------+ (11 rows) - + select * from emp full join dept on emp.deptno = dept.deptno where emp.gender = 'F'; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Wilma| | F| |NULL | + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Wilma | | F | |NULL | +-------+--------+--------+---------+-------------+ (6 rows) - + select * from (select * from emp where gender ='F') as emp full join dept on emp.deptno = dept.deptno; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Wilma| | F| |NULL | - |NULL | |NULL| 20 | Marketing| - |NULL | |NULL| 40 | Empty| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Wilma | | F | |NULL | + |NULL | |NULL | 20 | Marketing | + |NULL | |NULL | 40 | Empty | +-------+--------+--------+---------+-------------+ (8 rows) - + -- same as above, but expressed as a nestedLoop-join select * from (select * from emp where gender ='F') as emp full join dept on emp.deptno - dept.deptno = 0; +-------+--------+--------+---------+-------------+ | ENAME | DEPTNO | GENDER | DEPTNO0 | DNAME | +-------+--------+--------+---------+-------------+ - | Jane| 10 | F| 10 | Sales| - | Susan| 30 | F| 30 | Engineering| - | Alice| 30 | F| 30 | Engineering| - | Eve| 50 | F| |NULL | - | Grace| 60 | F| |NULL | - | Wilma| | F| |NULL | - |NULL | |NULL| 20 | Marketing| - |NULL | |NULL| 40 | Empty| + | Jane | 10 | F | 10 | Sales | + | Susan | 30 | F | 30 | Engineering | + | Alice | 30 | F | 30 | Engineering | + | Eve | 50 | F | |NULL | + | Grace | 60 | F | |NULL | + | Wilma | | F | |NULL | + |NULL | |NULL | 20 | Marketing | + |NULL | |NULL | 40 | Empty | +-------+--------+--------+---------+-------------+ (8 rows) - + -- [CALCITE-554] Outer join over NULL keys generates wrong result with t1(x) as (select * from (values (1),(2), (case when 1 = 1 then null else 3 end)) as t(x)), t2(x) as (select * from (values (1),(case when 1 = 1 then null else 3 end)) as t(x)) @@ -215,7 +215,7 @@ with t1(x) as (select * from (values (1),(2), (case when 1 = 1 then null else 3 | | +---+ (3 rows) - + -- Equivalent query, using CAST, and skipping unnecessary aliases -- (Postgres doesn't like the missing alias, or the missing parentheses.) with t1(x) as (select * from (values 1, 2, cast(null as integer))), @@ -229,7 +229,7 @@ with t1(x) as (select * from (values 1, 2, cast(null as integer))), | | +---+ (3 rows) - + -- Similar query, projecting left and right key columns with t1(x) as (select * from (values (1), (2), (cast(null as integer))) as t), t2(x) as (select * from (values (1), (cast(null as integer))) as t) @@ -242,7 +242,7 @@ with t1(x) as (select * from (values (1), (2), (cast(null as integer))) as t), | | | +---+---+ (3 rows) - + -- Similar, with 2 columns on each side projecting both columns with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer), 30)) as t), t2(x, y) as (select * from (values (1, 100), (cast(null as integer), 200)) as t) @@ -255,7 +255,7 @@ with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer) | | 30 | | | +---+----+----+-----+ (3 rows) - + -- Similar, full join with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer), 30)) as t), t2(x, y) as (select * from (values (1,100), (cast(null as integer), 200)) as t) @@ -274,7 +274,7 @@ with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer) @Test public void testNullableOuter() { // Validated on Postgres - this.q(""" + this.qst(""" with t1(x, y) as (select * from (values (1, 'aa'), (2, 'b'), (null, 'c')) as t), t2(y, x) as (select * from (values ('d', 1), ('b', 2)) as t) select * from t1 full join t2 on t1.x = t2.x and t1.y = t2.y; @@ -282,12 +282,12 @@ with t1(x, y) as (select * from (values (1, 'aa'), (2, 'b'), (null, 'c')) as t), | X | Y | Y | X | +---+---+----+-----+ | 1 | aa|NULL| | - | 2 | b| b| 2 | - | | c|NULL| | - | |NULL| d| 1 | + | 2 | b | b | 2 | + | | c |NULL| | + | |NULL| d | 1 | +---+---+----+-----+ - (4 rows)"""); - this.q(""" + (4 rows) + with t1(x, y, z) as (select * from (values (1, 'aa', 1.0), (2, 'b', 2.0), (null, 'c', 3.0)) as t), t2(y, x, w) as (select * from (values ('d', 1, 1.0), ('b', 2, 2.0)) as t) select * from t1 full join t2 on t1.x = t2.x and t1.y = t2.y; @@ -295,12 +295,12 @@ with t1(x, y, z) as (select * from (values (1, 'aa', 1.0), (2, 'b', 2.0), (null, | X | Y | Z | Y | X | W | +---+---+----+----+-----+----+ | 1 | aa| 1.0|NULL| | | - | 2 | b| 2.0| b| 2 | 2.0| - | | c| 3.0|NULL| | | - | |NULL| | d| 1 | 1.0| + | 2 | b | 2.0| b | 2 | 2.0| + | | c | 3.0|NULL| | | + | |NULL| | d | 1 | 1.0| +---+---+----+-----+----+----+ - (4 rows)"""); - this.q(""" + (4 rows) + with t1(x, y) as (select * from (values (1, 10), (2, 20), (null, 30)) as t), t2(y, x) as (select * from (values (100,1), (20, 2)) as t) select * from t1 full join t2 on t1.x = t2.x and t1.x = t2.y; @@ -313,6 +313,6 @@ with t1(x, y) as (select * from (values (1, 10), (2, 20), (null, 30)) as t), | | | 100| 1 | | | | 20 | 2 | +---+----+----+-----+ - (4 rows)"""); + (5 rows)"""); } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/PostgresTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/PostgresTests.java index 3cd815b7242..5c86f6d901b 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/PostgresTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/PostgresTests.java @@ -7,7 +7,7 @@ public class PostgresTests extends SqlIoTest { @Test public void testGreatestIgnoreNulls() { - this.qs(""" + this.qst(""" SELECT greatest_ignore_nulls(1, 2, 3) as x; X --- @@ -41,7 +41,7 @@ public void testGreatestIgnoreNulls() { @Test public void testGreatest() { - this.qs(""" + this.qst(""" SELECT greatest(1, 2, 3) as x; X --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/RedshiftTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/RedshiftTests.java index e8c6386322c..0359123f4da 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/RedshiftTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/RedshiftTests.java @@ -7,7 +7,7 @@ public class RedshiftTests extends ScottBaseTests { @Test public void testFirstValue() { - this.qs(""" + this.qst(""" select empno, first_value(sal) over (order by empno range between unbounded preceding and unbounded following) from emp where deptno = 30 order by 1; EMPNO | EXPR$1 @@ -23,7 +23,7 @@ select empno, first_value(sal) over (order by empno range between unbounded prec @Test public void testRank() { - this.qs(""" + this.qst(""" select rank() over (partition by deptno order by sal) from emp; EXPR$0 -------- @@ -46,7 +46,7 @@ public void testRank() { @Test public void testLag() { - this.qs(""" + this.qst(""" select empno, lag(sal) respect nulls over (order by empno) from emp where deptno = 30 order by 1; EMPNO | EXPR$1 @@ -75,7 +75,7 @@ select empno, lag(sal, 2) respect nulls over (order by empno) @Test public void testRegexpReplace() { - this.qs(""" + this.qst(""" select regexp_replace('DonecFri@semperpretiumneque.com', '@.*\\.(org|gov|com)$'); result -------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SelectTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SelectTests.java index 31908ff2aa8..a51a79cf570 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SelectTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SelectTests.java @@ -7,7 +7,7 @@ public class SelectTests extends ScottBaseTests { @Test public void testExclude() { // issue 5216 - this.qs(""" + this.qst(""" select * exclude(empno, ename, job, mgr) from emp order by hiredate limit 1; +------------+--------+------+--------+ | HIREDATE | SAL | COMM | DEPTNO | diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortHrTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortHrTests.java index e5ff02316f5..f5f89b460dd 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortHrTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortHrTests.java @@ -6,15 +6,15 @@ public class SortHrTests extends HrBaseTests { @Test public void testSort() { - this.qs(""" + this.qst(""" select * from "emps" offset 0; +-------+--------+-----------+---------+------------+ | empid | deptno | name | salary | commission | +-------+--------+-----------+---------+------------+ - | 100 | 10 | Bill| 10000.0 | 1000 | - | 110 | 10 | Theodore| 11500.0 | 250 | - | 150 | 10 | Sebastian| 7000.0 | | - | 200 | 20 | Eric| 8000.0 | 500 | + | 100 | 10 | Bill | 10000.0 | 1000 | + | 110 | 10 | Theodore | 11500.0 | 250 | + | 150 | 10 | Sebastian | 7000.0 | | + | 200 | 20 | Eric | 8000.0 | 500 | +-------+--------+-----------+---------+------------+ (4 rows) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortTests.java index 77d549c733c..9d0a87a1f89 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SortTests.java @@ -5,16 +5,16 @@ /** Tests from Calcite's sort.iq */ public class SortTests extends FoodmartBaseTests { @Test public void testSortOffset() { - this.qs(""" + this.qst(""" select * from dept order by deptno offset 1; +--------+------------+---------+ | DEPTNO | DNAME | LOC | +--------+------------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| - | 40 | OPERATIONS| BOSTON| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | + | 40 | OPERATIONS | BOSTON | +--------+------------+---------+ (3 rows) @@ -24,46 +24,46 @@ public class SortTests extends FoodmartBaseTests { +--------+------------+---------+ | DEPTNO | DNAME | LOC | +--------+------------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| - | 40 | OPERATIONS| BOSTON| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | + | 40 | OPERATIONS | BOSTON | +--------+------------+---------+ (3 rows)"""); } @Test public void testSort() { - this.qs(""" + this.qst(""" select * from "days" order by "day"; +-----+----------+ | day | week_day | - +-----+-------+ - | 1 | Sunday| - | 2 | Monday| - | 3 | Tuesday| + +-----+----------+ + | 1 | Sunday | + | 2 | Monday | + | 3 | Tuesday | | 4 | Wednesday| - | 5 | Thursday| - | 6 | Friday| - | 7 | Saturday| - +-----+-------+ + | 5 | Thursday | + | 6 | Friday | + | 7 | Saturday | + +-----+----------+ (7 rows) select * from "days" order by "day" limit 2; +-----+----------+ | day | week_day | - +-----+-------+ - | 1 | Sunday| - | 2 | Monday| - +-----+-------+ + +-----+----------+ + | 1 | Sunday | + | 2 | Monday | + +-----+----------+ (2 rows) select * from "days" where "day" between 2 and 4 order by "day"; +-----+-----------+ | day | week_day | +-----+-----------+ - | 2 | Monday| - | 3 | Tuesday| - | 4 | Wednesday| + | 2 | Monday | + | 3 | Tuesday | + | 4 | Wednesday | +-----+-----------+ (3 rows) @@ -121,10 +121,10 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 40 | OPERATIONS| BOSTON| - | 30 | SALES| CHICAGO| - | 20 | RESEARCH| DALLAS| - | 10 | ACCOUNTING| NEW YORK| + | 40 | OPERATIONS | BOSTON | + | 30 | SALES | CHICAGO | + | 20 | RESEARCH | DALLAS | + | 10 | ACCOUNTING | NEW YORK | +--------+------------+----------+ (4 rows) @@ -134,8 +134,8 @@ public void testSort() { +--------+----------+---------+ | DEPTNO | DNAME | LOC | +--------+----------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | +--------+----------+---------+ (2 rows) @@ -145,8 +145,8 @@ public void testSort() { +--------+----------+---------+ | DEPTNO | DNAME | LOC | +--------+----------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | +--------+----------+---------+ (2 rows) @@ -156,8 +156,8 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 10 | ACCOUNTING| NEW YORK| - | 20 | RESEARCH| DALLAS| + | 10 | ACCOUNTING | NEW YORK | + | 20 | RESEARCH | DALLAS | +--------+------------+----------+ (2 rows) @@ -167,8 +167,8 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 10 | ACCOUNTING| NEW YORK| - | 20 | RESEARCH| DALLAS| + | 10 | ACCOUNTING | NEW YORK | + | 20 | RESEARCH | DALLAS | +--------+------------+----------+ (2 rows) @@ -178,10 +178,10 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 10 | ACCOUNTING| NEW YORK| - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| - | 40 | OPERATIONS| BOSTON| + | 10 | ACCOUNTING | NEW YORK | + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | + | 40 | OPERATIONS | BOSTON | +--------+------------+----------+ (4 rows) @@ -191,8 +191,8 @@ public void testSort() { +--------+----------+---------+ | DEPTNO | DNAME | LOC | +--------+----------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | +--------+----------+---------+ (2 rows) @@ -202,8 +202,8 @@ public void testSort() { +--------+----------+---------+ | DEPTNO | DNAME | LOC | +--------+----------+---------+ - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | +--------+----------+---------+ (2 rows) @@ -213,8 +213,8 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 10 | ACCOUNTING| NEW YORK| - | 20 | RESEARCH| DALLAS| + | 10 | ACCOUNTING | NEW YORK | + | 20 | RESEARCH | DALLAS | +--------+------------+----------+ (2 rows) @@ -224,10 +224,10 @@ public void testSort() { +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ - | 10 | ACCOUNTING| NEW YORK| - | 20 | RESEARCH| DALLAS| - | 30 | SALES| CHICAGO| - | 40 | OPERATIONS| BOSTON| + | 10 | ACCOUNTING | NEW YORK | + | 20 | RESEARCH | DALLAS | + | 30 | SALES | CHICAGO | + | 40 | OPERATIONS | BOSTON | +--------+------------+----------+ (4 rows) """); diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StreamTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StreamTests.java index 3945afe5a34..b343987ba71 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StreamTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StreamTests.java @@ -38,7 +38,7 @@ public void testNegativeTumble() { @Test public void testTumble() { - this.qs(""" + this.qst(""" SELECT * FROM TABLE( TUMBLE( DATA => TABLE ORDERS, @@ -47,11 +47,11 @@ public void testTumble() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (5 rows) @@ -59,11 +59,11 @@ public void testTumble() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (5 rows) @@ -71,11 +71,11 @@ public void testTumble() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:16:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:24:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:58:00.000 | 2015-02-15 10:59:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:11:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (5 rows) @@ -83,32 +83,32 @@ public void testTumble() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:13:00.000 | 2015-02-15 10:23:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:23:00.000 | 2015-02-15 10:33:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:23:00.000 | 2015-02-15 10:33:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:53:00.000 | 2015-02-15 11:03:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:03:00.000 | 2015-02-15 11:13:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:13:00.000 | 2015-02-15 10:23:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:23:00.000 | 2015-02-15 10:33:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:23:00.000 | 2015-02-15 10:33:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:53:00.000 | 2015-02-15 11:03:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:03:00.000 | 2015-02-15 11:13:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (5 rows)"""); } @Test public void testHop() { - this.qs(""" + this.qst(""" SELECT * FROM TABLE(HOP(TABLE ORDERS, DESCRIPTOR(ROWTIME), INTERVAL '5' MINUTE, INTERVAL '10' MINUTE)); +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (10 rows) @@ -121,16 +121,16 @@ public void testHop() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (10 rows) @@ -138,37 +138,37 @@ public void testHop() { +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:10:00.000 | 2015-02-15 10:20:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:15:00.000 | 2015-02-15 10:25:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:20:00.000 | 2015-02-15 10:30:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:50:00.000 | 2015-02-15 11:00:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:55:00.000 | 2015-02-15 11:05:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:05:00.000 | 2015-02-15 11:15:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.000 | 2015-02-15 11:20:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (10 rows)"""); } @Test public void testHop4() { - this.qs(""" + this.qst(""" SELECT * FROM TABLE(HOP(TABLE ORDERS, DESCRIPTOR(ROWTIME), INTERVAL '5' MINUTE, INTERVAL '10' MINUTE, INTERVAL '2' MINUTE)); +---------------------+----+---------+-------+-------------------------+-------------------------+ | ROWTIME | ID | PRODUCT | UNITS | window_start | window_end | +---------------------+----+---------+-------+-------------------------+-------------------------+ - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:07:00.000 | 2015-02-15 10:17:00.000 | - | 2015-02-15 10:15:00 | 1 | paint| 10 | 2015-02-15 10:12:00.000 | 2015-02-15 10:22:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:17:00.000 | 2015-02-15 10:27:00.000 | - | 2015-02-15 10:24:15 | 2 | paper| 5 | 2015-02-15 10:22:00.000 | 2015-02-15 10:32:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:17:00.000 | 2015-02-15 10:27:00.000 | - | 2015-02-15 10:24:45 | 3 | brush| 12 | 2015-02-15 10:22:00.000 | 2015-02-15 10:32:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:52:00.000 | 2015-02-15 11:02:00.000 | - | 2015-02-15 10:58:00 | 4 | paint| 3 | 2015-02-15 10:57:00.000 | 2015-02-15 11:07:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:02:00.000 | 2015-02-15 11:12:00.000 | - | 2015-02-15 11:10:00 | 5 | paint| 3 | 2015-02-15 11:07:00.000 | 2015-02-15 11:17:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:07:00.000 | 2015-02-15 10:17:00.000 | + | 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:12:00.000 | 2015-02-15 10:22:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:17:00.000 | 2015-02-15 10:27:00.000 | + | 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:22:00.000 | 2015-02-15 10:32:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:17:00.000 | 2015-02-15 10:27:00.000 | + | 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:22:00.000 | 2015-02-15 10:32:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:52:00.000 | 2015-02-15 11:02:00.000 | + | 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:57:00.000 | 2015-02-15 11:07:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:02:00.000 | 2015-02-15 11:12:00.000 | + | 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:07:00.000 | 2015-02-15 11:17:00.000 | +---------------------+----+---------+-------+-------------------------+-------------------------+ (10 rows)"""); } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StructTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StructTests.java index 2d1d5b70ae7..3512eb0cc8d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StructTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/StructTests.java @@ -6,7 +6,7 @@ public class StructTests extends ScottBaseTests { @Test public void isNullRow() { - this.qs(""" + this.qst(""" SELECT ROW(NULL) IS NULL; r --- @@ -16,7 +16,7 @@ public void isNullRow() { @Test public void testRow() { - this.qs(""" + this.qst(""" -- struct.iq - Queries involving structured types -- [CALCITE-2677] Struct types with one field are not mapped correctly to Java Classes select * from (values @@ -87,10 +87,10 @@ public void testRow() { +--------+----------+---+ | DEPTNO | JOB | X | +--------+----------+---+ - | 20 | CLERK| 1 | - | 20 | MANAGER| 3 | - | 30 | SALESMAN| 2 | - | 30 | SALESMAN| 2 | + | 20 | CLERK | 1 | + | 20 | MANAGER | 3 | + | 30 | SALESMAN | 2 | + | 30 | SALESMAN | 2 | +--------+----------+---+ (4 rows) @@ -106,10 +106,10 @@ public void testRow() { +--------+----------+---+ | DEPTNO | JOB | X | +--------+----------+---+ - | 20 | CLERK| 1 | - | 20 | MANAGER| 3 | - | 30 | SALESMAN| 2 | - | 30 | SALESMAN| 2 | + | 20 | CLERK | 1 | + | 20 | MANAGER | 3 | + | 30 | SALESMAN | 2 | + | 30 | SALESMAN | 2 | +--------+----------+---+ (4 rows) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SubQueryTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SubQueryTests.java index 823c1a60e33..1a79006985f 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SubQueryTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/SubQueryTests.java @@ -6,7 +6,7 @@ public class SubQueryTests extends ScottBaseTests { @Test public void wellKnownCountBug() { - this.qs(""" + this.qst(""" SELECT * from emp as e where exists ( @@ -17,20 +17,20 @@ where exists ( +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ - | 7369 | SMITH| CLERK| 7902 | 1980-12-17 | 800.00 | | 20 | - | 7499 | ALLEN| SALESMAN| 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | - | 7521 | WARD| SALESMAN| 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | - | 7566 | JONES| MANAGER| 7839 | 1981-02-04 | 2975.00 | | 20 | - | 7654 | MARTIN| SALESMAN| 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | - | 7698 | BLAKE| MANAGER| 7839 | 1981-01-05 | 2850.00 | | 30 | - | 7782 | CLARK| MANAGER| 7839 | 1981-06-09 | 2450.00 | | 10 | - | 7788 | SCOTT| ANALYST| 7566 | 1987-04-19 | 3000.00 | | 20 | - | 7839 | KING| PRESIDENT| | 1981-11-17 | 5000.00 | | 10 | - | 7844 | TURNER| SALESMAN| 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | - | 7876 | ADAMS| CLERK| 7788 | 1987-05-23 | 1100.00 | | 20 | - | 7900 | JAMES| CLERK| 7698 | 1981-12-03 | 950.00 | | 30 | - | 7902 | FORD| ANALYST| 7566 | 1981-12-03 | 3000.00 | | 20 | - | 7934 | MILLER| CLERK| 7782 | 1982-01-23 | 1300.00 | | 10 | + | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | | 20 | + | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | + | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | + | 7566 | JONES | MANAGER | 7839 | 1981-02-04 | 2975.00 | | 20 | + | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | + | 7698 | BLAKE | MANAGER | 7839 | 1981-01-05 | 2850.00 | | 30 | + | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | | 10 | + | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | | 20 | + | 7839 | KING | PRESIDENT | | 1981-11-17 | 5000.00 | | 10 | + | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | + | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | | 20 | + | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | | 30 | + | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | | 20 | + | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ (14 rows) @@ -102,7 +102,7 @@ inner join ( @Test public void testOrderByLimit() { // Validated using MySQL - this.qs(""" + this.qst(""" SELECT comm AS comm FROM EMP where 30 = EMP.deptno ORDER BY comm limit 1; @@ -128,14 +128,14 @@ public void testOrderByLimit() { public void firstValueTests() { // All these produce calls to FIRST_VALUE from the expansion // Modified and tested on MySQL, since Calcite treats NULLs differently. - this.qs(""" + this.qst(""" SELECT dname FROM DEPT WHERE 2000 > (SELECT EMP.sal FROM EMP where DEPT.deptno = EMP.deptno ORDER BY year(hiredate), EMP.sal limit 1); +----------+ | DNAME | +----------+ - | RESEARCH| - | SALES| + | RESEARCH | + | SALES | +----------+ (2 rows) @@ -158,10 +158,10 @@ public void firstValueTests() { +------------+--------+ | DNAME | EXPR$1 | +------------+--------+ - | ACCOUNTING| | - | OPERATIONS| | - | RESEARCH| | - | SALES| 1400 | + | ACCOUNTING | | + | OPERATIONS | | + | RESEARCH | | + | SALES | 1400 | +------------+--------+ (4 rows) @@ -173,10 +173,10 @@ ORDER BY year(hiredate), EMP.sal limit 1) +------------+---------+ | DNAME | EXPR$1 | +------------+---------+ - | ACCOUNTING| 2450.00 | - | OPERATIONS| | - | RESEARCH| 800.00 | - | SALES| 950.00 | + | ACCOUNTING | 2450.00 | + | OPERATIONS | | + | RESEARCH | 800.00 | + | SALES | 950.00 | +------------+---------+ (4 rows) @@ -188,17 +188,17 @@ ORDER BY year(hiredate), EMP.sal limit 1) +------------+--------+ | DNAME | EXPR$1 | +------------+--------+ - | ACCOUNTING| | - | OPERATIONS| | - | RESEARCH| | - | SALES| | + | ACCOUNTING | | + | OPERATIONS | | + | RESEARCH | | + | SALES | | +------------+--------+ (4 rows)"""); } @Test @Ignore("Cannot be decorrelated") public void testFirst1() { - this.qs(""" + this.qst(""" select sal from EMP e where mod(cast(rand() as int), 2) = 3 OR 123 IN ( select cast(null as int) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggPostTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggPostTests.java index c5ef092549a..946255675ea 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggPostTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggPostTests.java @@ -7,7 +7,7 @@ public class WinAggPostTests extends PostBaseTests { @Test @Ignore("ORDER BY strings not supported https://github.com/feldera/feldera/issues/457") public void test() { - this.qs(""" + this.qst(""" select deptno, ename, mode(gender) over (partition by deptno order by ENAME) as m @@ -148,19 +148,19 @@ select deptno, gender, min(ename) as x, sum(deptno) as y, public void test0() { // Constant argument to aggregate, issue 4010 // validated on Postgres - this.qs(""" + this.qst(""" select *, first_value(ename) over (partition by deptno order by gender range unbounded preceding) from emp; ename | deptno | gender | first_value -------+--------+--------+------------- - Jane| 10 | F| Jane - Bob| 10 | M| Jane - Eric| 20 | M| Eric - Alice| 30 | F| Alice - Susan| 30 | F| Alice - Eve| 50 | F| Eve - Adam| 50 | M| Eve - Grace| 60 | F| Grace - Wilma| | F| Wilma + Jane | 10 | F | Jane + Bob | 10 | M | Jane + Eric | 20 | M | Eric + Alice | 30 | F | Alice + Susan | 30 | F | Alice + Eve | 50 | F | Eve + Adam | 50 | M | Eve + Grace | 60 | F | Grace + Wilma | | F | Wilma (9 rows) select gender,deptno, @@ -169,18 +169,18 @@ public void test0() { +--------+--------+--------+ | gender | deptno | count1 | +--------+--------+--------+ - | F| 10 | 1 | - | F| 30 | 2 | - | F| 30 | 2 | - | F| 50 | 1 | - | F| 60 | 1 | - | F| | 1 | - | M| 10 | 1 | - | M| 20 | 1 | - | M| 50 | 1 | + | F | 10 | 1 | + | F | 30 | 2 | + | F | 30 | 2 | + | F | 50 | 1 | + | F | 60 | 1 | + | F | | 1 | + | M | 10 | 1 | + | M | 20 | 1 | + | M | 50 | 1 | +--------+--------+--------+ (9 rows)"""); - this.qs(""" + this.qst(""" -- [CALCITE-1540] Support multiple columns in PARTITION BY clause of window function select gender,deptno, count(*) over (partition by gender,deptno) as count1 @@ -188,15 +188,15 @@ public void test0() { +--------+--------+--------+ | GENDER | DEPTNO | COUNT1 | +--------+--------+--------+ - | F| 10 | 1 | - | F| 30 | 2 | - | F| 30 | 2 | - | F| 50 | 1 | - | F| 60 | 1 | - | F| | 1 | - | M| 10 | 1 | - | M| 20 | 1 | - | M| 50 | 1 | + | F | 10 | 1 | + | F | 30 | 2 | + | F | 30 | 2 | + | F | 50 | 1 | + | F | 60 | 1 | + | F | | 1 | + | M | 10 | 1 | + | M | 20 | 1 | + | M | 50 | 1 | +--------+--------+--------+ (9 rows) @@ -208,15 +208,15 @@ public void test0() { +--------+--------+--------+ | GENDER | DEPTNO | COUNT1 | +--------+--------+--------+ - | F| 10 | 6 | - | F| 30 | 6 | - | F| 30 | 6 | - | F| 50 | 6 | - | F| 60 | 6 | - | F| | 6 | - | M| 10 | 3 | - | M| 20 | 3 | - | M| 50 | 3 | + | F | 10 | 6 | + | F | 30 | 6 | + | F | 30 | 6 | + | F | 50 | 6 | + | F | 60 | 6 | + | F | | 6 | + | M | 10 | 3 | + | M | 20 | 3 | + | M | 50 | 3 | +--------+--------+--------+ (9 rows)"""); } @@ -227,53 +227,53 @@ public void test2() { // deterministic in our implementation, but they give a different result // than other SQL dialects. // Here the sorting is implicit on ename, deptno, gender - this.qs(""" + this.qst(""" select *, first_value(deptno) over () from emp; ename | deptno | gender | first_value -------+--------+--------+------------- - Jane| 10 | F| 50 - Bob| 10 | M| 50 - Eric| 20 | M| 50 - Susan| 30 | F| 50 - Alice| 30 | F| 50 - Adam| 50 | M| 50 - Eve| 50 | F| 50 - Grace| 60 | F| 50 - Wilma| | F| 50 + Jane | 10 | F | 50 + Bob | 10 | M | 50 + Eric | 20 | M | 50 + Susan | 30 | F | 50 + Alice | 30 | F | 50 + Adam | 50 | M | 50 + Eve | 50 | F | 50 + Grace | 60 | F | 50 + Wilma | | F | 50 (9 rows)"""); - this.qs(""" + this.qst(""" select *, first_value(ename) over () from emp; ename | deptno | gender | first_value -------+--------+--------+------------- - Jane| 10 | F| Adam - Bob| 10 | M| Adam - Eric| 20 | M| Adam - Susan| 30 | F| Adam - Alice| 30 | F| Adam - Adam| 50 | M| Adam - Eve| 50 | F| Adam - Grace| 60 | F| Adam - Wilma| | F| Adam + Jane | 10 | F | Adam + Bob | 10 | M | Adam + Eric | 20 | M | Adam + Susan | 30 | F | Adam + Alice | 30 | F | Adam + Adam | 50 | M | Adam + Eve | 50 | F | Adam + Grace | 60 | F | Adam + Wilma | | F | Adam (9 rows) select *, first_value(ename) over (partition by deptno) from emp; ename | deptno | gender | first_value -------+--------+--------+------------- - Jane| 10 | F| Bob - Bob| 10 | M| Bob - Eric| 20 | M| Eric - Susan| 30 | F| Alice - Alice| 30 | F| Alice - Adam| 50 | M| Adam - Eve| 50 | F| Adam - Grace| 60 | F| Grace - Wilma| | F| Wilma + Jane | 10 | F | Bob + Bob | 10 | M | Bob + Eric | 20 | M | Eric + Susan | 30 | F | Alice + Alice | 30 | F | Alice + Adam | 50 | M | Adam + Eve | 50 | F | Adam + Grace | 60 | F | Grace + Wilma | | F | Wilma (9 rows)"""); } @Test public void test3() { - this.qs(""" + this.qst(""" -- No ORDER BY, windows defined in WINDOW clause. select deptno, gender, min(gender) over w1 as a, min(gender) over w2 as d from emp @@ -282,15 +282,15 @@ window w1 as (), +--------+--------+---+---+ | DEPTNO | GENDER | A | D | +--------+--------+---+---+ - | 10 | F| F| F| - | 10 | M| F| F| - | 20 | M| F| M| - | 30 | F| F| F| - | 30 | F| F| F| - | 50 | F| F| F| - | 50 | M| F| F| - | 60 | F| F| F| - | | F| F| F| + | 10 | F | F | F | + | 10 | M | F | F | + | 20 | M | F | M | + | 30 | F | F | F | + | 30 | F | F | F | + | 50 | F | F | F | + | 50 | M | F | F | + | 60 | F | F | F | + | | F | F | F | +--------+--------+---+---+ (9 rows) @@ -299,15 +299,15 @@ window w1 as (), +-------+--------+--------+---+ | ENAME | DEPTNO | GENDER | C | +-------+--------+--------+---+ - | Adam| 50 | M| 2 | - | Alice| 30 | F| 2 | - | Bob| 10 | M| 2 | - | Eric| 20 | M| 1 | - | Eve| 50 | F| 2 | - | Grace| 60 | F| 1 | - | Jane| 10 | F| 2 | - | Susan| 30 | F| 2 | - | Wilma| | F| 1 | + | Adam | 50 | M | 2 | + | Alice | 30 | F | 2 | + | Bob | 10 | M | 2 | + | Eric | 20 | M | 1 | + | Eve | 50 | F | 2 | + | Grace | 60 | F | 1 | + | Jane | 10 | F | 2 | + | Susan | 30 | F | 2 | + | Wilma | | F | 1 | +-------+--------+--------+---+ (9 rows) @@ -318,22 +318,22 @@ select deptno, gender, count(gender, deptno) over w1 as a +--------+--------+---+ | DEPTNO | GENDER | A | +--------+--------+---+ - | 10 | F| 8 | - | 10 | M| 8 | - | 20 | M| 8 | - | 30 | F| 8 | - | 30 | F| 8 | - | 50 | F| 8 | - | 50 | M| 8 | - | 60 | F| 8 | - | | F| 8 | + | 10 | F | 8 | + | 10 | M | 8 | + | 20 | M | 8 | + | 30 | F | 8 | + | 30 | F | 8 | + | 50 | F | 8 | + | 50 | M | 8 | + | 60 | F | 8 | + | | F | 8 | +--------+--------+---+ (9 rows)"""); } @Test @Ignore("unsupported aggregate functions") public void test4() { - this.qs(""" + this.qst(""" -- NTH_VALUE select emp."ENAME", emp."DEPTNO", nth_value(emp."DEPTNO", 1) over() as "first_value", @@ -345,15 +345,15 @@ public void test4() { +-------+--------+-------------+--------------+-------------+--------------+-------------+ | ENAME | DEPTNO | first_value | second_value | fifth_value | eighth_value | tenth_value | +-------+--------+-------------+--------------+-------------+--------------+-------------+ - | Adam| 50 | 10 | 10 | 30 | 60 | | - | Alice| 30 | 10 | 10 | 30 | 60 | | - | Bob| 10 | 10 | 10 | 30 | 60 | | - | Eric| 20 | 10 | 10 | 30 | 60 | | - | Eve| 50 | 10 | 10 | 30 | 60 | | - | Grace| 60 | 10 | 10 | 30 | 60 | | - | Jane| 10 | 10 | 10 | 30 | 60 | | - | Susan| 30 | 10 | 10 | 30 | 60 | | - | Wilma| | 10 | 10 | 30 | 60 | | + | Adam | 50 | 10 | 10 | 30 | 60 | | + | Alice | 30 | 10 | 10 | 30 | 60 | | + | Bob | 10 | 10 | 10 | 30 | 60 | | + | Eric | 20 | 10 | 10 | 30 | 60 | | + | Eve | 50 | 10 | 10 | 30 | 60 | | + | Grace | 60 | 10 | 10 | 30 | 60 | | + | Jane | 10 | 10 | 10 | 30 | 60 | | + | Susan | 30 | 10 | 10 | 30 | 60 | | + | Wilma | | 10 | 10 | 30 | 60 | | +-------+--------+-------------+--------------+-------------+--------------+-------------+ (9 rows) @@ -502,38 +502,38 @@ public void test4() { @Test public void testWindows1() { // Adjusted and validated using MySQL - this.qs(""" + this.qst(""" select *, count(*) over (order by deptno) as c from emp; ENAME | DEPTNO | GENDER | C -------+--------+--------+--- - Jane| 10 | F| 3 - Bob| 10 | M| 3 - Eric| 20 | M| 4 - Susan| 30 | F| 6 - Alice| 30 | F| 6 - Adam| 50 | M| 8 - Eve| 50 | F| 8 - Grace| 60 | F| 9 - Wilma| | F| 1 + Jane | 10 | F | 3 + Bob | 10 | M | 3 + Eric | 20 | M | 4 + Susan | 30 | F | 6 + Alice | 30 | F | 6 + Adam | 50 | M | 8 + Eve | 50 | F | 8 + Grace | 60 | F | 9 + Wilma | | F | 1 (9 rows)"""); } @Test public void testRank() { - this.qs(""" + this.qst(""" select *, rank() over (order by deptno NULLS LAST) as c from emp; +-------+--------+--------+---+ | ENAME | DEPTNO | GENDER | C | +-------+--------+--------+---+ - | Adam| 50 | M| 6 | - | Alice| 30 | F| 4 | - | Bob| 10 | M| 1 | - | Eric| 20 | M| 3 | - | Eve| 50 | F| 6 | - | Grace| 60 | F| 8 | - | Jane| 10 | F| 1 | - | Susan| 30 | F| 4 | - | Wilma| | F| 9 | + | Adam | 50 | M | 6 | + | Alice | 30 | F | 4 | + | Bob | 10 | M | 1 | + | Eric | 20 | M | 3 | + | Eve | 50 | F | 6 | + | Grace | 60 | F | 8 | + | Jane | 10 | F | 1 | + | Susan | 30 | F | 4 | + | Wilma | | F | 9 | +-------+--------+--------+---+ (9 rows) @@ -542,15 +542,15 @@ public void testRank() { +-------+--------+--------+---+ | ENAME | DEPTNO | GENDER | C | +-------+--------+--------+---+ - | Adam| 50 | M| 4 | - | Alice| 30 | F| 3 | - | Bob| 10 | M| 1 | - | Eric| 20 | M| 2 | - | Eve| 50 | F| 4 | - | Grace| 60 | F| 5 | - | Jane| 10 | F| 1 | - | Susan| 30 | F| 3 | - | Wilma| | F| 6 | + | Adam | 50 | M | 4 | + | Alice | 30 | F | 3 | + | Bob | 10 | M | 1 | + | Eric | 20 | M | 2 | + | Eve | 50 | F | 4 | + | Grace | 60 | F | 5 | + | Jane | 10 | F | 1 | + | Susan | 30 | F | 3 | + | Wilma | | F | 6 | +-------+--------+--------+---+ (9 rows)"""); } @@ -558,7 +558,7 @@ public void testRank() { @Test public void testRowDifferentPartitions() { // Validated on Postgres by making the query deterministic - this.qs(""" + this.qst(""" select *, row_number() over (order by deptno /*, ename, gender */) as r1, row_number() over (partition by deptno order by gender desc /*, ename */) as r2 @@ -566,15 +566,15 @@ public void testRowDifferentPartitions() { +-------+--------+--------+----+----+ | ENAME | DEPTNO | GENDER | R1 | R2 | +-------+--------+--------+----+----+ - | Wilma| | F| 1 | 1 | - | Bob| 10 | M| 2 | 1 | - | Jane| 10 | F| 3 | 2 | - | Eric| 20 | M| 4 | 1 | - | Alice| 30 | F| 5 | 1 | - | Susan| 30 | F| 6 | 2 | - | Adam| 50 | M| 7 | 1 | - | Eve| 50 | F| 8 | 2 | - | Grace| 60 | F| 9 | 1 | + | Wilma | | F | 1 | 1 | + | Bob | 10 | M | 2 | 1 | + | Jane | 10 | F | 3 | 2 | + | Eric | 20 | M | 4 | 1 | + | Alice | 30 | F | 5 | 1 | + | Susan | 30 | F | 6 | 2 | + | Adam | 50 | M | 7 | 1 | + | Eve | 50 | F | 8 | 2 | + | Grace | 60 | F | 9 | 1 | +-------+--------+--------+----+----+ (9 rows)"""); } @@ -585,7 +585,7 @@ public void testWindows2() { // Had to adjust results, since sorting is deterministic in Feldera. // Validated on Postgres by making the query deterministic by uncommenting // the commented-out sort helpers - this.qs(""" + this.qst(""" -- [CALCITE-806] ROW_NUMBER should emit distinct values select *, row_number() over (order by deptno /* nulls first, ename, gender */) as r1, @@ -597,15 +597,15 @@ public void testWindows2() { +-------+--------+--------+----+----+----+----+---+ | ENAME | DEPTNO | GENDER | R1 | R2 | R3 | R4 | R | +-------+--------+--------+----+----+----+----+---+ - | Wilma| | F| 1 | 1 | 1 | 6 | 9 | - | Bob| 10 | M| 2 | 1 | 2 | 2 | 3 | - | Jane| 10 | F| 3 | 2 | 1 | 4 | 7 | - | Eric| 20 | M| 4 | 1 | 1 | 3 | 4 | - | Alice| 30 | F| 5 | 1 | 1 | 1 | 2 | - | Susan| 30 | F| 6 | 2 | 2 | 5 | 8 | - | Adam| 50 | M| 7 | 1 | 2 | 1 | 1 | - | Eve| 50 | F| 8 | 2 | 1 | 2 | 5 | - | Grace| 60 | F| 9 | 1 | 1 | 3 | 6 | + | Wilma | | F | 1 | 1 | 1 | 6 | 9 | + | Bob | 10 | M | 2 | 1 | 2 | 2 | 3 | + | Jane | 10 | F | 3 | 2 | 1 | 4 | 7 | + | Eric | 20 | M | 4 | 1 | 1 | 3 | 4 | + | Alice | 30 | F | 5 | 1 | 1 | 1 | 2 | + | Susan | 30 | F | 6 | 2 | 2 | 5 | 8 | + | Adam | 50 | M | 7 | 1 | 2 | 1 | 1 | + | Eve | 50 | F | 8 | 2 | 1 | 2 | 5 | + | Grace | 60 | F | 9 | 1 | 1 | 3 | 6 | +-------+--------+--------+----+----+----+----+---+ (9 rows) @@ -619,19 +619,19 @@ public void testWindows2() { +--------+-------+---+ | DEPTNO | ENAME | R | +--------+-------+---+ - | 10 | Jane| 1 | - | 30 | Alice| 1 | - | 30 | Susan| 2 | - | 50 | Eve| 1 | - | 60 | Grace| 1 | - | | Wilma| 1 | + | 10 | Jane | 1 | + | 30 | Alice | 1 | + | 30 | Susan | 2 | + | 50 | Eve | 1 | + | 60 | Grace | 1 | + | | Wilma | 1 | +--------+-------+---+ (6 rows)"""); } @Test public void testWindows3() { - this.qs(""" + this.qst(""" -- [CALCITE-2271] Two windows under a JOIN 2 select t1.l, t1.key as key1, t2.key as key2 @@ -665,7 +665,7 @@ public void testWindows3() { @Test public void testCountIf() { - this.qs(""" + this.qst(""" -- COUNTIF(b) (BigQuery) is equivalent to COUNT(*) FILTER (WHERE b) select deptno, countif(gender = 'F') as f from emp @@ -703,7 +703,7 @@ select countif(a > 0) + countif(a > 1) + countif(c > 1) as c @Test public void testGrouping3() { - this.qs(""" + this.qst(""" -- [CALCITE-4665] Allow Aggregate.groupKey to be a strict superset of -- Aggregate.groupKeys -- Use a condition on grouping_id to filter out the superset grouping sets. @@ -718,15 +718,15 @@ having grouping_id(ename, deptno, gender) <> 0 +-------+--------+--------+-----+-----+-----+ | ENAME | DEPTNO | GENDER | G_E | G_D | G_G | +-------+--------+--------+-----+-----+-----+ - | Adam| 50 |NULL| 0 | 0 | 1 | - | Adam| |NULL| 0 | 1 | 1 | - | Bob| 10 |NULL| 0 | 0 | 1 | - | Bob| |NULL| 0 | 1 | 1 | - | Eric| 20 |NULL| 0 | 0 | 1 | - | Eric| |NULL| 0 | 1 | 1 | - |NULL| 10 |NULL| 1 | 0 | 1 | - |NULL| 20 |NULL| 1 | 0 | 1 | - |NULL| 50 |NULL| 1 | 0 | 1 | + | Adam | 50 |NULL | 0 | 0 | 1 | + | Adam | |NULL | 0 | 1 | 1 | + | Bob | 10 |NULL | 0 | 0 | 1 | + | Bob | |NULL | 0 | 1 | 1 | + | Eric | 20 |NULL | 0 | 0 | 1 | + | Eric | |NULL | 0 | 1 | 1 | + |NULL | 10 |NULL | 1 | 0 | 1 | + |NULL | 20 |NULL | 1 | 0 | 1 | + |NULL | 50 |NULL | 1 | 0 | 1 | +-------+--------+--------+-----+-----+-----+ (9 rows) @@ -740,15 +740,15 @@ group by grouping sets (ename, deptno, (ename, deptno)) +-------+--------+-----+-----+ | ENAME | DEPTNO | G_E | G_D | +-------+--------+-----+-----+ - | Adam| 50 | 0 | 0 | - | Adam| | 0 | 1 | - | Bob| 10 | 0 | 0 | - | Bob| | 0 | 1 | - | Eric| 20 | 0 | 0 | - | Eric| | 0 | 1 | - |NULL| 10 | 1 | 0 | - |NULL| 20 | 1 | 0 | - |NULL| 50 | 1 | 0 | + | Adam | 50 | 0 | 0 | + | Adam | | 0 | 1 | + | Bob | 10 | 0 | 0 | + | Bob | | 0 | 1 | + | Eric | 20 | 0 | 0 | + | Eric | | 0 | 1 | + |NULL | 10 | 1 | 0 | + |NULL | 20 | 1 | 0 | + |NULL | 50 | 1 | 0 | +-------+--------+-----+-----+ (9 rows) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggTests.java index 6cdb64d404e..d6dd7bd0dbd 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/quidem/WinAggTests.java @@ -7,7 +7,7 @@ public class WinAggTests extends ScottBaseTests { @Test public void testWindows0() { - this.qs(""" + this.qst(""" select empno, deptno, count(*) over (order by deptno) c1, count(*) over (order by deptno range unbounded preceding) c2, @@ -37,7 +37,7 @@ public void testWindows0() { @Test @Ignore("ROWS not yet implemented in WINDOW https://github.com/feldera/feldera/issues/457") public void testWindows() { - this.qs(""" + this.qst(""" -- Check default brackets. Note that: -- c2 and c3 are equivalent to c1; -- c5 is equivalent to c4; diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/AggregateTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/AggregateTests.java index 4bb2e738dcd..3d1d757c7de 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/AggregateTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/AggregateTests.java @@ -54,7 +54,7 @@ CREATE TABLE NN ( @Test public void issue2042() { - this.qs(""" + this.qst(""" SELECT ARG_MAX(I, I), ARG_MAX(I, J), ARG_MAX(J, I), ARG_MAX(J, J) FROM NN; ii | ij | ji | jj @@ -89,7 +89,7 @@ SELECT K, ARG_MIN(I, I), ARG_MIN(I, J), ARG_MIN(J, I), ARG_MIN(J, J) @Test public void testIssue1957() { // validated using Postgres - this.qs(""" + this.qst(""" SELECT id, (SELECT ARRAY_AGG(id) FROM ( @@ -111,7 +111,7 @@ public void testIssue1957() { @Test public void issue4777() { // validated using Postgres, but second result is not deterministic - this.qs(""" + this.qst(""" SELECT ARRAY_AGG(parentId ORDER BY id) FROM warehouse; array @@ -207,7 +207,7 @@ FROM TABLE( @Test public void testArrayConstructor() { - this.qs(""" + this.qst(""" SELECT id, (SELECT ARRAY( @@ -225,7 +225,7 @@ public void testArrayConstructor() { 30 | { 3, 5, 20 } (6 rows)"""); - this.qs(""" + this.qst(""" SELECT id, (SELECT ARRAY( @@ -247,7 +247,7 @@ public void testArrayConstructor() { @Test public void testOneArgMin() { - this.qs(""" + this.qst(""" SELECT ARG_MIN(V, B) FROM T; B @@ -296,13 +296,13 @@ public void endVisit() { @Test public void testArgMin() { - this.qs(""" + this.qst(""" SELECT ARG_MIN(V, B), ARG_MIN(V, I), ARG_MIN(V, S), ARG_MIN(V, T), ARG_MIN(V, R), ARG_MIN(V, D), ARG_MIN(V, E) FROM T; B | I | S | T | R | D | E --------------------------- - 0| 0| 0| 0| 0| 0| 0 + 0 | 0 | 0 | 0 | 0 | 0 | 0 (1 row) SELECT ARG_MAX(V, B), ARG_MAX(V, I), ARG_MAX(V, S), ARG_MAX(V, T), @@ -310,13 +310,13 @@ SELECT ARG_MAX(V, B), ARG_MAX(V, I), ARG_MAX(V, S), ARG_MAX(V, T), FROM T; B | I | S | T | R | D | E --------------------------- - 2| 2| 2| 2| 2| 2| 2 + 2 | 2 | 2 | 2 | 2 | 2 | 2 (1 row)"""); } @Test public void testAggregates() { - this.qs(""" + this.qst(""" SELECT COUNT(*), COUNT(B), COUNT(I), COUNT(S), COUNT(T), COUNT(R), COUNT(D), COUNT(E) FROM T; * | B | I | S | T | R | D | E ------------------------------- @@ -386,7 +386,7 @@ public void testAggregates() { @Test public void testDistinctAggregates() { - this.qs(""" + this.qst(""" SELECT COUNT(*), COUNT(DISTINCT B), COUNT(DISTINCT I), COUNT(DISTINCT S), COUNT(DISTINCT T), COUNT(DISTINCT R), COUNT(DISTINCT D), COUNT(DISTINCT E) FROM T; * | B | I | S | T | R | D | E ------------------------------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/ArrayFunctionsTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/ArrayFunctionsTests.java index 6f4527ec28d..f51522b80a4 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/ArrayFunctionsTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/ArrayFunctionsTests.java @@ -6,7 +6,7 @@ public class ArrayFunctionsTests extends SqlIoTest { @Test public void testArrayAppend() { - this.qs(""" + this.qst(""" SELECT array_append(ARRAY [1, 2], null::int); array_append -------------- @@ -38,7 +38,7 @@ public void testArrayAppend() { public void testArrayConcat() { this.statementsFailingInCompilation("CREATE VIEW V AS SELECT array_concat()", "Invalid number of arguments to function"); - this.qs(""" + this.qst(""" SELECT array_concat(array[1, 2], array[2, 3]); r --- @@ -66,7 +66,7 @@ public void testArrayConcat() { @Test public void testArrayExcept() { - this.qs(""" + this.qst(""" SELECT array_except(array[2, 3, 3], array[2]); r --- @@ -106,7 +106,7 @@ public void testArrayExcept() { @Test public void testArrayUnion() { - this.qs(""" + this.qst(""" select array_union(array[2, 3, 3], array[3]); r --- @@ -140,7 +140,7 @@ public void testArrayUnion() { @Test public void testArrayRepeat() { - this.qs(""" + this.qst(""" SELECT array_repeat(3, 3); array_repeat -------------- @@ -176,7 +176,7 @@ public void testArrayRepeat() { @Test public void testArrayRepeat2() { - this.qs(""" + this.qst(""" SELECT array_repeat(123, null); array_repeat -------------- @@ -188,7 +188,7 @@ public void testArrayRepeat2() { @Test public void testArrayRepeat3() { - this.qs(""" + this.qst(""" SELECT array_repeat('a', 6); array_repeat -------------- @@ -200,7 +200,7 @@ public void testArrayRepeat3() { @Test public void testArrayPosition() { - this.qs(""" + this.qst(""" SELECT array_position(ARRAY [2, 4, 6, 8, null], null); array_position ---------------- @@ -255,7 +255,7 @@ public void testArrayPosition() { @Test public void testArrayContains() { - this.qs(""" + this.qst(""" SELECT array_contains(ARRAY [2, 4, 6, 8, null], 4); array_contains --------------- @@ -297,7 +297,7 @@ public void testArrayContains() { @Test public void testArrayPositionDiffTypes() { - this.qs(""" + this.qst(""" SELECT array_position(ARRAY [1, 2, 3, 4], 1e0); result -------- @@ -319,7 +319,7 @@ public void testArrayPositionDiffTypes() { @Test public void testArrayContainsDiffTypes() { - this.qs(""" + this.qst(""" SELECT array_contains(ARRAY [1, 2, 3, 4], 1e0); result -------- @@ -341,7 +341,7 @@ public void testArrayContainsDiffTypes() { @Test public void testArrayRemoveDiffTypes() { - this.qs(""" + this.qst(""" SELECT array_remove(ARRAY [1, 2, 3, 4], 1e0); result -------- @@ -363,7 +363,7 @@ public void testArrayRemoveDiffTypes() { @Test public void testArrayRemove() { - this.qs(""" + this.qst(""" SELECT array_remove(ARRAY [2, 2, 6, 6, 8, 2], 2); array_remove -------------- @@ -431,7 +431,7 @@ public void testNullArray() { @Test public void testArrayPrepend() { - this.qs(""" + this.qst(""" SELECT array_prepend(ARRAY [2, 3], 1); array_prepend --------------- @@ -479,7 +479,7 @@ public void testArrayPrepend() { @Test public void testCardinality() { - this.qs(""" + this.qst(""" SELECT cardinality(ARRAY [1]); cardinality ------------- @@ -503,7 +503,7 @@ public void testCardinality() { @Test public void testSortArray() { - this.qs(""" + this.qst(""" SELECT sort_array(ARRAY [7, 1, 4, 3]); sort_array ------------ @@ -569,7 +569,7 @@ public void testSortArray() { @Test public void testArraySize() { - this.qs(""" + this.qst(""" SELECT cardinality(ARRAY [1, 2, 3]); array_size ------------ @@ -616,7 +616,7 @@ public void testArraySize() { @Test public void testArrayReverse() { - this.qs(""" + this.qst(""" SELECT ARRAY_REVERSE(ARRAY [2, 3, 3]); array_reverse --------------- @@ -652,7 +652,7 @@ public void testArrayReverse() { @Test public void testArrayMinMax() { - this.qs(""" + this.qst(""" SELECT array_max(ARRAY [9, 1, 2, 4, 8]); array_max ----------- @@ -683,7 +683,7 @@ public void testArrayMinMax() { // Test for https://github.com/feldera/feldera/issues/1472 @Test public void testArrayCompact2() { - this.qs(""" + this.qst(""" SELECT array_compact(ARRAY [NULL]); array_compact --------------- @@ -694,7 +694,7 @@ public void testArrayCompact2() { @Test public void testArrayCompact() { - this.qs(""" + this.qst(""" SELECT array_compact(ARRAY [1, null, 2, null]); array_compact --------------- @@ -754,7 +754,7 @@ public void testArrayCompact() { @Test public void testArrayDistinct() { - this.qs(""" + this.qst(""" SELECT array_distinct(ARRAY [1, 1, 2, 2, 3, 3]); array_distinct ---------------- @@ -829,7 +829,7 @@ public void issue3272() { @Test public void testArraysOverlap() { - this.qs(""" + this.qst(""" SELECT ARRAYS_OVERLAP(null, null); arrays_overlap ---------------- @@ -929,7 +929,7 @@ public void testArraysOverlapDiffTypes() { @Test public void testArrayAgg() { // Tests from https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate_functions#array_agg - this.qs(""" + this.qst(""" SELECT ARRAY_AGG(x) AS array_agg FROM UNNEST(ARRAY [2, 1,-2, 3, -2, 1, 2]) AS x; +-------------------------+ | array_agg | @@ -978,7 +978,7 @@ SELECT x, ARRAY_AGG(y) as array_agg @Test public void testOverArrayAgg() { // The order of the elements in the array is non-deterministic - this.qs(""" + this.qst(""" SELECT x, ARRAY_AGG(x) OVER (ORDER BY ABS(x)) AS array_agg @@ -999,7 +999,7 @@ public void testOverArrayAgg() { @Test public void testArrayIntersect() { - this.qs(""" + this.qst(""" select array_intersect(array[2, 3, 3], array[3]); r --- @@ -1039,7 +1039,7 @@ public void testArrayIntersect() { @Test public void testArrayInsert() { - this.qs(""" + this.qst(""" select array_insert(cast(null as integer array), 3, 4); r --- @@ -1144,7 +1144,7 @@ public void testArrayInsert() { @Test public void testExists() { - this.qs(""" + this.qst(""" SELECT array_EXISTS(array[1, 2, 3], x -> x > 2); result ------ @@ -1265,7 +1265,7 @@ public void testArrayExistsTable() { @Test public void testTransform() { - this.qs(""" + this.qst(""" SELECT transform(array[1, 2, 3], x -> x + 3); result ------ diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CalciteSqlOperatorTest.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CalciteSqlOperatorTest.java index 3bcb38349c5..5ca69515e39 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CalciteSqlOperatorTest.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CalciteSqlOperatorTest.java @@ -7,7 +7,7 @@ public class CalciteSqlOperatorTest extends SqlIoTest { @Test public void testIf() { - this.qs(""" + this.qst(""" SELECT if(1 = 2, 1, 2); result -------- @@ -53,7 +53,7 @@ public void testIf() { @Test public void testRegexReplace2Func() { - this.qs(""" + this.qst(""" select regexp_replace('a b c', 'b'); r --- @@ -81,6 +81,7 @@ public void testRegexReplace2Func() { @Test public void testRegexReplace3Func() { + // Spaces are significant in these outputs this.qs(""" select regexp_replace('a b c', 'b', 'X'); r @@ -181,7 +182,7 @@ select regexp_replace('abc\t @Test public void testDocs() { - this.qs(""" + this.qst(""" select regexp_replace('1078910', '[^01]'); r ----- @@ -209,7 +210,7 @@ public void testDocs() { @Test public void testConcatWithSeparator() { - this.qs(""" + this.qst(""" select concat_ws(',', 'a'); r --- @@ -276,7 +277,7 @@ public void testConcatWithSeparator() { @Test public void testMapContainsKey() { - this.qs(""" + this.qst(""" select map_contains_key(map[1, 'a', 2, 'b'], 1); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CastTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CastTests.java index 14d50e927c2..a096f512081 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CastTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/CastTests.java @@ -156,7 +156,7 @@ public void runtimeOverflowsTests() { @Test public void mixedTypesTest() { - this.qs("SELECT CAST(100 AS UNSIGNED) - 10;" + + this.qst("SELECT CAST(100 AS UNSIGNED) - 10;" + """ t --- @@ -202,7 +202,7 @@ public void mixedTypesTest() { @Test public void timeCastTests() { - this.qs(""" + this.qst(""" SELECT CAST(1000 AS TIMESTAMP); t --- @@ -254,7 +254,7 @@ public void timeCastTests() { @Test public void testCastStringToComplexLongInterval() { - this.qs(""" + this.qst(""" SELECT CAST('1-1' AS INTERVAL YEAR TO MONTH); i --- @@ -276,7 +276,7 @@ public void testCastStringToComplexLongInterval() { @Test public void testCastStringToComplexShortInterval() { - this.qs(""" + this.qst(""" SELECT CAST('100 1' AS INTERVAL DAY TO HOUR); i --- @@ -304,7 +304,7 @@ public void testCastStringToComplexShortInterval() { @Test public void testCastStringToComplexShortInterval2() { - this.qs(""" + this.qst(""" SELECT CAST('10 10:1' AS INTERVAL DAYS TO MINUTES); i --- @@ -344,7 +344,7 @@ public void testCastStringToComplexShortInterval2() { @Test public void testCastStringToComplexShortInterval1() { - this.qs(""" + this.qst(""" SELECT CAST('100:1' AS INTERVAL MINUTES TO SECONDS); i --- @@ -384,7 +384,7 @@ public void testCastStringToComplexShortInterval1() { @Test public void testCastStringToSimpleInterval() { - this.qs(""" + this.qst(""" SELECT CAST('1' AS INTERVAL YEAR); i --- @@ -718,7 +718,7 @@ enum CanConvert { @Test public void issue5894() { - this.qs(""" + this.qst(""" SELECT INTERVAL '1' YEAR; r --- @@ -762,7 +762,7 @@ public void issue5895() { @Test public void issue6257() { // Calcite rounds by truncating, so we are tied to that behavior - this.qs(""" + this.qst(""" SELECT CAST(INTERVAL '10' DAY AS BIGINT); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/DateArithmeticTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/DateArithmeticTests.java index 57dcde5b98a..70f94dd1742 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/DateArithmeticTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/DateArithmeticTests.java @@ -6,7 +6,7 @@ public class DateArithmeticTests extends SqlIoTest { @Test public void testTimeAddInterval() { - this.qs(""" + this.qst(""" SELECT DATE '2024-01-01' + INTERVAL '10' MINUTES; date ---------- @@ -186,7 +186,7 @@ public void testTimeAddInterval() { @Test public void testTimeSubInterval() { - this.qs(""" + this.qst(""" SELECT DATE '2024-01-01' - INTERVAL '10' MINUTES; date ---------- @@ -358,7 +358,7 @@ public void testTimeSubInterval() { @Test public void testDateSub() { - this.qs(""" + this.qst(""" SELECT (date '2023-12-01' - date '2022-12-01') days; diff ------ @@ -394,7 +394,7 @@ public void testDateSub() { ------ 334 days ago (1 row)"""); - this.qs(""" + this.qst(""" SELECT (TIMESTAMP '2023-01-01 10:00:00' - TIMESTAMP '2023-12-01 10:00:00') month; diff ------ @@ -404,7 +404,7 @@ public void testDateSub() { @Test public void makeDateTests() { - this.qs(""" + this.qst(""" SELECT MAKE_DATE(2020, 1, 1); r --- @@ -465,7 +465,7 @@ public void makeDateTests() { @Test public void makeTimestampTests() { - this.qs(""" + this.qst(""" SELECT MAKE_TIMESTAMP(2020, 1, 1, 10, 0, 0); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/LateralAliasTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/LateralAliasTests.java index 2372dfc922d..3451f7ac903 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/LateralAliasTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/LateralAliasTests.java @@ -15,7 +15,7 @@ public void prepareInputs(DBSPCompiler compiler) { @Test public void lateralTest() { // Tests from the SQL documentation in docs/sql/identifiers.md - this.qs(""" + this.qst(""" SELECT 1 as X, X+X as Y; x | y ------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/OuterJoinTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/OuterJoinTests.java index d46d6e2e24a..1ced2b3533d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/OuterJoinTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/OuterJoinTests.java @@ -112,7 +112,7 @@ public void testCommonIndex() { @Test public void testPredicatePullLeftJoin() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L LEFT JOIN A AS R ON L.X = R.X and L.Y = 0; lx | ly | lx | ly ------------------- @@ -241,7 +241,7 @@ public void testPredicatePullLeftJoin() { @Test public void testPredicatePullRightJoin() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L RIGHT JOIN A AS R ON L.X = R.X and L.Y = 0; lx | ly | lx | ly ------------------- @@ -362,7 +362,7 @@ public void testPredicatePullRightJoin() { @Test public void testStandadJoinCondition() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L LEFT JOIN A AS R ON L.X = R.X and L.Y = R.Y; lx | ly | lx | ly ------------------- @@ -483,7 +483,7 @@ public void testStandadJoinCondition() { @Test public void testNonEqui() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L LEFT JOIN A AS R ON L.X < R.X and L.Y = R.Y; lx | ly | lx | ly ------------------- @@ -604,7 +604,7 @@ public void testNonEqui() { @Test public void testDistinct() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L LEFT JOIN A AS R ON L.X IS NOT DISTINCT FROM R.X and L.Y IS NOT DISTINCT FROM R.Y; lx | ly | lx | ly ------------------- @@ -725,7 +725,7 @@ public void testDistinct() { @Test public void testMix() { // validated on postgres - this.qs(""" + this.qst(""" SELECT * FROM A AS L LEFT JOIN A AS R ON L.X = R.X and L.Y IS NOT DISTINCT FROM R.Y; lx | ly | lx | ly ------------------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/PivotTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/PivotTests.java index 5bd98a233d3..82782e8d96f 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/PivotTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/PivotTests.java @@ -38,21 +38,18 @@ Create Table GG ( @Test public void testGroupby() { - this.q(""" + this.qst(""" SELECT CourseName, Sum(Price) FROM GG GROUP BY CourseName; - CourseName | Price - ----------------- - C| 5000 - JAVA| 6000 - PLACEMENT 100| 5000 - PYTHON| 8000"""); - } - - @Test - public void testGGPivot() { - this.q(""" + CourseName | Price + ---------------------- + C | 5000 + JAVA | 6000 + PLACEMENT 100 | 5000 + PYTHON | 8000 + (4 rows) + SELECT CourseName, PG, IV FROM GG PIVOT ( @@ -61,17 +58,18 @@ public void testGGPivot() { 'INTERVIEWPREPARATION' AS IV ) ) AS PivotTable; - CourseName | PG | IV - ----------------- - C| 5000 | NULL - JAVA| 6000 | NULL - PLACEMENT 100| NULL | 5000 - PYTHON| 8000 | NULL"""); + CourseName | PG | IV + ----------------------------- + C | 5000 | NULL + JAVA | 6000 | NULL + PLACEMENT 100 | NULL | 5000 + PYTHON | 8000 | NULL + (4 rows)"""); } @Test public void testSparkPivot() { - this.q(""" + this.qst(""" SELECT * FROM person PIVOT ( SUM(age) AS a, AVG(class) AS cc @@ -80,13 +78,13 @@ FOR name IN ('John' AS john, 'Mike' AS mike) +------+-----------+---------+---------+---------+---------+ | id | address | john_a | john_cc | mike_a | mike_cc | +------+-----------+---------+---------+---------+---------+ - | 200 | Street 2| NULL | NULL | NULL | NULL | - | 100 | Street 1| 30 | 1 | NULL | NULL | - | 300 | Street 3| NULL | NULL | 80 | 3 | - | 400 | Street 4| NULL | NULL | NULL | NULL | + | 200 | Street 2 | NULL | NULL | NULL | NULL | + | 100 | Street 1 | 30 | 1 | NULL | NULL | + | 300 | Street 3 | NULL | NULL | 80 | 3 | + | 400 | Street 4 | NULL | NULL | NULL | NULL | +------+-----------+---------+---------+---------+---------+ - """); - this.q(""" + (4 rows) + SELECT * FROM person PIVOT ( SUM(age) AS a, AVG(class) AS cc @@ -95,25 +93,27 @@ FOR name IN ('John' AS john, 'Mike' AS mike) +------+-----------+-------+-------+-------+-------+ | id | address | c1_a | c1_cc | c2_a | c2_cc | +------+-----------+-------+-------+-------+-------+ - | 200 | Street 2| NULL | NULL | NULL | NULL | - | 100 | Street 1| 30 | 1 | NULL | NULL | - | 300 | Street 3| NULL | NULL | NULL | NULL | - | 400 | Street 4| NULL | NULL | NULL | NULL | - +------+-----------+-------+-------+-------+-------+"""); + | 200 | Street 2 | NULL | NULL | NULL | NULL | + | 100 | Street 1 | 30 | 1 | NULL | NULL | + | 300 | Street 3 | NULL | NULL | NULL | NULL | + | 400 | Street 4 | NULL | NULL | NULL | NULL | + +------+-----------+-------+-------+-------+-------+ + (4 rows)"""); } @Test public void testPivotDoc() { - this.q(""" + this.qst(""" SELECT year, type, SUM(count) FROM FURNITURE GROUP BY year, type; year | type | sum ----------------- - 2020 | chair| 4 - 2021 | table| 3 - 2021 | chair| 4 - 2023 | desk| 1 - 2023 | table| 2"""); - this.q(""" + 2020 | chair | 4 + 2021 | table | 3 + 2021 | chair | 4 + 2023 | desk | 1 + 2023 | table | 2 + (5 rows) + SELECT * FROM FURNITURE PIVOT ( SUM(count) AS ct @@ -124,6 +124,6 @@ FOR type IN ('desk' AS desks, 'table' AS tables, 'chair' as chairs) 2020 | | | 4 2021 | | 3 | 4 2023 | 1 | 2 | - """); + (3 rows)"""); } } diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java index 5ab2906f4b7..83493b18714 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java @@ -255,7 +255,7 @@ NOT EXISTS ( @Test public void issue4562() { - this.qs(""" + this.qst(""" SELECT TIMESTAMPADD(MINUTE, 2, '2020-06-21 14:23:44.123'::TIMESTAMP); r --- @@ -508,7 +508,7 @@ public void issue4263() { @Test public void issue4264() { - this.qs(""" + this.qst(""" SELECT TRIM(trailing '' FROM 'x'); result -------- @@ -757,6 +757,7 @@ CREATE TABLE row_tbl( @Test public void issue5087() { + // Spaces are significant this.qs(""" SELECT '1 2' AS r; @@ -1422,7 +1423,7 @@ CREATE TABLE tbl(id INT, @Test public void testBinaryStringCast() { - this.qs(""" + this.qst(""" SELECT bin2utf8(x'404141'); r --- @@ -1632,7 +1633,7 @@ public void issue5352() { @Test public void issue5352_a() { - this.qs(""" + this.qst(""" SELECT 'TRUE'::BOOLEAN; r --- @@ -1876,7 +1877,7 @@ public void issue5380() { @Test public void safeArrayCast() { - this.qs(""" + this.qst(""" SELECT SAFE_CAST(ARRAY['a'] AS INT ARRAY); r --- @@ -1892,7 +1893,7 @@ public void safeArrayCast() { @Test public void safeNestedArrayCast() { - this.qs(""" + this.qst(""" SELECT SAFE_CAST(ARRAY[ARRAY['a']] AS INT ARRAY ARRAY); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression2Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression2Tests.java index 95b5e778020..cd913406d64 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression2Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression2Tests.java @@ -605,7 +605,7 @@ and exists ( @Test public void testBetween() { - this.qs(""" + this.qst(""" SELECT 1 BETWEEN 2 AND 0; r --- @@ -627,7 +627,7 @@ public void testBetween() { @Test public void testStdDevPop() { - this.qs(""" + this.qst(""" WITH T(x) as (VALUES(CAST(NULL AS DECIMAL(5, 2)))) SELECT STDDEV_POP(x) FROM T; r --- @@ -911,7 +911,7 @@ h DECIMAL(38, 10), @Test public void issue5981() { - this.qs(""" + this.qst(""" SELECT TO_HEX(x'48656c6c6f'); r --- @@ -992,7 +992,7 @@ public void issue5927() { @Test public void testXxHash() { - this.qs(""" + this.qst(""" SELECT XXHASH('abc', 2); r --- @@ -1061,7 +1061,7 @@ public void calciteIssue7501() { @Test public void testFiniteOrNull() { - this.qs(""" + this.qst(""" SELECT FINITE_OR_NULL(1e0); r --- @@ -1100,7 +1100,7 @@ public void issue6181() { r --- NULL"""); - this.qs(""" + this.qst(""" SELECT INTERVAL '+1' HOURS / 5; r --- @@ -1687,7 +1687,7 @@ public void issue4146() { @Test public void issue4146a() { // Validated on postgres - this.qs(""" + this.qst(""" SELECT COALESCE(NULL, TIMESTAMP WITH TIME ZONE '2020-01-01 10:10:10 America/New_York'); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java index 20c27e04fee..4503fb59274 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java @@ -618,7 +618,7 @@ CREATE TABLE T ( @Test public void issue6352() { - this.qs(""" + this.qst(""" SELECT SAFE_CAST('true' AS BOOL); r --- @@ -643,7 +643,7 @@ public void issue6352() { NULL (1 row)"""); - this.qs(""" + this.qst(""" SELECT SAFE_CAST('0.0' AS DOUBLE); r --- @@ -662,7 +662,7 @@ public void issue6352() { NULL (1 row)"""); - this.qs(""" + this.qst(""" SELECT SAFE_CAST('0.0' AS REAL); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/RegressionTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/RegressionTests.java index a89dd527325..f3392a6ce77 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/RegressionTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/RegressionTests.java @@ -1714,7 +1714,7 @@ public void missingCast() { @Test public void testDiv() { - this.qs(""" + this.qst(""" SELEct 95.0/100; r ---- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StringTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StringTests.java index 576889478b4..de95d44d779 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StringTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StringTests.java @@ -14,7 +14,7 @@ public void testReverseNegative() { @Test public void testReverse() { - this.qs(""" + this.qst(""" SELECT REVERSE('Feldera'); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StructTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StructTests.java index 950fbb150ad..8fee6572d94 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StructTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/StructTests.java @@ -23,9 +23,9 @@ public class StructTests extends SqlIoTest { @Test public void issue3262() { // Duplicates a test from CatalogTests, since programs with handles cannot be used to generate Rust tests. - var ccs = this.getCCS( - "CREATE TABLE fails (named_pairs MAP);" + - "CREATE VIEW V AS SELECT named_pairs['a'].k FROM fails;"); + var ccs = this.getCCS(""" + CREATE TABLE fails (named_pairs MAP); + CREATE VIEW V AS SELECT named_pairs['a'].k FROM fails;"""); ccs.stepWeightOne("INSERT INTO fails VALUES(MAP['a', ROW('2', '3'), 'b', NULL])", """ result diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeArithmeticTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeArithmeticTests.java index d994677d330..dab71732e12 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeArithmeticTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeArithmeticTests.java @@ -6,7 +6,7 @@ public class TimeArithmeticTests extends SqlIoTest { @Test public void testTimestampAddLongInterval() { - this.qs(""" + this.qst(""" SELECT TIMESTAMP '2024-01-01 10:23:45' + INTERVAL 10 MONTHS; ts --------------------- @@ -118,7 +118,7 @@ public void testTimestampAddLongInterval() { @Test public void testTimeAddInterval() { - this.qs(""" + this.qst(""" SELECT '23:00:00'::time + INTERVAL '10' MINUTES; time ---------- @@ -316,7 +316,7 @@ public void testTimeAddInterval() { @Test public void testTimeSubInterval() { - this.qs(""" + this.qst(""" SELECT '00:00:00'::time - INTERVAL '10' MINUTES; time -------- @@ -417,7 +417,7 @@ public void testTimeSubInterval() { @Test public void testTimeAddInterval1() { - this.qs(""" + this.qst(""" SELECT '12:34:56'::time + INTERVAL '25' DAYS; time --------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeTests.java index 46500c0cae7..b9361faad5d 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TimeTests.java @@ -253,7 +253,7 @@ public void timestampDiffTest() { @Test public void testMakeTime() { - this.qs(""" + this.qst(""" SELECT MAKE_TIME(1, 2, 3); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TinyintTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TinyintTests.java index 7ff6157a5ad..1ec95a8f917 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TinyintTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TinyintTests.java @@ -22,7 +22,7 @@ INSERT INTO INT_TBL(f1) VALUES @Test public void testSelect() { - this.qs( + this.qst( """ SELECT * FROM INT_TBL; f1 diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TrigonometryTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TrigonometryTests.java index 63259b630f3..190b2ceb6ce 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TrigonometryTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/TrigonometryTests.java @@ -7,7 +7,7 @@ public class TrigonometryTests extends SqlIoTest { // Tested using Postgres 15.2 @Test public void testSin() { - this.qs( + this.qst( """ SELECT sin(null); sin @@ -56,7 +56,7 @@ public void testSin() { // Tested using Postgres 15.2 @Test public void testSinDouble() { - this.qs( + this.qst( """ SELECT sin(CAST(0 AS DOUBLE)); sin @@ -93,7 +93,7 @@ public void testSinDouble() { // Tested using Postgres 15.2 @Test public void testCos() { - this.qs( + this.qst( """ SELECT cos(null); cos @@ -142,7 +142,7 @@ public void testCos() { // Tested using Postgres 15.2 @Test public void testCosDouble() { - this.qs( + this.qst( """ SELECT cos(CAST(0 AS DOUBLE)); cos @@ -191,7 +191,7 @@ public void testPi() { // Tested using Postgres 15.2 @Test public void testTan() { - this.qs( + this.qst( """ SELECT tan(null); tan @@ -240,7 +240,7 @@ public void testTan() { // Tested using Postgres 15.2 @Test public void testTanDouble() { - this.qs( + this.qst( """ SELECT tan(CAST(null as DOUBLE)); tan @@ -283,7 +283,7 @@ public void testTanDouble() { // Tested using Postgres 15.2 @Test public void testCot() { - this.qs( + this.qst( """ SELECT cot(0); cot @@ -332,7 +332,7 @@ public void testCot() { // Tested using Postgres 15.2 @Test public void testCotDouble() { - this.qs( + this.qst( """ SELECT cot(CAST(0 AS DOUBLE)); cot @@ -383,7 +383,7 @@ public void testCotDouble() { // Right now, we return a NaN, instead of throwing an error @Test public void testAsin() { - this.qs( + this.qst( """ SELECT asin(null); asin @@ -464,7 +464,7 @@ public void testAsin() { // Right now, we return a NaN, instead of throwing an error @Test public void testAsinDouble() { - this.qs( + this.qst( """ SELECT asin(CAST(-2 AS DOUBLE)); asin @@ -539,7 +539,7 @@ public void testAsinDouble() { // Right now, we return a NaN, instead of throwing an error @Test public void testAcos() { - this.qs( + this.qst( """ SELECT acos(null); acos @@ -620,7 +620,7 @@ public void testAcos() { // Right now, we return a NaN, instead of throwing an error @Test public void testAcosDouble() { - this.qs( + this.qst( """ SELECT acos(CAST(-2 AS DOUBLE)); acos @@ -693,7 +693,7 @@ public void testAcosDouble() { // Tested using Postgres 15.2 @Test public void testAtan() { - this.qs( + this.qst( """ SELECT atan(null); atan @@ -760,7 +760,7 @@ public void testAtan() { // Tested using Postgres 15.2 @Test public void testAtanDouble() { - this.qs( + this.qst( """ SELECT atan(CAST(null as DOUBLE)); atan @@ -827,7 +827,7 @@ public void testAtanDouble() { // Tested using Postgres 15.2 @Test public void testAtan2() { - this.qs( + this.qst( """ SELECT atan2(null, null); atan2 @@ -870,7 +870,7 @@ public void testAtan2() { // Tested using Postgres 15.2 @Test public void testAtan2Double() { - this.qs( + this.qst( """ SELECT atan2(CAST(0 AS DOUBLE), CAST(0 AS DOUBLE)); atan2 @@ -901,7 +901,7 @@ public void testAtan2Double() { // Tested using Postgres 15.2 @Test public void testRadians() { - this.qs( + this.qst( """ SELECT radians(null); radians @@ -956,7 +956,7 @@ public void testRadians() { // Tested using Postgres 15.2 @Test public void testRadiansDouble() { - this.qs( + this.qst( """ SELECT radians(CAST(null AS DOUBLE)); radians @@ -1011,7 +1011,7 @@ public void testRadiansDouble() { // Tested using Postgres 15.2 @Test public void testDegrees() { - this.qs( + this.qst( """ SELECT degrees(null); degrees @@ -1066,7 +1066,7 @@ public void testDegrees() { // Tested on Postgres @Test public void validInputs() { - this.qs( + this.qst( """ SELECT sin('-3'); sin @@ -1121,7 +1121,7 @@ public void invalidInputs() { // Tested on Apache Spark @Test public void testSec() { - this.qs(""" + this.qst(""" SELECT ROUND(sec(0.6), 12); sec ----------------- @@ -1152,7 +1152,7 @@ public void testSec() { // Tested on Apache Spark @Test public void testCsc() { - this.qs(""" + this.qst(""" SELECT csc(0.6); csc ----------------- @@ -1176,7 +1176,7 @@ public void testCsc() { @Test public void testHyperbolicFns() { - this.qs( + this.qst( """ SELECT ROUND(sinh(1), 12); sinh @@ -1249,7 +1249,7 @@ public void testHyperbolicFns() { @Test public void testArcHyperbolic() { - this.qs(""" + this.qst(""" SELECT asinh('Infinity'::float8); asinh ---------- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/VariantTests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/VariantTests.java index 4b3bbc53f04..de27aa1d0f2 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/VariantTests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/VariantTests.java @@ -501,7 +501,7 @@ public void testSparkInline() { @Test public void issue5938() { // type -> Variant -> string - this.qs(""" + this.qst(""" SELECT CAST(CAST(1 AS VARIANT) AS VARCHAR); r --- @@ -573,7 +573,7 @@ public void issue5938() { @Test public void issue5938a() { // String -> Variant -> type - this.qs(""" + this.qst(""" SELECT CAST(CAST('1' AS VARIANT) AS INT); r --- diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/SqlIoTest.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/SqlIoTest.java index 7b7766067fa..7808a7a6c06 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/SqlIoTest.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/tools/SqlIoTest.java @@ -290,6 +290,10 @@ public void qst(String queriesWithOutputs) { this.qs(queriesWithOutputs, TestOptimizations.Both, true); } + public void qst(String queriesWithOutputs, TestOptimizations to) { + this.qs(queriesWithOutputs, to, true); + } + public void qs(String queriesWithOutputs) { this.qs(queriesWithOutputs, TestOptimizations.Both, false); } From 4150b39205221f122bfdfa27bfb589f171829e1f Mon Sep 17 00:00:00 2001 From: "release-feldera-feldera[bot]" Date: Tue, 23 Jun 2026 05:50:52 +0000 Subject: [PATCH 4/7] ci: Prepare for v0.314.0 --- Cargo.lock | 42 +++++++++++------------ Cargo.toml | 26 +++++++------- openapi.json | 2 +- python/dbt-feldera/pyproject.toml | 2 +- python/felderize/pyproject.toml | 2 +- python/pyproject.toml | 2 +- python/uv.lock | 4 +-- sql-to-dbsp-compiler/SQL-compiler/pom.xml | 2 +- 8 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa76ac4b6a2..8fd21ea182d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3952,7 +3952,7 @@ dependencies = [ [[package]] name = "dbsp" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "arc-swap", @@ -4042,7 +4042,7 @@ dependencies = [ [[package]] name = "dbsp_adapters" -version = "0.313.0" +version = "0.314.0" dependencies = [ "actix", "actix-codec", @@ -4185,7 +4185,7 @@ dependencies = [ [[package]] name = "dbsp_nexmark" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "ascii_table", @@ -5157,7 +5157,7 @@ dependencies = [ [[package]] name = "fda" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "arrow", @@ -5209,7 +5209,7 @@ dependencies = [ [[package]] name = "feldera-adapterlib" -version = "0.313.0" +version = "0.314.0" dependencies = [ "actix-web", "anyhow", @@ -5243,7 +5243,7 @@ dependencies = [ [[package]] name = "feldera-buffer-cache" -version = "0.313.0" +version = "0.314.0" dependencies = [ "crossbeam-utils", "enum-map", @@ -5271,7 +5271,7 @@ dependencies = [ [[package]] name = "feldera-datagen" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "async-channel 2.5.0", @@ -5297,7 +5297,7 @@ dependencies = [ [[package]] name = "feldera-fxp" -version = "0.313.0" +version = "0.314.0" dependencies = [ "bytecheck", "dbsp", @@ -5317,7 +5317,7 @@ dependencies = [ [[package]] name = "feldera-iceberg" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "chrono", @@ -5339,7 +5339,7 @@ dependencies = [ [[package]] name = "feldera-ir" -version = "0.313.0" +version = "0.314.0" dependencies = [ "proptest", "proptest-derive", @@ -5351,7 +5351,7 @@ dependencies = [ [[package]] name = "feldera-macros" -version = "0.313.0" +version = "0.314.0" dependencies = [ "prettyplease", "proc-macro2", @@ -5361,7 +5361,7 @@ dependencies = [ [[package]] name = "feldera-observability" -version = "0.313.0" +version = "0.314.0" dependencies = [ "actix-http", "awc", @@ -5376,7 +5376,7 @@ dependencies = [ [[package]] name = "feldera-rest-api" -version = "0.313.0" +version = "0.314.0" dependencies = [ "chrono", "feldera-observability", @@ -5395,7 +5395,7 @@ dependencies = [ [[package]] name = "feldera-samply" -version = "0.313.0" +version = "0.314.0" dependencies = [ "crossbeam", "feldera-size-of", @@ -5431,7 +5431,7 @@ dependencies = [ [[package]] name = "feldera-sqllib" -version = "0.313.0" +version = "0.314.0" dependencies = [ "arcstr", "base58", @@ -5475,7 +5475,7 @@ dependencies = [ [[package]] name = "feldera-storage" -version = "0.313.0" +version = "0.314.0" dependencies = [ "anyhow", "crossbeam", @@ -5498,7 +5498,7 @@ dependencies = [ [[package]] name = "feldera-types" -version = "0.313.0" +version = "0.314.0" dependencies = [ "actix-web", "anyhow", @@ -8761,7 +8761,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pipeline-manager" -version = "0.313.0" +version = "0.314.0" dependencies = [ "actix-cors", "actix-files", @@ -9971,7 +9971,7 @@ dependencies = [ [[package]] name = "readers" -version = "0.313.0" +version = "0.314.0" dependencies = [ "async-std", "csv", @@ -11670,7 +11670,7 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "sltsqlvalue" -version = "0.313.0" +version = "0.314.0" dependencies = [ "dbsp", "feldera-sqllib", @@ -12024,7 +12024,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "storage-test-compat" -version = "0.313.0" +version = "0.314.0" dependencies = [ "dbsp", "derive_more 1.0.0", diff --git a/Cargo.toml b/Cargo.toml index 53f4846f506..17f6f29dd3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace.package] authors = ["Feldera Team "] -version = "0.313.0" +version = "0.314.0" license = "MIT OR Apache-2.0" homepage = "https://github.com/feldera/feldera" repository = "https://github.com/feldera/feldera" @@ -108,7 +108,7 @@ csv = "1.2.2" csv-core = "0.1.10" dashmap = "6.1.0" datafusion = "53.1" -dbsp = { path = "crates/dbsp", version = "0.313.0" } +dbsp = { path = "crates/dbsp", version = "0.314.0" } dbsp_nexmark = { path = "crates/nexmark" } deadpool-postgres = "0.14.1" # Feldera fork of delta-rs: upstream tag `rust-v0.32.3` + 2 patches, on branch @@ -133,20 +133,20 @@ erased-serde = "0.3.31" fake = "2.10" fastbloom = "0.14.0" fdlimit = "0.3.0" -feldera-buffer-cache = { version = "0.313.0", path = "crates/buffer-cache" } +feldera-buffer-cache = { version = "0.314.0", path = "crates/buffer-cache" } feldera-cloud1-client = "0.1.2" feldera-datagen = { path = "crates/datagen" } -feldera-fxp = { version = "0.313.0", path = "crates/fxp", features = ["dbsp"] } +feldera-fxp = { version = "0.314.0", path = "crates/fxp", features = ["dbsp"] } feldera-iceberg = { path = "crates/iceberg" } -feldera-observability = { version = "0.313.0", path = "crates/feldera-observability" } -feldera-macros = { version = "0.313.0", path = "crates/feldera-macros" } -feldera-sqllib = { version = "0.313.0", path = "crates/sqllib" } -feldera-storage = { version = "0.313.0", path = "crates/storage" } -feldera-types = { version = "0.313.0", path = "crates/feldera-types" } -feldera-rest-api = { version = "0.313.0", path = "crates/rest-api" } -feldera-ir = { version = "0.313.0", path = "crates/ir" } -feldera-adapterlib = { version = "0.313.0", path = "crates/adapterlib" } -feldera-samply = { version = "0.313.0", path = "crates/samply" } +feldera-observability = { version = "0.314.0", path = "crates/feldera-observability" } +feldera-macros = { version = "0.314.0", path = "crates/feldera-macros" } +feldera-sqllib = { version = "0.314.0", path = "crates/sqllib" } +feldera-storage = { version = "0.314.0", path = "crates/storage" } +feldera-types = { version = "0.314.0", path = "crates/feldera-types" } +feldera-rest-api = { version = "0.314.0", path = "crates/rest-api" } +feldera-ir = { version = "0.314.0", path = "crates/ir" } +feldera-adapterlib = { version = "0.314.0", path = "crates/adapterlib" } +feldera-samply = { version = "0.314.0", path = "crates/samply" } flate2 = "1.1.0" form_urlencoded = "1.2.0" fs_extra = "1.3.0" diff --git a/openapi.json b/openapi.json index 18cff1992de..79e7c09fb93 100644 --- a/openapi.json +++ b/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "MIT OR Apache-2.0" }, - "version": "0.313.0" + "version": "0.314.0" }, "paths": { "/config/authentication": { diff --git a/python/dbt-feldera/pyproject.toml b/python/dbt-feldera/pyproject.toml index bb3b4be4292..1839054d7a9 100644 --- a/python/dbt-feldera/pyproject.toml +++ b/python/dbt-feldera/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "dbt-feldera" readme = "README.md" description = "The dbt adapter for Feldera — DBSP-native incremental view maintenance" -version = "0.313.0" +version = "0.314.0" license = "MIT" requires-python = ">=3.10" authors = [ diff --git a/python/felderize/pyproject.toml b/python/felderize/pyproject.toml index 52f0a3bfc02..18dbf2aa1c2 100644 --- a/python/felderize/pyproject.toml +++ b/python/felderize/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "felderize" readme = "README.md" description = "SQL dialect to Feldera SQL translator agent" -version = "0.313.0" +version = "0.314.0" license = "MIT" requires-python = ">=3.10" authors = [ diff --git a/python/pyproject.toml b/python/pyproject.toml index b374ccd9424..585396759dd 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "feldera" readme = "README.md" description = "The feldera python client" -version = "0.313.0" +version = "0.314.0" license = "MIT" requires-python = ">=3.10" authors = [ diff --git a/python/uv.lock b/python/uv.lock index 5371a996584..653b1d64532 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ ] [options] -exclude-newer = "2026-06-11T02:24:36.332984623Z" +exclude-newer = "2026-06-16T05:50:17.266848806Z" exclude-newer-span = "P1W" [[package]] @@ -326,7 +326,7 @@ wheels = [ [[package]] name = "feldera" -version = "0.313.0" +version = "0.314.0" source = { editable = "." } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, diff --git a/sql-to-dbsp-compiler/SQL-compiler/pom.xml b/sql-to-dbsp-compiler/SQL-compiler/pom.xml index 8294fd634e2..b771ba326bf 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/pom.xml +++ b/sql-to-dbsp-compiler/SQL-compiler/pom.xml @@ -19,7 +19,7 @@ 1.43.0 2.21.1 3.1.12 - 0.313.0 + 0.314.0 1.28.0 From d59330f7e8879eb1ce898b4a664af4bad414c125 Mon Sep 17 00:00:00 2001 From: Simon Kassing Date: Tue, 23 Jun 2026 11:58:02 +0200 Subject: [PATCH 5/7] pipeline-manager: fix row locking When a table row is retrieved for update purposes, the row itself is now locked by adding `FOR UPDATE` to the query. Although the current global lock mechanism on the database connection of the API server prevents concurrent access, the runner can separately access/change the rows (although, only certain fields when they are in its domain). One such concurrent one is setting of the desired resources status, and the transition of current resources status based on it. A lock timeout of 10 seconds is added along with two custom error types `LockTookTooLong` and `DeadlockDetected`. Both correspond to HTTP error code 503, indicating to the client it should retry. One example of concurrent access: 1. Assume a pipeline is fully compiled 2. User: calls `pipeline.start(wait=False)` 3. API server: `/start` is called -> sets desired status to `Provisioned` -> returns 4. User: call returns as `wait=False` 5. Runner: tasked with transitioning the current status towards `Provisioned` 6. Runner: starts transaction 7. Runner: retrieves the pipeline to check that the current status is `Stopped` and desired status is not `Stopped`, as otherwise it will not still transition toward `Provisioned`. This is not the case. 8. User calls `pipeline.stop(wait=True)` 9. API server: `/stop` is called -> sets desired status to `Stopped` -> returns 10. API server: `GET pipeline` is called -> returns 11. User call returns: sees current and desired status is `Stopped` 12. Runner: transitions the status to Provisioning (as check at step (7) passed) 13. Runner: commits transaction 14. Runner: tasked with transitioning the current status towards `Stopped`, and performs that operation. Current status: `Stopping`. 15. User: calls `pipeline.start()` 16. API server: `/start` is called -> desired status is right now `Stopped`, and current status is `Stopping`, so setting desired status to `Provisioned` is not allowed -> returns error `IllegalPipelineAction` 17. User: `FelderaAPIError` exception is raised This fixes it by having the runner take an FOR UPDATE lock at step (7), and as such the API server at step (9) will be forced to wait until the runner is finished before being able to acquire the lock itself. After which, at step (11) the user will get back that the current status is not yet `Stopped` and will continue to poll until it is. As such, the user starting the pipeline again (step (15)) only happens once the pipeline is truly stopped, and will succeed. Signed-off-by: Simon Kassing --- crates/pipeline-manager/src/db/error.rs | 21 +- .../src/db/operations/pipeline.rs | 209 ++++++++-- .../src/db/operations/pipeline_monitor.rs | 14 +- .../src/db/storage_postgres.rs | 363 +++++++++++------- crates/pipeline-manager/src/db/test.rs | 169 +++++++- .../tests/platform/test_pipeline_lifecycle.py | 93 ++--- 6 files changed, 640 insertions(+), 229 deletions(-) diff --git a/crates/pipeline-manager/src/db/error.rs b/crates/pipeline-manager/src/db/error.rs index 59590a13cc3..d38e7222567 100644 --- a/crates/pipeline-manager/src/db/error.rs +++ b/crates/pipeline-manager/src/db/error.rs @@ -16,7 +16,7 @@ use feldera_types::error::ErrorResponse; use refinery::Error as RefineryError; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{backtrace::Backtrace, borrow::Cow, error::Error as StdError, fmt, fmt::Display}; -use tokio_postgres::error::Error as PgError; +use tokio_postgres::error::{Error as PgError, SqlState}; #[derive(Debug, Serialize)] #[serde(untagged)] @@ -256,6 +256,8 @@ pub enum DBError { event_id: PipelineMonitorEventId, }, NoPipelineMonitorEventsAvailable, + LockTookTooLong, + DeadlockDetected, } impl DBError { @@ -394,6 +396,13 @@ where impl From for DBError { fn from(error: PgError) -> Self { + if let Some(error) = error.as_db_error() { + if matches!(error.code(), &SqlState::LOCK_NOT_AVAILABLE) { + return DBError::LockTookTooLong; + } else if matches!(error.code(), &SqlState::T_R_DEADLOCK_DETECTED) { + return DBError::DeadlockDetected; + } + } Self::PostgresError { error: Box::new(error), backtrace: Backtrace::capture(), @@ -812,6 +821,12 @@ impl Display for DBError { DBError::NoPipelineMonitorEventsAvailable => { write!(f, "There are not yet any pipeline monitor events recorded") } + DBError::LockTookTooLong => { + write!(f, "The lock required for this operation took too long to acquire. Try this operation again later.") + } + DBError::DeadlockDetected => { + write!(f, "A deadlock was detected while performing the operation. Try this operation again later. Please also file a bug report, as this error should not happen.") + } } } } @@ -931,6 +946,8 @@ impl DetailedError for DBError { } Self::UnknownPipelineMonitorEvent { .. } => Cow::from("UnknownPipelineMonitorEvent"), Self::NoPipelineMonitorEventsAvailable => Cow::from("NoPipelineMonitorEventsAvailable"), + Self::LockTookTooLong => Cow::from("LockTookTooLong"), + Self::DeadlockDetected => Cow::from("DeadlockDetected"), } } } @@ -1014,6 +1031,8 @@ impl ResponseError for DBError { Self::UnnecessaryResourcesStatusTransition { .. } => StatusCode::BAD_REQUEST, Self::UnknownPipelineMonitorEvent { .. } => StatusCode::NOT_FOUND, Self::NoPipelineMonitorEventsAvailable => StatusCode::NOT_FOUND, + Self::LockTookTooLong => StatusCode::SERVICE_UNAVAILABLE, + Self::DeadlockDetected => StatusCode::SERVICE_UNAVAILABLE, } } diff --git a/crates/pipeline-manager/src/db/operations/pipeline.rs b/crates/pipeline-manager/src/db/operations/pipeline.rs index 57ba525b736..9e18b883160 100644 --- a/crates/pipeline-manager/src/db/operations/pipeline.rs +++ b/crates/pipeline-manager/src/db/operations/pipeline.rs @@ -38,6 +38,12 @@ use tokio_postgres::Row; use tracing::warn; use uuid::Uuid; +/// This expression converts the first 8 bytes of the pipeline UUID to a BIGINT, +/// and takes its absolute value. It is used to determine which compiler server +/// worker the pipeline is assigned to. +const PIPELINE_ID_SQL_HASH_FUNCTION_CALL: &str = + "abs(('x' || substr(replace(p.id::text, '-', ''), 1, 16))::bit(64)::bigint)"; + pub(crate) async fn list_pipelines( txn: &Transaction<'_>, tenant_id: TenantId, @@ -78,17 +84,25 @@ pub(crate) async fn list_pipelines_for_monitoring( Ok(result) } +/// Retrieve pipeline complete descriptor by its name. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. pub(crate) async fn get_pipeline( txn: &Transaction<'_>, tenant_id: TenantId, name: &str, + row_lock: bool, ) -> Result { let stmt = txn .prepare_cached(&format!( "SELECT {PIPELINE_COLUMNS_ALL} FROM pipeline AS p WHERE p.tenant_id = $1 AND p.name = $2 - " + {} + ", + if row_lock { "FOR UPDATE" } else { "" } )) .await?; let row = txn.query_opt(&stmt, &[&tenant_id.0, &name]).await?.ok_or( @@ -99,17 +113,25 @@ pub(crate) async fn get_pipeline( parse_pipeline_row_all(&row) } +/// Retrieve pipeline monitoring descriptor (only contains status-related fields) by its name. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. pub(crate) async fn get_pipeline_for_monitoring( txn: &Transaction<'_>, tenant_id: TenantId, name: &str, + row_lock: bool, ) -> Result { let stmt = txn .prepare_cached(&format!( "SELECT {PIPELINE_COLUMNS_MONITORING} FROM pipeline AS p WHERE p.tenant_id = $1 AND p.name = $2 - " + {} + ", + if row_lock { "FOR UPDATE" } else { "" } )) .await?; let row = txn.query_opt(&stmt, &[&tenant_id.0, &name]).await?.ok_or( @@ -120,18 +142,27 @@ pub(crate) async fn get_pipeline_for_monitoring( parse_pipeline_row_monitoring(&row) } +/// Retrieve pipeline by its identifier; internal helper that allows specifying which `fields` +/// to retrieve. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. async fn internal_get_pipeline_by_id( txn: &Transaction<'_>, tenant_id: TenantId, pipeline_id: PipelineId, fields: &'static str, + row_lock: bool, ) -> Result { let stmt = txn .prepare_cached(&format!( "SELECT {fields} FROM pipeline AS p WHERE p.tenant_id = $1 AND p.id = $2 - " + {} + ", + if row_lock { "FOR UPDATE" } else { "" } )) .await?; txn.query_opt(&stmt, &[&tenant_id.0, &pipeline_id.0]) @@ -139,33 +170,65 @@ async fn internal_get_pipeline_by_id( .ok_or(DBError::UnknownPipeline { pipeline_id }) } +/// Retrieve pipeline complete descriptor by its identifier. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. pub async fn get_pipeline_by_id( txn: &Transaction<'_>, tenant_id: TenantId, pipeline_id: PipelineId, + row_lock: bool, ) -> Result { let row = - internal_get_pipeline_by_id(txn, tenant_id, pipeline_id, PIPELINE_COLUMNS_ALL).await?; + internal_get_pipeline_by_id(txn, tenant_id, pipeline_id, PIPELINE_COLUMNS_ALL, row_lock) + .await?; parse_pipeline_row_all(&row) } +/// Retrieve pipeline monitoring descriptor (only contains status-related fields) by its identifier. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. pub async fn get_pipeline_by_id_for_monitoring( txn: &Transaction<'_>, tenant_id: TenantId, pipeline_id: PipelineId, + row_lock: bool, ) -> Result { - let row = internal_get_pipeline_by_id(txn, tenant_id, pipeline_id, PIPELINE_COLUMNS_MONITORING) - .await?; + let row = internal_get_pipeline_by_id( + txn, + tenant_id, + pipeline_id, + PIPELINE_COLUMNS_MONITORING, + row_lock, + ) + .await?; parse_pipeline_row_monitoring(&row) } +/// Retrieve pipeline descriptor by its identifier, getting only the fields needed to construct +/// an event. +/// +/// Set `row_lock` to `true` when using the retrieved row in the decision logic in the +/// rest of the transaction (for example, whether/how to update its fields). It will +/// acquire a FOR UPDATE lock on the retrieved row in that case. pub async fn get_pipeline_by_id_for_event_info( txn: &Transaction<'_>, tenant_id: TenantId, pipeline_id: PipelineId, + row_lock: bool, ) -> Result { - let row = internal_get_pipeline_by_id(txn, tenant_id, pipeline_id, PIPELINE_COLUMNS_EVENT_INFO) - .await?; + let row = internal_get_pipeline_by_id( + txn, + tenant_id, + pipeline_id, + PIPELINE_COLUMNS_EVENT_INFO, + row_lock, + ) + .await?; parse_pipeline_row_event_info(&row) } @@ -367,7 +430,7 @@ pub(crate) async fn update_pipeline( // Fetch current pipeline to decide how to update. // This will also return an error if the pipeline does not exist. - let current = get_pipeline(txn, tenant_id, original_name).await?; + let current = get_pipeline(txn, tenant_id, original_name, true).await?; // Build the current client metadata and merge the patch into it to get the // new value. `current.client_metadata()` uses an exhaustive `ClientMetadata` @@ -655,7 +718,7 @@ pub(crate) async fn delete_pipeline( tenant_id: TenantId, name: &str, ) -> Result { - let current = get_pipeline(txn, tenant_id, name).await?; + let current = get_pipeline(txn, tenant_id, name, true).await?; // Pipeline deletion is only possible if it is fully stopped if current.deployment_resources_status != ResourcesStatus::Stopped @@ -696,7 +759,7 @@ pub(crate) async fn set_program_status( new_program_binary_integrity_checksum: &Option, new_program_info_integrity_checksum: &Option, ) -> Result<(), DBError> { - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; // Only if the program whose status is being transitioned is the same one can it be updated if current.program_version != program_version_guard { @@ -959,7 +1022,7 @@ pub(crate) async fn dismiss_deployment_error( tenant_id: TenantId, pipeline_name: &str, ) -> Result<(), DBError> { - let current = get_pipeline(txn, tenant_id, pipeline_name).await?; + let current = get_pipeline(txn, tenant_id, pipeline_name, true).await?; // If an error has to be cleared, then it is only possible if it is fully stopped if (current.deployment_resources_status != ResourcesStatus::Stopped @@ -997,7 +1060,7 @@ pub(crate) async fn set_deployment_resources_desired_status( bootstrap_config: Option, dismiss_error: bool, ) -> Result { - let current = get_pipeline(txn, tenant_id, pipeline_name).await?; + let current = get_pipeline(txn, tenant_id, pipeline_name, true).await?; // Deployment error will be automatically dismissed if this is wanted let final_deployment_error = if dismiss_error { @@ -1139,7 +1202,7 @@ async fn check_version_guard_and_transition_deployment_resources_status( new_deployment_resources_status: ResourcesStatus, remain: bool, ) -> Result { - let current = get_pipeline_by_id_for_monitoring(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id_for_monitoring(txn, tenant_id, pipeline_id, true).await?; // Use the version guard to check that the deployment is the intended one if current.version != version_guard { @@ -1209,7 +1272,7 @@ pub(crate) async fn set_deployment_resources_status_stopped( false, ) .await?; - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; set_deployment_resources_status( txn, @@ -1285,7 +1348,7 @@ pub(crate) async fn set_deployment_resources_status_provisioning( false, ) .await?; - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; set_deployment_resources_status( txn, @@ -1358,7 +1421,7 @@ pub(crate) async fn set_deployment_resources_status_provisioned( false, ) .await?; - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; set_deployment_resources_status( txn, @@ -1432,7 +1495,7 @@ pub(crate) async fn set_deployment_resources_status_stopping( false, ) .await?; - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; set_deployment_resources_status( txn, @@ -1655,7 +1718,7 @@ pub(crate) async fn set_storage_status( pipeline_id: PipelineId, new_storage_status: StorageStatus, ) -> Result<(), DBError> { - let current = get_pipeline_by_id(txn, tenant_id, pipeline_id).await?; + let current = get_pipeline_by_id(txn, tenant_id, pipeline_id, true).await?; // Check that the transition is permitted validate_storage_status_transition( @@ -1771,6 +1834,104 @@ pub(crate) async fn list_pipelines_across_all_tenants_for_monitoring( Ok(result) } +/// Retrieves a list of pipelines across all tenants that belong to the worker ID which are +/// `Stopped` and are either: +/// - of the same platform version and are `CompilingSql` +/// - of a different platform version and are either `Pending` or `CompilingSql` +/// +/// The SQL compiler worker will use the result of this to reset the compilation of those +/// pipelines in the database, before picking up its next job. +pub(crate) async fn list_pipelines_across_all_tenants_needing_sql_compilation_clear( + txn: &Transaction<'_>, + platform_version: &str, + worker_id: usize, + total_workers: usize, +) -> Result, DBError> { + let stmt = txn + .prepare_cached(&format!( + "SELECT p.tenant_id, {PIPELINE_COLUMNS_MONITORING} + FROM pipeline AS p + WHERE p.deployment_resources_status = 'stopped' + AND ( + (p.platform_version = $1 AND p.program_status = 'compiling_sql') + OR + (p.platform_version != $1 AND (p.program_status = 'pending' OR p.program_status = 'compiling_sql')) + ) + AND ({PIPELINE_ID_SQL_HASH_FUNCTION_CALL} % $2) = $3 + ORDER BY p.id ASC + FOR UPDATE + " + )) + .await?; + let rows: Vec = txn + .query( + &stmt, + &[ + &platform_version.to_string(), + &(total_workers as i64), + &(worker_id as i64), + ], + ) + .await?; + let mut result = Vec::with_capacity(rows.len()); + for row in rows { + result.push(( + TenantId(row.get("tenant_id")), + parse_pipeline_row_monitoring(&row)?, + )); + } + Ok(result) +} + +/// Retrieves a list of pipelines across all tenants that belong to the worker ID which are +/// `Stopped` and are either: +/// - of the same platform version and are `CompilingRust` +/// - of a different platform version and are either `SqlCompiled` or `CompilingRust` +/// +/// The Rust compiler worker will use the result of this to reset the compilation of those +/// pipelines in the database, before picking up its next job. +pub(crate) async fn list_pipelines_across_all_tenants_needing_rust_compilation_clear( + txn: &Transaction<'_>, + platform_version: &str, + worker_id: usize, + total_workers: usize, +) -> Result, DBError> { + let stmt = txn + .prepare_cached(&format!( + "SELECT p.tenant_id, {PIPELINE_COLUMNS_MONITORING} + FROM pipeline AS p + WHERE p.deployment_resources_status = 'stopped' + AND ( + (p.platform_version = $1 AND p.program_status = 'compiling_rust') + OR + (p.platform_version != $1 AND (p.program_status = 'sql_compiled' OR p.program_status = 'compiling_rust')) + ) + AND ({PIPELINE_ID_SQL_HASH_FUNCTION_CALL} % $2) = $3 + ORDER BY p.id ASC + FOR UPDATE + " + )) + .await?; + let rows: Vec = txn + .query( + &stmt, + &[ + &platform_version.to_string(), + &(total_workers as i64), + &(worker_id as i64), + ], + ) + .await?; + let mut result = Vec::with_capacity(rows.len()); + for row in rows { + result.push(( + TenantId(row.get("tenant_id")), + parse_pipeline_row_monitoring(&row)?, + )); + } + Ok(result) +} + /// Retrieves the pipeline which is stopped, whose program status has been Pending /// for the longest, and is of the current platform version. Returns `None` if none is found. pub(crate) async fn get_next_sql_compilation( @@ -1779,9 +1940,6 @@ pub(crate) async fn get_next_sql_compilation( worker_id: usize, total_workers: usize, ) -> Result, DBError> { - // The expression `abs(('x' || substr(replace(p.id::text, '-', ''), 1, 16))::bit(64)::bigint) % $2) = $3` - // converts the first 8 bytes of the UUID to a bigint, takes its absolute value, - // and computes the modulo with the total number of workers. let stmt = txn .prepare_cached(&format!( "SELECT p.tenant_id, {PIPELINE_COLUMNS_ALL} @@ -1789,7 +1947,7 @@ pub(crate) async fn get_next_sql_compilation( WHERE p.deployment_resources_status = 'stopped' AND p.program_status = 'pending' AND p.platform_version = $1 - AND (abs(('x' || substr(replace(p.id::text, '-', ''), 1, 16))::bit(64)::bigint) % $2) = $3 + AND ({PIPELINE_ID_SQL_HASH_FUNCTION_CALL} % $2) = $3 ORDER BY p.program_status_since ASC, p.id ASC LIMIT 1 " @@ -1822,9 +1980,6 @@ pub(crate) async fn get_next_rust_compilation( worker_id: usize, total_workers: usize, ) -> Result, DBError> { - // The expression `abs(('x' || substr(replace(p.id::text, '-', ''), 1, 16))::bit(64)::bigint) % $2) = $3` - // converts the first 8 bytes of the UUID to a bigint, takes its absolute value, - // and computes the modulo with the total number of workers. let stmt = txn .prepare_cached(&format!( "SELECT p.tenant_id, {PIPELINE_COLUMNS_ALL} @@ -1832,7 +1987,7 @@ pub(crate) async fn get_next_rust_compilation( WHERE p.deployment_resources_status = 'stopped' AND p.program_status = 'sql_compiled' AND p.platform_version = $1 - AND (abs(('x' || substr(replace(p.id::text, '-', ''), 1, 16))::bit(64)::bigint) % $2) = $3 + AND ({PIPELINE_ID_SQL_HASH_FUNCTION_CALL} % $2) = $3 ORDER BY p.program_status_since ASC, p.id ASC LIMIT 1 " diff --git a/crates/pipeline-manager/src/db/operations/pipeline_monitor.rs b/crates/pipeline-manager/src/db/operations/pipeline_monitor.rs index e5454a2e690..deab05c97cf 100644 --- a/crates/pipeline-manager/src/db/operations/pipeline_monitor.rs +++ b/crates/pipeline-manager/src/db/operations/pipeline_monitor.rs @@ -25,7 +25,7 @@ pub(crate) async fn get_pipeline_monitor_event_short( pipeline_name: String, event_id: PipelineMonitorEventId, ) -> Result { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -51,7 +51,7 @@ pub(crate) async fn get_pipeline_monitor_event_extended( pipeline_name: String, event_id: PipelineMonitorEventId, ) -> Result { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -76,7 +76,7 @@ pub(crate) async fn get_latest_pipeline_monitor_event_short( tenant_id: TenantId, pipeline_name: String, ) -> Result { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -103,7 +103,7 @@ pub(crate) async fn get_latest_pipeline_monitor_event_extended( tenant_id: TenantId, pipeline_name: String, ) -> Result { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -130,7 +130,7 @@ pub(crate) async fn list_pipeline_monitor_events_short( tenant_id: TenantId, pipeline_name: String, ) -> Result, DBError> { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -157,7 +157,7 @@ pub(crate) async fn list_pipeline_monitor_events_extended( tenant_id: TenantId, pipeline_name: String, ) -> Result, DBError> { - let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name) + let pipeline_id = get_pipeline_for_monitoring(txn, tenant_id, &pipeline_name, false) .await? .id; @@ -185,7 +185,7 @@ pub(crate) async fn new_pipeline_monitor_event( pipeline_id: PipelineId, new_event_id: Uuid, ) -> Result<(), DBError> { - let pipeline = get_pipeline_by_id_for_event_info(txn, tenant_id, pipeline_id).await?; + let pipeline = get_pipeline_by_id_for_event_info(txn, tenant_id, pipeline_id, true).await?; let stmt = txn .prepare_cached( diff --git a/crates/pipeline-manager/src/db/storage_postgres.rs b/crates/pipeline-manager/src/db/storage_postgres.rs index 4ac57df33b4..40134443f72 100644 --- a/crates/pipeline-manager/src/db/storage_postgres.rs +++ b/crates/pipeline-manager/src/db/storage_postgres.rs @@ -30,28 +30,32 @@ use deadpool_postgres::{Manager, Pool, RecyclingMethod}; use feldera_types::config::{PipelineConfig, RuntimeConfig}; use feldera_types::error::ErrorResponse; use feldera_types::runtime_status::{BootstrapConfig, RuntimeDesiredStatus, RuntimeStatus}; -use tokio_postgres::Row; +use tokio_postgres::{IsolationLevel, Row}; use tracing::{debug, info}; use uuid::Uuid; -// Convert PipelineId UUID to u64 to match PostgreSQL's behavior. -// This uses the first 8 bytes of the UUID converted to a big-endian u64. -// This ensures consistent worker assignment between Rust and SQL implementations. -fn pipline_uuid_to_u64(pipeline_id: PipelineId) -> u64 { +/// Converts PipelineId UUID to u64 to mostly match PostgreSQL's behavior. +/// This uses the first 8 bytes of the UUID converted to a big-endian i64, +/// of which the absolute value is taken. Unlike the SQL implementation, +/// this implementation does not error when it is a `i64::MIN`. +#[cfg(test)] // Only used in the database behavioral model test +fn pipeline_uuid_to_u64(pipeline_id: PipelineId) -> u64 { let bytes = pipeline_id.0.as_bytes(); - u64::from_be_bytes([ + i64::from_be_bytes([ bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], ]) + .unsigned_abs() } /// Determine if a pipeline is assigned to a specific worker based on its ID. /// Uses modulo operation to distribute pipelines across workers. +#[cfg(test)] // Only used in the database behavioral model test pub(crate) fn is_pipeline_assigned_to_worker( pipeline_id: PipelineId, worker_index: u64, total_workers: u64, ) -> bool { - let hash = pipline_uuid_to_u64(pipeline_id); + let hash = pipeline_uuid_to_u64(pipeline_id); (hash % total_workers) == worker_index } @@ -189,7 +193,7 @@ impl Storage for StoragePostgres { ) -> Result { let mut client = self.pool.get().await?; let txn = client.transaction().await?; - let pipeline = operations::pipeline::get_pipeline(&txn, tenant_id, name).await?; + let pipeline = operations::pipeline::get_pipeline(&txn, tenant_id, name, false).await?; txn.commit().await?; Ok(pipeline) } @@ -202,7 +206,7 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipeline = - operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, name).await?; + operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, name, false).await?; txn.commit().await?; Ok(pipeline) } @@ -215,7 +219,7 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipeline = - operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline_id).await?; + operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline_id, false).await?; txn.commit().await?; Ok(pipeline) } @@ -227,9 +231,13 @@ impl Storage for StoragePostgres { ) -> Result { let mut client = self.pool.get().await?; let txn = client.transaction().await?; - let pipeline = - operations::pipeline::get_pipeline_by_id_for_monitoring(&txn, tenant_id, pipeline_id) - .await?; + let pipeline = operations::pipeline::get_pipeline_by_id_for_monitoring( + &txn, + tenant_id, + pipeline_id, + false, + ) + .await?; txn.commit().await?; Ok(pipeline) } @@ -242,10 +250,19 @@ impl Storage for StoragePostgres { provision_called: bool, ) -> Result { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; - let pipeline_monitoring = - operations::pipeline::get_pipeline_by_id_for_monitoring(&txn, tenant_id, pipeline_id) - .await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; + let pipeline_monitoring = operations::pipeline::get_pipeline_by_id_for_monitoring( + &txn, + tenant_id, + pipeline_id, + false, + ) + .await?; let is_ready_compiled = pipeline_monitoring.program_status == ProgramStatus::Success && is_supported_runtime(platform_version, &pipeline_monitoring.platform_version); let pipeline_result = if matches!( @@ -268,7 +285,8 @@ impl Storage for StoragePostgres { ), ) { ExtendedPipelineDescrRunner::Complete( - operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline_id).await?, + operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline_id, false) + .await?, ) } else { ExtendedPipelineDescrRunner::Monitoring(pipeline_monitoring) @@ -299,7 +317,7 @@ impl Storage for StoragePostgres { // Fetch newly created pipeline let extended_pipeline = - operations::pipeline::get_pipeline(&txn, tenant_id, &pipeline.name).await?; + operations::pipeline::get_pipeline(&txn, tenant_id, &pipeline.name, false).await?; txn.commit().await?; Ok(extended_pipeline) @@ -318,7 +336,8 @@ impl Storage for StoragePostgres { let txn = client.transaction().await?; // Check if pipeline exists - let current = operations::pipeline::get_pipeline(&txn, tenant_id, original_name).await; + let current = + operations::pipeline::get_pipeline(&txn, tenant_id, original_name, true).await; let is_new: bool = match current { Ok(_) => { // Pipeline already exists, as such update it. For a full @@ -370,7 +389,7 @@ impl Storage for StoragePostgres { // Fetch new or updated pipeline let extended_pipeline = - operations::pipeline::get_pipeline(&txn, tenant_id, &pipeline.name).await?; + operations::pipeline::get_pipeline(&txn, tenant_id, &pipeline.name, false).await?; txn.commit().await?; Ok((is_new, extended_pipeline)) @@ -387,7 +406,7 @@ impl Storage for StoragePostgres { // Check if pipeline exists let current = - operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name) + operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name, true) .await?; if current.deployment_resources_status != ResourcesStatus::Stopped { @@ -398,12 +417,15 @@ impl Storage for StoragePostgres { .prepare_cached( "UPDATE pipeline SET platform_version = $1 - WHERE id = $2", + WHERE tenant_id = $2 AND id = $3", ) .await?; let rows_affected = txn - .execute(&stmt_update, &[&platform_version, ¤t.id.0]) + .execute( + &stmt_update, + &[&platform_version, &tenant_id.0, ¤t.id.0], + ) .await?; assert_eq!(rows_affected, 1); @@ -462,7 +484,7 @@ impl Storage for StoragePostgres { // Fetch updated pipeline let final_name = name.clone().unwrap_or(original_name.to_string()); let extended_pipeline = - operations::pipeline::get_pipeline(&txn, tenant_id, &final_name).await?; + operations::pipeline::get_pipeline(&txn, tenant_id, &final_name, false).await?; txn.commit().await?; Ok(extended_pipeline) @@ -771,7 +793,7 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipeline = - operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name) + operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name, true) .await?; let was_set = if pipeline.deployment_resources_status != ResourcesStatus::Provisioned { operations::pipeline::set_deployment_resources_desired_status( @@ -804,9 +826,13 @@ impl Storage for StoragePostgres { let txn = client.transaction().await?; // If the pipeline currently is already Stopped and is desired to be Stopped, // then there is no need to transition to Provisioning - let pipeline = - operations::pipeline::get_pipeline_by_id_for_monitoring(&txn, tenant_id, pipeline_id) - .await?; + let pipeline = operations::pipeline::get_pipeline_by_id_for_monitoring( + &txn, + tenant_id, + pipeline_id, + true, + ) + .await?; if pipeline.deployment_resources_status == ResourcesStatus::Stopped && pipeline.deployment_resources_desired_status == ResourcesDesiredStatus::Stopped { @@ -925,9 +951,13 @@ impl Storage for StoragePostgres { ) -> Result<(), DBError> { let mut client = self.pool.get().await?; let txn = client.transaction().await?; - let pipeline = - operations::pipeline::get_pipeline_by_id_for_monitoring(&txn, tenant_id, pipeline_id) - .await?; + let pipeline = operations::pipeline::get_pipeline_by_id_for_monitoring( + &txn, + tenant_id, + pipeline_id, + true, + ) + .await?; // If the pipeline currently is already Stopped and is desired to be Stopped, // then there is no need to transition to Stopping if pipeline.deployment_resources_status == ResourcesStatus::Stopped @@ -1013,9 +1043,13 @@ impl Storage for StoragePostgres { ) -> Result<(), DBError> { let mut client = self.pool.get().await?; let txn = client.transaction().await?; - let pipeline = - operations::pipeline::get_pipeline_by_id_for_monitoring(&txn, tenant_id, pipeline_id) - .await?; + let pipeline = operations::pipeline::get_pipeline_by_id_for_monitoring( + &txn, + tenant_id, + pipeline_id, + true, + ) + .await?; operations::pipeline::set_deployment_resources_desired_status( &txn, tenant_id, @@ -1046,7 +1080,7 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipeline = - operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name) + operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name, true) .await?; if pipeline.storage_status != StorageStatus::Cleared { // If it is already cleared, it does not have to transition to clearing @@ -1123,55 +1157,49 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipelines = - operations::pipeline::list_pipelines_across_all_tenants_for_monitoring(&txn).await?; + operations::pipeline::list_pipelines_across_all_tenants_needing_sql_compilation_clear( + &txn, + platform_version, + worker_id, + total_workers, + ) + .await?; for (tenant_id, pipeline) in pipelines { - // skip the pipelines that are not assigned to this worker - if !is_pipeline_assigned_to_worker(pipeline.id, worker_id as u64, total_workers as u64) - { - continue; - } - - if pipeline.deployment_resources_status == ResourcesStatus::Stopped { - if pipeline.platform_version == platform_version { - if pipeline.program_status == ProgramStatus::CompilingSql { - operations::pipeline::set_program_status( - &txn, - tenant_id, - pipeline.id, - pipeline.program_version, - &ProgramStatus::Pending, - &None, - &None, - &None, - &None, - &None, - &None, - &None, - ) - .await?; - } - } else if pipeline.program_status == ProgramStatus::Pending - || pipeline.program_status == ProgramStatus::CompilingSql - { - operations::pipeline::update_pipeline( - &txn, - true, // Done by compiler - tenant_id, - &pipeline.name, - &operations::pipeline::PipelineFieldUpdates { - name: &None, - client_metadata: &PatchClientMetadata::default(), - runtime_config: &None, - program_code: &None, - udf_rust: &None, - udf_toml: &None, - program_config: &None, - }, - platform_version, - true, - ) - .await?; - } + if pipeline.platform_version == platform_version { + operations::pipeline::set_program_status( + &txn, + tenant_id, + pipeline.id, + pipeline.program_version, + &ProgramStatus::Pending, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + ) + .await?; + } else { + operations::pipeline::update_pipeline( + &txn, + true, // Done by compiler + tenant_id, + &pipeline.name, + &operations::pipeline::PipelineFieldUpdates { + name: &None, + client_metadata: &PatchClientMetadata::default(), + runtime_config: &None, + program_code: &None, + udf_rust: &None, + udf_toml: &None, + program_config: &None, + }, + platform_version, + true, + ) + .await?; } } txn.commit().await?; @@ -1206,63 +1234,55 @@ impl Storage for StoragePostgres { let mut client = self.pool.get().await?; let txn = client.transaction().await?; let pipelines = - operations::pipeline::list_pipelines_across_all_tenants_for_monitoring(&txn).await?; + operations::pipeline::list_pipelines_across_all_tenants_needing_rust_compilation_clear( + &txn, + platform_version, + worker_id, + total_workers, + ) + .await?; for (tenant_id, pipeline) in pipelines { - // skip the pipelines that are not assigned to this worker - if !is_pipeline_assigned_to_worker(pipeline.id, worker_id as u64, total_workers as u64) - { - continue; - } - - if pipeline.deployment_resources_status == ResourcesStatus::Stopped { - if pipeline.platform_version == platform_version { - if pipeline.program_status == ProgramStatus::CompilingRust { - // Because `program_info` can be rather large, it is only fetched when - // the program status needs to be reset to `SqlCompiled` - let pipeline_complete = - operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline.id) - .await?; - operations::pipeline::set_program_status( - &txn, - tenant_id, - pipeline.id, - pipeline.program_version, - &ProgramStatus::SqlCompiled, - &Some(pipeline_complete.program_error.sql_compilation.clone().expect("program_error.sql_compilation must be present if current status is CompilingRust")), - &None, - &None, - &Some(pipeline_complete.program_info.clone().expect( - "program_info must be present if current status is CompilingRust", - )), - &None, - &None, - &None, - ) + if pipeline.platform_version == platform_version { + let pipeline_complete = + operations::pipeline::get_pipeline_by_id(&txn, tenant_id, pipeline.id, true) .await?; - } - } else if pipeline.program_status == ProgramStatus::SqlCompiled - || pipeline.program_status == ProgramStatus::CompilingRust - { - operations::pipeline::update_pipeline( - &txn, - true, // Done by compiler - tenant_id, - &pipeline.name, - &operations::pipeline::PipelineFieldUpdates { - name: &None, - client_metadata: &PatchClientMetadata::default(), - runtime_config: &None, - program_code: &None, - udf_rust: &None, - udf_toml: &None, - program_config: &None, - }, - platform_version, - true, - ) - .await?; - } + operations::pipeline::set_program_status( + &txn, + tenant_id, + pipeline.id, + pipeline.program_version, + &ProgramStatus::SqlCompiled, + &Some(pipeline_complete.program_error.sql_compilation.clone().expect("program_error.sql_compilation must be present if current status is CompilingRust")), + &None, + &None, + &Some(pipeline_complete.program_info.clone().expect( + "program_info must be present if current status is CompilingRust", + )), + &None, + &None, + &None, + ) + .await?; + } else { + operations::pipeline::update_pipeline( + &txn, + true, // Done by compiler + tenant_id, + &pipeline.name, + &operations::pipeline::PipelineFieldUpdates { + name: &None, + client_metadata: &PatchClientMetadata::default(), + runtime_config: &None, + program_code: &None, + udf_rust: &None, + udf_toml: &None, + program_config: &None, + }, + platform_version, + true, + ) + .await?; } } txn.commit().await?; @@ -1315,10 +1335,19 @@ impl Storage for StoragePostgres { how_many: u64, ) -> Result<(ExtendedPipelineDescrMonitoring, Vec), DBError> { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; - let pipeline = - operations::pipeline::get_pipeline_for_monitoring(&txn, tenant_id, pipeline_name) - .await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; + let pipeline = operations::pipeline::get_pipeline_for_monitoring( + &txn, + tenant_id, + pipeline_name, + false, + ) + .await?; let bundle_data = operations::pipeline::get_support_bundle_data(&txn, pipeline.id, how_many).await?; txn.commit().await?; @@ -1413,7 +1442,12 @@ impl Storage for StoragePostgres { pipeline_name: String, ) -> Result, DBError> { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let events = operations::pipeline_monitor::list_pipeline_monitor_events_short( &txn, tenant_id, @@ -1430,7 +1464,12 @@ impl Storage for StoragePostgres { pipeline_name: String, ) -> Result, DBError> { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let events = operations::pipeline_monitor::list_pipeline_monitor_events_extended( &txn, tenant_id, @@ -1448,7 +1487,12 @@ impl Storage for StoragePostgres { event_id: PipelineMonitorEventId, ) -> Result { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let event = operations::pipeline_monitor::get_pipeline_monitor_event_short( &txn, tenant_id, @@ -1467,7 +1511,12 @@ impl Storage for StoragePostgres { event_id: PipelineMonitorEventId, ) -> Result { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let event = operations::pipeline_monitor::get_pipeline_monitor_event_extended( &txn, tenant_id, @@ -1485,7 +1534,12 @@ impl Storage for StoragePostgres { pipeline_name: String, ) -> Result { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let event = operations::pipeline_monitor::get_latest_pipeline_monitor_event_short( &txn, tenant_id, @@ -1502,7 +1556,12 @@ impl Storage for StoragePostgres { pipeline_name: String, ) -> Result { let mut client = self.pool.get().await?; - let txn = client.transaction().await?; + let txn = client + .build_transaction() + .isolation_level(IsolationLevel::RepeatableRead) + .read_only(true) + .start() + .await?; let event = operations::pipeline_monitor::get_latest_pipeline_monitor_event_extended( &txn, tenant_id, @@ -1561,7 +1620,13 @@ impl StoragePostgres { db_config: &DatabaseConfig, #[cfg(feature = "postgresql_embedded")] pg_inst: Option, ) -> Result { - let config = db_config.tokio_postgres_config()?; + let mut config = db_config.tokio_postgres_config()?; + let new_options = if let Some(options) = config.get_options() { + format!("{options} -c lock_timeout=10000") + } else { + "-c lock_timeout=10000".to_string() + }; + config.options(new_options); debug!( "Opening Postgres connection with configuration: {:?}", config diff --git a/crates/pipeline-manager/src/db/test.rs b/crates/pipeline-manager/src/db/test.rs index b69ca8e0e8a..a094f2c74c2 100644 --- a/crates/pipeline-manager/src/db/test.rs +++ b/crates/pipeline-manager/src/db/test.rs @@ -2,6 +2,7 @@ use crate::api::support_data_collector::SupportBundleData; use crate::auth::{generate_api_key, TenantRecord}; use crate::db::error::DBError; use crate::db::error::DBError::InvalidResourcesStatusNotRemain; +use crate::db::operations::pipeline::get_pipeline_by_id_for_monitoring; use crate::db::storage::{ExtendedPipelineDescrRunner, Storage}; use crate::db::storage_postgres::{is_pipeline_assigned_to_worker, StoragePostgres}; use crate::db::types::api_key::{ApiKeyDescr, ApiKeyId, ApiPermission}; @@ -52,9 +53,10 @@ use std::borrow::Cow; use std::collections::{BTreeMap, VecDeque}; use std::fmt::Debug; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, Instant}; use std::vec; -use tokio::sync::Mutex; +use tokio::spawn; +use tokio::sync::{oneshot, Mutex}; use tokio::time::sleep; use tracing::info; use uuid::Uuid; @@ -2967,6 +2969,169 @@ async fn pipeline_client_metadata_update_while_running() { assert_eq!(unchanged.refresh_version, before.refresh_version); } +#[tokio::test] +async fn pipeline_concurrent_access_stall() { + let handle = test_setup().await; + let tenant_id = TenantRecord::default().id; + + // Create pipeline + let pipeline = handle + .db + .new_pipeline( + tenant_id, + Uuid::now_v7(), + "v0", + PipelineDescr { + name: "example1".to_string(), + description: "d1".to_string(), + tags: vec!["t1".to_string()], + runtime_config: json!({}), + program_code: "c1".to_string(), + udf_rust: "r1".to_string(), + udf_toml: "t2".to_string(), + program_config: json!({}), + }, + ) + .await + .unwrap(); + + // Client to create transactions with + let mut client1 = handle.db.pool.get().await.unwrap(); + let mut client2 = handle.db.pool.get().await.unwrap(); + + // Non-conflicting + for (row_lock1, row_lock2) in [(false, false), (true, false), (false, true)] { + let txn1 = client1.transaction().await.unwrap(); + let txn2 = client2.transaction().await.unwrap(); + get_pipeline_by_id_for_monitoring(&txn1, tenant_id, pipeline.id, row_lock1) + .await + .unwrap(); + get_pipeline_by_id_for_monitoring(&txn2, tenant_id, pipeline.id, row_lock2) + .await + .unwrap(); + txn1.commit().await.unwrap(); + txn2.commit().await.unwrap(); + } + + // Conflicting + let txn1 = client1.transaction().await.unwrap(); + let txn2 = client2.transaction().await.unwrap(); + get_pipeline_by_id_for_monitoring(&txn1, tenant_id, pipeline.id, true) + .await + .unwrap(); + // The lock timeout has been set globally via an option. As such, the below is not needed. + // This test does take some time as a consequence (the actual timeout used: 10 seconds). + // However, this is an important check to make sure that when the system is deployed, + // the lock timeout is enforced. + // txn2.execute("SET LOCAL lock_timeout = 10000", &[]).await.unwrap(); + let ts_start = Instant::now(); + let error = get_pipeline_by_id_for_monitoring(&txn2, tenant_id, pipeline.id, true) + .await + .unwrap_err(); + assert!( + matches!(error, DBError::LockTookTooLong), + "got {error:?} instead of {:?}", + DBError::LockTookTooLong + ); + let elapsed = ts_start.elapsed(); + assert!(elapsed >= Duration::from_millis(8000) && elapsed <= Duration::from_millis(30000)); + txn1.commit().await.unwrap(); + txn2.commit().await.unwrap(); +} + +#[tokio::test] +async fn pipeline_concurrent_access_deadlock() { + let handle = test_setup().await; + let tenant_id = TenantRecord::default().id; + + // Create pipeline 1 + let pipeline1 = handle + .db + .new_pipeline( + tenant_id, + Uuid::now_v7(), + "v0", + PipelineDescr { + name: "example1".to_string(), + description: "d1".to_string(), + tags: vec!["t1".to_string()], + runtime_config: json!({}), + program_code: "c1".to_string(), + udf_rust: "r1".to_string(), + udf_toml: "t2".to_string(), + program_config: json!({}), + }, + ) + .await + .unwrap(); + + // Create pipeline 2 + let pipeline2 = handle + .db + .new_pipeline( + tenant_id, + Uuid::now_v7(), + "v0", + PipelineDescr { + name: "example2".to_string(), + description: "d1".to_string(), + tags: vec!["t1".to_string(), "t2".to_string()], + runtime_config: json!({}), + program_code: "c1".to_string(), + udf_rust: "r1".to_string(), + udf_toml: "t2".to_string(), + program_config: json!({}), + }, + ) + .await + .unwrap(); + + // Deadlock: + // - T2 locks pipeline 2 + // - T1 locks pipeline 1 + // - T1 tries to lock pipeline 2 -> waits or deadlock + // - T2 tries to lock pipeline 1 -> waits or deadlock + let mut client1 = handle.db.pool.get().await.unwrap(); + let mut client2 = handle.db.pool.get().await.unwrap(); + let txn2 = client2.transaction().await.unwrap(); + get_pipeline_by_id_for_monitoring(&txn2, tenant_id, pipeline2.id, true) + .await + .unwrap(); + let (tx, rx) = oneshot::channel::<()>(); + let join_handle = spawn(async move { + let txn1 = client1.transaction().await.unwrap(); + get_pipeline_by_id_for_monitoring(&txn1, tenant_id, pipeline1.id, true) + .await + .unwrap(); + tx.send(()).unwrap(); + if let Err(e) = + get_pipeline_by_id_for_monitoring(&txn1, tenant_id, pipeline2.id, true).await + { + return Some(e); + } + txn1.commit().await.unwrap(); + return None; + }); + rx.await.unwrap(); + let t2_error = if let Err(e) = + get_pipeline_by_id_for_monitoring(&txn2, tenant_id, pipeline1.id, true).await + { + Some(e) + } else { + None + }; + let t1_error = join_handle.await.unwrap(); + assert!(!(t1_error.is_some() && t2_error.is_some())); + let error = t1_error.unwrap_or_else(|| { + t2_error.expect("neither transaction errored whereas exactly one was expected to") + }); + assert!( + matches!(error, DBError::DeadlockDetected), + "got {error:?} instead of {:?}", + DBError::DeadlockDetected + ); +} + ////////////////////////////////////////////////////////////////////////////// ///// PROP TESTS ///// diff --git a/python/tests/platform/test_pipeline_lifecycle.py b/python/tests/platform/test_pipeline_lifecycle.py index 57dbbe7cf9b..cd180170ca0 100644 --- a/python/tests/platform/test_pipeline_lifecycle.py +++ b/python/tests/platform/test_pipeline_lifecycle.py @@ -186,7 +186,7 @@ def test_pipeline_deleted_during_program_compilation(pipeline_name): @gen_pipeline_name -def test_pipeline_stop_force_after_start(pipeline_name): +def test_pipeline_stop_with_force_after_start(pipeline_name): """ Start and then force stop after varying short delays. """ @@ -195,15 +195,10 @@ def test_pipeline_stop_force_after_start(pipeline_name): ).create_or_replace() for delay_sec in [0, 0.1, 0.5, 1, 3, 10, 20]: - print(f"Testing with {delay_sec} second delay") - - # Issue non-blocking start pipeline.start(wait=False) - - # Shortly wait for the pipeline to transition to next state(s) time.sleep(delay_sec) - - # Stop force and clear the pipeline + pipeline.stop(force=True) + pipeline.start(wait=False) pipeline.stop(force=True) pipeline.clear_storage() @@ -215,73 +210,85 @@ def test_pipeline_stop_with_force(pipeline_name): """ create_pipeline(pipeline_name, "") - # Already stopped force + # Already stopped stop_pipeline(pipeline_name, force=True) - # Start then immediate stop (force) - # - # We do not wait for the pipeline to start, but we do wait for it - # to transition away from "Stopped". Otherwise, there is a race: - # - # - Request start. - # - # - Request force stop. - # - # - Check for "stopped" status succeeds because starting up is - # taking a little while, so we move along to - # start_pipeline_as_paused(). - # - # - Pipeline transitions to "stopping". - # - # - start_pipeline_as_paused() fails with "Cannot restart the - # pipeline while it is stopping. Wait until it is stopped before - # starting the pipeline again." + # Start (don't wait), immediately stop start_pipeline(pipeline_name, wait=False) - pipeline = Pipeline.get(pipeline_name, TEST_CLIENT) - wait_for_condition( - f"{pipeline_name} no longer stopped", - lambda: pipeline.status() != PipelineStatus.STOPPED, - timeout_s=30.0, - poll_interval_s=0.2, - ) stop_pipeline(pipeline_name, force=True) - # Start paused then stop (simulate by pausing immediately) + # Start (wait for running), stop + start_pipeline(pipeline_name) + stop_pipeline(pipeline_name, force=True) + + # Start (wait for paused), stop start_pipeline_as_paused(pipeline_name) stop_pipeline(pipeline_name, force=True) - # Start, stop (without waiting), then stop again + # Start (wait for running), stop twice in a row start_pipeline(pipeline_name) stop_pipeline(pipeline_name, force=True, wait=False) stop_pipeline(pipeline_name, force=True) + # Stopping must complete before starting again. + # + # It is possible that the stopping happens very quickly, as such only if an error occurs, + # is it checked that it is the correct error code. + start_pipeline(pipeline_name) + stop_pipeline(pipeline_name, force=True, wait=False) + error = None + try: + start_pipeline(pipeline_name) + except FelderaAPIError as e: + error = e + if error is not None: + assert error.error_code == "IllegalPipelineAction" + stop_pipeline(pipeline_name, force=True, wait=False) + + +@enterprise_only +@gen_pipeline_name +def test_pipeline_stop_without_force_after_start(pipeline_name): + """ + Start and then stop after varying short delays. + """ + pipeline = PipelineBuilder( + TEST_CLIENT, pipeline_name, "CREATE TABLE t1(c1 INTEGER);" + ).create_or_replace() + + for delay_sec in [0, 0.1, 0.5, 1, 3, 10, 20]: + pipeline.start(wait=False) + time.sleep(delay_sec) + pipeline.stop(force=False) + pipeline.start(wait=False) + pipeline.stop(force=False) + pipeline.clear_storage() + @enterprise_only @gen_pipeline_name def test_pipeline_stop_without_force(pipeline_name): """ - Same sequences but without force (Enterprise only). + Sequences of starting/stopping without force (Enterprise only). """ create_pipeline(pipeline_name, "") # Already stopped stop_pipeline(pipeline_name, force=False) - # Start then stop (non-force) - # - # See test_pipeline_stop_with_force() for notes. + # Start (don't wait), immediately stop start_pipeline(pipeline_name, wait=False) stop_pipeline(pipeline_name, force=False) - # Start, wait for running, stop + # Start (wait for running), stop start_pipeline(pipeline_name) stop_pipeline(pipeline_name, force=False) - # Start paused (pause right away), stop + # Start (wait for paused), stop start_pipeline_as_paused(pipeline_name) stop_pipeline(pipeline_name, force=False) - # Start, stop twice in a row + # Start (wait for running), stop twice in a row start_pipeline(pipeline_name) stop_pipeline(pipeline_name, force=False, wait=False) stop_pipeline(pipeline_name, force=False) From 7b1b0d4c139f7132dec7d1e276c3eb0065371481 Mon Sep 17 00:00:00 2001 From: Simon Kassing Date: Tue, 23 Jun 2026 18:08:55 +0200 Subject: [PATCH 6/7] python: more lenient `test_refresh_version_due_to_status_changes` The number of refresh changes depends on the number of runtime, storage, and resources status updates, which can be more frequent when under heavy load. Signed-off-by: Simon Kassing --- python/tests/platform/test_pipeline_lifecycle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tests/platform/test_pipeline_lifecycle.py b/python/tests/platform/test_pipeline_lifecycle.py index cd180170ca0..2fb70487eb1 100644 --- a/python/tests/platform/test_pipeline_lifecycle.py +++ b/python/tests/platform/test_pipeline_lifecycle.py @@ -698,7 +698,7 @@ def test_refresh_version_due_to_status_changes(pipeline_name): TEST_CLIENT.http.get(f"/pipelines/{pipeline_name}?selector=status")[ "refresh_version" ] - <= 10 + <= 15 ) pipeline.stop(force=True) pipeline.clear_storage() @@ -706,7 +706,7 @@ def test_refresh_version_due_to_status_changes(pipeline_name): TEST_CLIENT.http.get(f"/pipelines/{pipeline_name}?selector=status")[ "refresh_version" ] - <= 15 + <= 25 ) From ad8a97714d83671cf5fa06462ef204339d39c906 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Mon, 22 Jun 2026 23:44:48 -0700 Subject: [PATCH 7/7] [SQLLIB] Rename truncate -> trunc Signed-off-by: Mihai Budiu --- crates/sqllib/src/decimal.rs | 12 +- .../compiler/sql/simple/Regression1Tests.java | 211 +++++++------- .../compiler/sql/simple/Regression3Tests.java | 260 +++++++++--------- 3 files changed, 247 insertions(+), 236 deletions(-) diff --git a/crates/sqllib/src/decimal.rs b/crates/sqllib/src/decimal.rs index 1ab5082ca10..cab03152d04 100644 --- a/crates/sqllib/src/decimal.rs +++ b/crates/sqllib/src/decimal.rs @@ -237,13 +237,23 @@ pub fn bround_SqlDecimal_i32( some_polymorphic_function2!(bround [const P: usize, const S: usize], SqlDecimal, SqlDecimal, i32, i32, SqlDecimal); #[doc(hidden)] -pub fn truncate_SqlDecimal_i32( +pub fn trunc_SqlDecimal_i32( value: SqlDecimal, digits: i32, ) -> SqlDecimal { value.trunc_digits(digits) } +some_polymorphic_function2!(trunc [const P: usize, const S: usize], SqlDecimal, SqlDecimal, i32, i32, SqlDecimal); + +#[doc(hidden)] +pub fn truncate_SqlDecimal_i32( + value: SqlDecimal, + digits: i32, +) -> SqlDecimal { + trunc_SqlDecimal_i32(value, digits) +} + some_polymorphic_function2!(truncate [const P: usize, const S: usize], SqlDecimal, SqlDecimal, i32, i32, SqlDecimal); #[doc(hidden)] diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java index 83493b18714..f5f93a69171 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression1Tests.java @@ -78,14 +78,14 @@ public void mapMapTest() { public void issue3952() { var ccs = this.getCCS(""" CREATE TABLE tbl(t0 TIMESTAMP, t1 TIMESTAMP NOT NULL); - + CREATE LOCAL VIEW intervalv AS SELECT (t0 - TIMESTAMP '2025-06-21 14:23:44') YEAR AS yr0, (TIMESTAMP '2025-06-21 14:23:44' - t1) YEAR AS yr1, (t0 - TIMESTAMP '2025-06-21 14:23:44') DAYS AS d0, (TIMESTAMP '2025-06-21 14:23:44' - t1) DAYS AS d1 FROM tbl; - + CREATE MATERIALIZED VIEW v AS SELECT CAST(ABS(yr0) AS BIGINT), CAST(ABS(yr1) AS BIGINT), CAST(ABS(d0) AS BIGINT), CAST(ABS(d1) AS BIGINT) @@ -108,7 +108,7 @@ CREATE TABLE a ( bg DOUBLE, bk SMALLINT ); - + CREATE VIEW bl AS SELECT bm.c AS bn, @@ -267,7 +267,7 @@ public void issue4562() { public void issue4650() { var ccs = this.getCCS(""" CREATE TABLE t(tmestmp TIMESTAMP); - + CREATE MATERIALIZED VIEW v AS SELECT TIMESTAMPDIFF(MINUTE, tmestmp, TIMESTAMP '2022-01-22 20:24:44.332') AS min, TIMESTAMPDIFF(SECOND, tmestmp, TIMESTAMP '2022-01-22 20:24:44.332') AS sec, @@ -305,7 +305,7 @@ CREATE TABLE customer ( -- Lateness annotation: customer records cannot arrive more than 7 days out of order. ts TIMESTAMP LATENESS INTERVAL 7 DAYS ); - + -- Credit card transactions. CREATE TABLE transaction ( -- Lateness annotation: transactions cannot arrive more than 1 day out of order. @@ -314,7 +314,7 @@ CREATE TABLE transaction ( customer_id BIGINT NOT NULL, state VARCHAR ); - + -- Data enrichment: -- * Use ASOF JOIN to find the most recent customer record for each transaction. -- * Compute 'out_of_state' flag, which indicates that the transaction was performed outside @@ -327,7 +327,7 @@ CREATE TABLE transaction ( transaction LEFT ASOF JOIN customer MATCH_CONDITION ( transaction.ts >= customer.ts ) ON transaction.customer_id = customer.id; - + -- Rolling aggregation: Compute the number of out-of-state transactions in the last 30 days for each transaction. CREATE VIEW transaction_with_history AS SELECT @@ -382,15 +382,15 @@ public void testExcept() { String sql = """ CREATE TABLE F(ARG0 VARCHAR, ARG1 INT NOT NULL); CREATE TABLE G(ARG1 INT NOT NULL); - + CREATE LOCAL VIEW V0 AS SELECT true FROM G WHERE NOT EXISTS( SELECT true FROM F WHERE F.arg1 = G.arg1); - + CREATE LOCAL VIEW V1 AS SELECT true FROM ((SELECT arg1 FROM G) EXCEPT (SELECT arg1 FROM F)); - + CREATE VIEW DIFF AS (SELECT * FROM V0 EXCEPT SELECT * FROM V1) UNION ALL (SELECT * FROM V1 EXCEPT SELECT * FROM V0)"""; for (int i = 0; i < 2; i++) { @@ -514,13 +514,13 @@ public void issue4264() { -------- x (1 row) - + SELECT TRIM(leading 'abc' FROM 'abacabadaba'); result -------- daba (1 row) - + SELECT TRIM(both 'abc' FROM 'abacabadaba'); result -------- @@ -567,7 +567,7 @@ CREATE TABLE map_tbl( id INT, c1 MAP NOT NULL, c2 MAP); - + CREATE VIEW map_arg_max_distinct_gby AS SELECT id, ARG_MAX(DISTINCT c1, c2) AS c1 FROM map_tbl GROUP BY id;"""); @@ -703,7 +703,8 @@ public void issue4448a() { @Test public void issue4446() { - this.getCC(""" + // Also issue 6524 + this.getCCS(""" create table t (d decimal(8,3)); create view v as select trunc(d) from t;"""); } @@ -765,13 +766,13 @@ public void issue5087() { --- 1\\n2 (1 row) - + SELECT U&'hello\\0041'; r --- helloA (1 row) - + SELECT U&'hello!0041' UESCAPE '!'; r --- @@ -810,7 +811,7 @@ CREATE TABLE t( tmestmp TIMESTAMP, datee DATE, tme TIME); - + CREATE MATERIALIZED VIEW v0 AS SELECT FLOOR(tmestmp TO YEAR) AS yr, FLOOR(datee TO MONTH) AS mth, @@ -820,7 +821,7 @@ CREATE TABLE t( FLOOR(tme TO MILLISECOND) AS millsec1, FLOOR(tme TO MICROSECOND) AS microsec FROM t; - + CREATE MATERIALIZED VIEW v1 AS SELECT CEIL(tmestmp TO YEAR) AS yr, CEIL(datee TO MONTH) AS mth, @@ -920,7 +921,7 @@ public void issue4677() { public void issue4649() { var ccs = this.getCCS(""" CREATE TABLE t(booll BOOL); - + CREATE MATERIALIZED VIEW equality_illegal AS SELECT booll = 456 AS booll, FALSE = 456 AS booll2 @@ -947,7 +948,7 @@ public void sltBugTest() { public void issue4708() { var ccs = this.getCCS(""" CREATE TABLE tbl(intt INT); - + CREATE MATERIALIZED VIEW v AS SELECT intt <=> -12 AS intt FROM tbl;"""); ccs.stepWeightOne("INSERT INTO tbl VALUES(NULL), (-12)", """ @@ -966,7 +967,7 @@ public void issue4729() { public void issue4752() { var ccs = this.getCCS(""" CREATE TABLE tbl(arr VARCHAR ARRAY); - + CREATE MATERIALIZED VIEW v1 AS SELECT arr BETWEEN ARRAY['bye', '14'] AND ARRAY['bye', '14'] AS arr FROM tbl;"""); @@ -978,7 +979,7 @@ public void issue4752() { this.getCCS(""" CREATE TABLE tbl(bin BINARY); - + CREATE MATERIALIZED VIEW v2 AS SELECT bin BETWEEN X'0B1620' AND X'0B1620' AS bin FROM tbl;"""); @@ -997,7 +998,7 @@ public void issue4834() { public void issue4815() { var ccs = this.getCCS(""" CREATE TABLE tbl(bin BINARY(3)); - + CREATE VIEW G AS SELECT LEAST(bin, X'1F8B0800') AS res, LEAST(X'0B1620', X'1F8B0800') AS res1 @@ -1035,7 +1036,7 @@ public void issue4797() { public void issue4817() { this.getCCS(""" CREATE TABLE tbl(mapp MAP); - + CREATE MATERIALIZED VIEW v AS SELECT LEAST_IGNORE_NULLS(mapp, MAP['a', 13, 'b', 17]) AS mapp FROM tbl;"""); @@ -1045,7 +1046,7 @@ public void issue4817() { public void issue4814() { this.getCCS(""" CREATE TABLE tbl(mapp MAP); - + CREATE MATERIALIZED VIEW v AS SELECT LEAST(mapp, MAP['a', 13, 'b', 17]) AS mapp FROM tbl;"""); @@ -1057,11 +1058,11 @@ public void issue4794() { CREATE TABLE tbl( arr VARCHAR ARRAY NULL, mapp MAP NULL); - + CREATE MATERIALIZED VIEW v1 AS SELECT COALESCE(NULL, arr, ARRAY ['bye']) AS arr FROM tbl; - + CREATE MATERIALIZED VIEW v2 AS SELECT COALESCE(NULL, mapp, MAP['a', 15, 'b', NULL]) AS mapp FROM tbl;"""); @@ -1073,7 +1074,7 @@ public void issue4794_2() { CREATE TABLE tbl( arr VARCHAR ARRAY NULL, mapp MAP NULL); - + CREATE MATERIALIZED VIEW v3 AS SELECT COALESCE(mapp, MAP['a', 15, 'b', NULL]) AS mapp FROM tbl;"""); @@ -1092,7 +1093,7 @@ public void issue4847() { // Validated on Postgres var ccs = this.getCCS(""" CREATE TABLE tbl(id INT, tiny_int TINYINT UNSIGNED); - + CREATE MATERIALIZED VIEW v AS SELECT STDDEV(tiny_int) AS tiny_int FROM tbl;"""); @@ -1125,7 +1126,7 @@ public void ifnullTest() { public void notDistinctFromTest() { this.getCCS(""" CREATE TABLE illegal_tbl(tmestmp TIMESTAMP); - + CREATE MATERIALIZED VIEW equality_null_legal AS SELECT tmestmp <=> NULL AS tmestmp FROM illegal_tbl;"""); } @@ -1140,7 +1141,7 @@ CREATE FUNCTION X(d VARCHAR NOT NULL) PARSE_TIMESTAMP('%Y-%m-%d %H:%M:%S Z', d), -- ISO 8601 with timezone offset (+/-HHMM or +/-HH:MM) PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%S.%3f%:z', d))); - + CREATE materialized VIEW V0 AS SELECT X('2011-12-01 00:00:00');"""); } @@ -1149,7 +1150,7 @@ public void issue4888() { this.getCC(""" CREATE TABLE tbl( roww ROW(i1 INT, v1 VARCHAR NULL)); - + CREATE MATERIALIZED VIEW v AS SELECT COALESCE(NULL, roww, ROW(4,'cat')) AS roww FROM tbl;"""); @@ -1160,11 +1161,11 @@ public void issue4889() { this.getCC(""" CREATE TABLE tbl( roww ROW(i1 INT, v1 VARCHAR NULL)); - + CREATE MATERIALIZED VIEW v1 AS SELECT GREATEST_IGNORE_NULLS(NULL, roww, ROW(5, NULL)) AS roww FROM tbl; - + CREATE MATERIALIZED VIEW v2 AS SELECT LEAST_IGNORE_NULLS(NULL, roww, ROW(5, NULL)) AS roww FROM tbl;"""); @@ -1184,7 +1185,7 @@ public void issue4923() { this.getCCS(""" CREATE TABLE tbl( roww ROW(i1 INT, v1 VARCHAR NULL)); - + CREATE MATERIALIZED VIEW v AS SELECT ARRAY(SELECT roww, roww FROM tbl) AS arr;"""); } @@ -1193,10 +1194,10 @@ CREATE TABLE tbl( public void mapVariant() { var ccs = this.getCCS(""" create table j(j VARCHAR); - + create LOCAL view user_props AS SELECT PARSE_JSON(j) AS contacts FROM j; - + create view abc as WITH ref_profile AS ( SELECT cast(contacts as MAP) contacts @@ -1219,11 +1220,11 @@ public void issue4890() { this.getCC(""" CREATE TABLE tbl( roww ROW(i1 INT, v1 VARCHAR NULL)); - + CREATE MATERIALIZED VIEW v1 AS SELECT roww IN (ROW(4,'cat')) AS roww FROM tbl; - + CREATE MATERIALIZED VIEW v2 AS SELECT roww IN (ROW(4,'cat')) AS roww FROM tbl;"""); @@ -1234,11 +1235,11 @@ public void issue4891() { this.getCC(""" CREATE TABLE tbl( roww ROW(i1 INT, v1 VARCHAR NULL)); - + CREATE MATERIALIZED VIEW v1 AS SELECT roww IN (roww) AS roww FROM tbl; - + CREATE MATERIALIZED VIEW v2 AS SELECT roww NOT IN (roww) AS roww FROM tbl;"""); @@ -1248,9 +1249,9 @@ roww NOT IN (roww) AS roww public void issue4975() { this.getCCS(""" CREATE TABLE tbl1(id INT, c2 VARCHAR); - + CREATE TABLE tbl2(id INT, c2 VARCHAR); - + CREATE MATERIALIZED VIEW v AS SELECT i.id, i.c2 AS i_c2, v.c2 AS v_c2 FROM tbl1 i @@ -1268,7 +1269,7 @@ CREATE TABLE T ( en VARCHAR, ss INT, ts BIGINT NOT NULL); - + CREATE VIEW s AS SELECT *, @@ -1323,16 +1324,16 @@ public void endVisit() { """ id | step | en | ss | ts | x | y | z --------------------------------------------------- - 1 | true | beta| 10 | 116 | 0 | false | true - 1 | true | alpha| 10 | 590 | 47| true | true - 1 | true | alpha| 10 | 597 | 0 | true | false - 1 | true | gamma| 10 | 604 | 0 | true | true + 1 | true | beta| 10 | 116 | 0 | false | true + 1 | true | alpha| 10 | 590 | 47| true | true + 1 | true | alpha| 10 | 597 | 0 | true | false + 1 | true | gamma| 10 | 604 | 0 | true | true 1 | true | delta| 20 | 618 | 1 | true | false - 2 | false | beta| 10 | 593 | 0 | false | true - 2 | false | alpha| 25 | 600 | 0 | false | false - 2 | false | eta| 12 | 608 | 0 | false | false - 2 | false | gamma| 25 | 615 | 0 | false | false - 2 | false | gamma| 25 | 622 | 0 | false | false"""); + 2 | false | beta| 10 | 593 | 0 | false | true + 2 | false | alpha| 25 | 600 | 0 | false | false + 2 | false | eta| 12 | 608 | 0 | false | false + 2 | false | gamma| 25 | 615 | 0 | false | false + 2 | false | gamma| 25 | 622 | 0 | false | false"""); } @Test @@ -1340,7 +1341,7 @@ public void testSlt() { this.getCC(""" CREATE TABLE tab0( pk INTEGER, col0 INTEGER, col1 REAL, col2 TEXT, col3 INTEGER, col4 REAL, col5 TEXT); - + CREATE VIEW V AS SELECT pk FROM tab0 WHERE col4 IS NULL AND ((col3 >= 4) OR col1 < 6.94 OR (((col1 BETWEEN 7.86 AND 3.33) AND (col3 > 3 AND col1 <= 3.18 AND col0 > 4 AND col4 < 2.65) AND (col0 IS NULL))) OR col4 BETWEEN 2.56 AND 1.46 AND col3 < 5) OR col1 BETWEEN 0.15 AND 9.37 AND @@ -1357,27 +1358,27 @@ CREATE TABLE interval_tbl( id INT NOT NULL, c1 TIMESTAMP, c2 TIMESTAMP); - + CREATE LOCAL VIEW atbl_interval_months AS SELECT id, (c1 - c2)MONTH AS c1_minus_c2 FROM interval_tbl; - + CREATE LOCAL VIEW atbl_interval_seconds AS SELECT id, (c1 - c2)SECOND AS c1_minus_c2 FROM interval_tbl; - + CREATE LOCAL VIEW atbl_interval_seconds_res AS SELECT id, CAST(c1_minus_c2 AS VARCHAR) AS f_c1 FROM atbl_interval_seconds; - + CREATE LOCAL VIEW atbl_interval_months_res AS SELECT id, CAST(c1_minus_c2 AS VARCHAR) AS f_c1 FROM atbl_interval_months; - + CREATE VIEW V AS (SELECT * FROM atbl_interval_seconds_res) UNION ALL (SELECT * FROM atbl_interval_months_res);"""); ccs.stepWeightOne("INSERT INTO interval_tbl VALUES(0, '2014-11-05 08:27:00', '2024-12-05 12:45:00')", """ id | f_c1 @@ -1391,7 +1392,7 @@ public void issue5120() { var ccs = this.getCCS(""" CREATE TYPE S AS(i1 INT NOT NULL, i2 INT); CREATE TABLE tbl(id INT, c1_arr S ARRAY); - + CREATE VIEW v AS SELECT id, i1_val + 1, i2_val + 1, idx FROM tbl, @@ -1407,7 +1408,7 @@ public void issue5120() { ccs = this.getCCS(""" CREATE TABLE tbl(id INT, c1_arr ROW(i1 INT NOT NULL, i2 INT NULL) ARRAY NOT NULL); - + CREATE VIEW v AS SELECT id, i1_val + 1, i2_val + 1, idx FROM tbl, @@ -1429,26 +1430,26 @@ public void testBinaryStringCast() { --- @AA (1 row) - + SELECT bin2utf8(NULL); r --- NULL (1 row) - + -- FF is invalid SELECT bin2utf8(x'FF'); r --- NULL (1 row) - + SELECT bin2utf8(x'f09f918b'); r --- 👋 (1 row) - + SELECT bin2utf8(CAST('👋' AS VARBINARY)); r --- @@ -1477,14 +1478,14 @@ public void issue5276() { CREATE TYPE LEVEL_1 AS ( col VARCHAR ); - + CREATE TYPE LEVEL_0 AS ( col LEVEL_1 ); - + CREATE TABLE T(l LEVEL_0, X INT); CREATE TABLE S(X INT); - + CREATE VIEW V AS (SELECT * FROM T) UNION (SELECT NULL, X FROM S)"""); } @@ -1495,11 +1496,11 @@ public void issue5275() { CREATE TYPE LEVEL_1 AS ( col VARCHAR ); - + CREATE TYPE LEVEL_0 AS ( col LEVEL_1 ); - + CREATE LOCAL VIEW V AS SELECT CAST(NULL AS LEVEL_0)"""); } @@ -1511,7 +1512,7 @@ CREATE TABLE tbl( id INT, intt INT, roww ROW(i1 INT, v1 VARCHAR NULL) NULL); - + CREATE MATERIALIZED VIEW v AS SELECT AVG(roww[1]) AS roww FROM tbl WHERE id = 0;"""); @@ -1541,7 +1542,7 @@ SELECT x, x in (SELECT e from FT) public void issue5299() { this.getCC(""" CREATE LINEAR AGGREGATE u256_sum(value BINARY(32)) RETURNS BINARY(32); - + CREATE TABLE A ( id VARCHAR(20) NOT NULL PRIMARY KEY, a VARCHAR(64), @@ -1551,7 +1552,7 @@ small DECIMAL(38, 18), num1 BINARY(32), num2 BINARY(32) ) WITH ('append_only' = 'true'); - + CREATE VIEW b AS SELECT u256_sum(num1), u256_sum(num2), SUM(small), MAX(sno) FROM A"""); @@ -1563,11 +1564,11 @@ public void issue5307() { CREATE TYPE LEVEL_1 AS ( col VARCHAR NOT NULL ); - + CREATE TYPE LEVEL_0 AS ( col LEVEL_1 ); - + CREATE LOCAL VIEW V AS SELECT NULL::LEVEL_0 AS null_col"""); } @@ -1620,7 +1621,7 @@ public void issue5345() { public void issue5352() { var ccs = this.getCCS(""" CREATE TABLE tbl(str VARCHAR); - + CREATE MATERIALIZED VIEW v AS SELECT str::BOOLEAN IS FALSE AS arr, str::BOOLEAN IS TRUE AS arr1 @@ -1639,79 +1640,79 @@ public void issue5352_a() { --- true (1 row) - + SELECT 'true'::BOOLEAN; r --- true (1 row) - + SELECT 'TrUe'::BOOLEAN; r --- true (1 row) - + SELECT NULL::BOOLEAN; r --- NULL (1 row) - + SELECT SAFE_CAST('TRUE' AS BOOLEAN); r --- true (1 row) - + SELECT SAFE_CAST('true' AS BOOLEAN); r --- true (1 row) - + SELECT SAFE_CAST('TrUe' AS BOOLEAN); r --- true (1 row) - + SELECT SAFE_CAST('t' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST('no' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST('N' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST('1' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST('0' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST('yes' AS BOOLEAN); r --- NULL (1 row) - + SELECT SAFE_CAST(NULL AS BOOLEAN); r --- @@ -1744,7 +1745,7 @@ public void issue5331() { this.statementsFailingInCompilation(""" CREATE TABLE asof_tbl1(intt INT, arr VARCHAR ARRAY); CREATE TABLE asof_tbl2(intt INT, arr VARCHAR ARRAY); - + CREATE MATERIALIZED VIEW v AS SELECT * FROM asof_tbl1 t1 LEFT ASOF JOIN asof_tbl2 t2 @@ -1758,7 +1759,7 @@ public void issue5384() { this.statementsFailingInCompilation(""" CREATE TYPE user_def AS(i1 INT, v1 VARCHAR NULL); CREATE TABLE tbl(mapp1 MAP); - + CREATE MATERIALIZED VIEW v AS SELECT CAST(mapp1 AS MAP) AS to_map FROM tbl;""", "Cast function cannot convert value of type "); @@ -1772,12 +1773,12 @@ CREATE TABLE source ( key VARCHAR NOT NULL INTERNED, version BIGINT ) WITH ('append_only' = 'true'); - + CREATE TABLE lookup ( key VARCHAR NOT NULL INTERNED PRIMARY KEY, metadata VARCHAR ); - + CREATE LOCAL VIEW v AS SELECT @@ -1785,7 +1786,7 @@ CREATE TABLE lookup ( MAX(key) as key FROM source GROUP BY id; - + CREATE VIEW result AS SELECT @@ -1838,7 +1839,7 @@ public void issue5375() { public void issue5378() { var ccs = this.getCCS(""" CREATE TABLE tbl(mapp MAP); - + CREATE MATERIALIZED VIEW v AS SELECT MAP_KEYS(SAFE_CAST(mapp AS MAP)), MAP_VALUES(SAFE_CAST(mapp AS MAP)) @@ -1857,7 +1858,7 @@ public void issue5378() { public void issue5379() { this.statementsFailingInCompilation(""" CREATE TABLE tbl(mapp MAP); - + CREATE MATERIALIZED VIEW v AS SELECT CAST(mapp AS MAP) AS to_map, SAFE_CAST(mapp AS MAP) AS to_map1 @@ -1869,7 +1870,7 @@ public void issue5379() { public void issue5380() { this.statementsFailingInCompilation(""" CREATE TABLE tbl(mapp MAP); - + CREATE MATERIALIZED VIEW v AS SELECT CAST(mapp AS MAP) AS to_map FROM tbl;""", "Cast function cannot convert value of type (VARCHAR CHARACTER SET \"UTF-8\" NOT NULL, INTEGER) MAP"); @@ -1883,7 +1884,7 @@ public void safeArrayCast() { --- NULL (1 row) - + SELECT SAFE_CAST(ARRAY['1'] AS INT ARRAY); r --- @@ -1899,7 +1900,7 @@ public void safeNestedArrayCast() { --- NULL (1 row) - + SELECT ELEMENT(SAFE_CAST(ARRAY[ARRAY['1']] AS INT ARRAY ARRAY)); r --- @@ -1923,7 +1924,7 @@ public void issue5390() { CREATE TYPE user_def_array AS (val VARCHAR ARRAY); CREATE TYPE user_def_row AS (val ROW(i1 INT, v1 VARCHAR NULL)); CREATE TYPE user_def_udt AS (val user_def); - + CREATE TABLE tbl(arr VARCHAR ARRAY, mapp MAP, roww ROW(i1 INT, v1 VARCHAR NULL) NULL, udt user_def); CREATE MATERIALIZED VIEW v AS SELECT @@ -1945,11 +1946,11 @@ public void mapCast() { this.getCCS(""" CREATE TABLE varnt_cmpx_tbl( roww ROW(int INT, var VARCHAR)); - + CREATE MATERIALIZED VIEW cmpx_to_variant AS SELECT CAST(roww AS VARIANT) AS roww_varnt FROM varnt_cmpx_tbl; - + CREATE MATERIALIZED VIEW variant_to_cmpx AS SELECT CAST(roww_varnt AS ROW(int INT, var VARCHAR)) AS roww FROM cmpx_to_variant;"""); @@ -1960,7 +1961,7 @@ public void issue5448() { // Also test for issue 5449 var ccs = this.getCCS(""" CREATE TABLE tbl(intt INTEGER UNSIGNED, x INT); - + CREATE MATERIALIZED VIEW v AS SELECT ABS(intt) AS a, SIGN(x) as s, SIGN(intt) as i FROM tbl;"""); ccs.stepWeightOne("INSERT INTO tbl VALUES(0, 0), (1, 1), (2, -1)", """ @@ -1978,13 +1979,13 @@ CREATE TABLE T ( str VARCHAR, data INT NOT NULL ); - + CREATE LOCAL VIEW V AS SELECT T.str AS str, ARRAY_AGG(ROW(T.data)) AS e FROM T GROUP BY T.str; - + CREATE VIEW W AS SELECT CASE WHEN V.str IS NOT NULL THEN V.e ELSE NULL diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java index 4503fb59274..1c09deec61e 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java @@ -50,7 +50,7 @@ CREATE TABLE T ( id INT, col ROW(field1 VARCHAR, field2 INT) ); - + CREATE VIEW V AS SELECT id FROM T t ORDER BY (t.col).field2;"""); } @@ -145,8 +145,8 @@ CREATE TABLE purchase ( ) WITH ( 'append_only' = 'true' ); - - + + CREATE MATERIALIZED VIEW v1 WITH ('emit_final' = 'a_ts') AS @@ -156,7 +156,7 @@ CREATE TABLE purchase ( FROM purchase a JOIN purchase b ON a.ts = b.ts; - + CREATE MATERIALIZED VIEW v2 WITH ('emit_final' = 'a_ts') AS @@ -177,7 +177,7 @@ CREATE TABLE T ( amount INT, seq BOOL ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous @@ -205,17 +205,17 @@ CREATE TABLE T ( String expected = """ customer_id | previous ------------------------ - 1 | 3 - 1 | 33 - 1 | 33 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 3 + 1 | 33 + 1 | 33 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; var ccs = this.getCCS(program); ccs.stepWeightOne(data, expected); @@ -229,17 +229,17 @@ CREATE TABLE T ( String expected2 = """ customer_id | previous ------------------------ - 1 | 30 - 1 | 30 - 1 | 25 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 30 + 1 | 30 + 1 | 25 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; ccs.stepWeightOne(data, expected2); } @@ -253,7 +253,7 @@ CREATE TABLE T ( d1 TIMESTAMP, d2 TIMESTAMP ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY (d1 - d2) HOURS) AS previous @@ -281,17 +281,17 @@ CREATE TABLE T ( String expected = """ customer_id | previous ------------------------ - 1 | 3 - 1 | 13 - 1 | 33 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 6 - 4 | 6 - 4 | 6"""; + 1 | 3 + 1 | 13 + 1 | 33 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 6 + 4 | 6 + 4 | 6"""; var ccs = this.getCCS(program); ccs.stepWeightOne(data, expected); @@ -305,17 +305,17 @@ CREATE TABLE T ( String expected2 = """ customer_id | previous ------------------------ - 1 | 10 - 1 | 30 - 1 | 25 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 6 - 4 | 6 - 4 | 6"""; + 1 | 10 + 1 | 30 + 1 | 25 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 6 + 4 | 6 + 4 | 6"""; ccs.stepWeightOne(data, expected2); } @@ -329,7 +329,7 @@ CREATE TABLE T ( d1 TIMESTAMP, d2 TIMESTAMP ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY (d1 - d2) MONTHS) AS previous @@ -357,17 +357,17 @@ CREATE TABLE T ( String expected = """ customer_id | previous ------------------------ - 1 | 3 - 1 | 13 - 1 | 33 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 6 - 4 | 6 - 4 | 6"""; + 1 | 3 + 1 | 13 + 1 | 33 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 6 + 4 | 6 + 4 | 6"""; var ccs = this.getCCS(program); ccs.stepWeightOne(data, expected); @@ -381,17 +381,17 @@ CREATE TABLE T ( String expected2 = """ customer_id | previous ------------------------ - 1 | 10 - 1 | 30 - 1 | 25 - 1 | 28 - 2 | 3 - 2 | 3 - 2 | 10 - 3 | 100 - 4 | 6 - 4 | 6 - 4 | 6"""; + 1 | 10 + 1 | 30 + 1 | 25 + 1 | 28 + 2 | 3 + 2 | 3 + 2 | 10 + 3 | 100 + 4 | 6 + 4 | 6 + 4 | 6"""; ccs.stepWeightOne(data, expected2); } @@ -406,7 +406,7 @@ CREATE TABLE T ( d1 TIMESTAMP NOT NULL, d2 TIMESTAMP NOT NULL ); - + CREATE VIEW V AS SELECT customer_id, """; @@ -419,7 +419,7 @@ CREATE TABLE T ( amount INT, seq BOOL NOT NULL ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous FROM T;"""); @@ -448,7 +448,7 @@ CREATE TABLE T ( amount INT, seq BINARY(1) ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous @@ -477,17 +477,17 @@ seq BINARY(1) String expected = """ customer_id | previous ------------------------ - 1 | 3 - 1 | 13 - 1 | 33 - 1 | 28 - 2 | 0 - 2 | 7 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 3 + 1 | 13 + 1 | 33 + 1 | 28 + 2 | 0 + 2 | 7 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; var ccs = this.getCCS(program); ccs.stepWeightOne(data, expected); @@ -501,17 +501,17 @@ seq BINARY(1) String expected2 = """ customer_id | previous ------------------------ - 1 | 10 - 1 | 30 - 1 | 25 - 1 | 28 - 2 | 0 - 2 | 7 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 10 + 1 | 30 + 1 | 25 + 1 | 28 + 2 | 0 + 2 | 7 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; ccs.stepWeightOne(data, expected2); } @@ -525,7 +525,7 @@ CREATE TABLE T ( amount INT, seq BINARY(1) NOT NULL ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous @@ -552,16 +552,16 @@ seq BINARY(1) NOT NULL String expected = """ customer_id | previous ------------------------ - 1 | 10 - 1 | 30 - 1 | 25 - 2 | 0 - 2 | 7 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 10 + 1 | 30 + 1 | 25 + 2 | 0 + 2 | 7 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; var ccs = this.getCCS(program); ccs.stepWeightOne(data, expected); @@ -575,16 +575,16 @@ seq BINARY(1) NOT NULL String expected2 = """ customer_id | previous ------------------------ - 1 | 10 - 1 | 30 - 1 | 25 - 2 | 0 - 2 | 7 - 2 | 10 - 3 | 100 - 4 | 3 - 4 | 3 - 4 | 6"""; + 1 | 10 + 1 | 30 + 1 | 25 + 2 | 0 + 2 | 7 + 2 | 10 + 3 | 100 + 4 | 3 + 4 | 3 + 4 | 6"""; ccs.stepWeightOne(data, expected2); } @@ -597,7 +597,7 @@ CREATE TABLE T ( amount INT, seq BINARY(16) ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous @@ -609,7 +609,7 @@ CREATE TABLE T ( amount INT, seq VARBINARY ); - + CREATE VIEW V AS SELECT customer_id, SUM(amount) OVER (PARTITION BY customer_id ORDER BY seq) AS previous @@ -624,19 +624,19 @@ public void issue6352() { --- t (1 row) - + SELECT SAFE_CAST('false' AS BOOL); r --- f (1 row) - + SELECT SAFE_CAST('blah' AS BOOL); r --- NULL (1 row) - + SELECT SAFE_CAST('t' AS BOOL); r --- @@ -649,13 +649,13 @@ public void issue6352() { --- 0 (1 row) - + SELECT SAFE_CAST('false' AS DOUBLE); r --- NULL (1 row) - + SELECT SAFE_CAST(NULL AS DOUBLE); r --- @@ -668,19 +668,19 @@ public void issue6352() { --- 0 (1 row) - + SELECT SAFE_CAST('false' AS REAL); r --- NULL (1 row) - + SELECT SAFE_CAST('Infinity' AS REAL); r --- Infinity (1 row) - + SELECT SAFE_CAST(NULL AS REAL); r --- @@ -714,7 +714,7 @@ CREATE TABLE T( b VARCHAR, r ROW (b VARCHAR) ); - + CREATE VIEW Z AS SELECT b, r.b, t.b FROM T;"""); } }