1use core::mem;
16use core::time::Duration;
17use std::collections::{HashMap, HashSet, VecDeque};
18use std::fmt::{Display, Formatter};
19use std::sync::Arc;
20use std::time::Instant;
21
22use anyhow::anyhow;
23use bytes::Bytes;
24use futures::StreamExt;
25use itertools::Itertools;
26use pgwire::pg_field_descriptor::PgFieldDescriptor;
27use pgwire::pg_response::StatementType;
28use pgwire::types::{Format, Row};
29use risingwave_batch::task::{ShutdownSender, ShutdownToken};
30use risingwave_common::catalog::{ColumnCatalog, Field};
31use risingwave_common::error::BoxedError;
32use risingwave_common::session_config::QueryMode;
33use risingwave_common::types::{DataType, ScalarImpl, StructType, StructValue};
34use risingwave_common::util::iter_util::ZipEqFast;
35use risingwave_hummock_sdk::HummockVersionId;
36
37use super::SessionImpl;
38use crate::catalog::TableId;
39use crate::catalog::subscription_catalog::SubscriptionCatalog;
40use crate::error::{ErrorCode, Result};
41use crate::expr::{ExprType, FunctionCall, InputRef, Literal};
42use crate::handler::HandlerArgs;
43use crate::handler::declare_cursor::create_chunk_stream_for_cursor;
44use crate::handler::query::{RwBatchQueryPlanResult, gen_batch_plan_fragmenter};
45use crate::handler::util::{
46 DataChunkToRowSetAdapter, StaticSessionData, convert_logstore_u64_to_unix_millis,
47 pg_value_format, to_pg_field,
48};
49use crate::monitor::{CursorMetrics, PeriodicCursorMetrics};
50use crate::optimizer::PlanRoot;
51use crate::optimizer::plan_node::{BatchFilter, BatchLogSeqScan, BatchSeqScan, generic};
52use crate::optimizer::property::{Order, RequiredDist};
53use crate::scheduler::{DistributedQueryStream, LocalQueryStream, ReadSnapshot, SchedulerError};
54use crate::utils::Condition;
55use crate::{OptimizerContext, OptimizerContextRef, PgResponseStream, TableCatalog};
56
57pub enum CursorDataChunkStream {
58 LocalDataChunk(Option<LocalQueryStream>),
59 DistributedDataChunk(Option<DistributedQueryStream>),
60 PgResponse(PgResponseStream),
61}
62
63pub struct FetchCursorCancelHandle {
64 cancel_tx: ShutdownSender,
65 cancel_rx: ShutdownToken,
66}
67
68impl FetchCursorCancelHandle {
69 pub fn new() -> Self {
70 let (cancel_tx, cancel_rx) = ShutdownToken::new();
71 Self {
72 cancel_tx,
73 cancel_rx,
74 }
75 }
76
77 fn register(&self, session: &SessionImpl) {
78 session.set_cancel_query_flag(self.cancel_tx.clone());
79 }
80
81 async fn cancelled(&mut self) {
82 self.cancel_rx.cancelled().await;
83 }
84
85 fn is_cancelled(&self) -> bool {
86 self.cancel_rx.is_cancelled()
87 }
88}
89
90impl CursorDataChunkStream {
91 pub fn init_row_stream(
92 &mut self,
93 fields: &Vec<Field>,
94 formats: &Vec<Format>,
95 session: Arc<SessionImpl>,
96 ) {
97 let columns_type = fields.iter().map(|f| f.data_type()).collect();
98 match self {
99 CursorDataChunkStream::LocalDataChunk(data_chunk) => {
100 let data_chunk = mem::take(data_chunk).unwrap();
101 let row_stream = PgResponseStream::LocalQuery(DataChunkToRowSetAdapter::new(
102 data_chunk,
103 columns_type,
104 formats.clone(),
105 session,
106 ));
107 *self = CursorDataChunkStream::PgResponse(row_stream);
108 }
109 CursorDataChunkStream::DistributedDataChunk(data_chunk) => {
110 let data_chunk = mem::take(data_chunk).unwrap();
111 let row_stream = PgResponseStream::DistributedQuery(DataChunkToRowSetAdapter::new(
112 data_chunk,
113 columns_type,
114 formats.clone(),
115 session,
116 ));
117 *self = CursorDataChunkStream::PgResponse(row_stream);
118 }
119 _ => {}
120 }
121 }
122
123 pub async fn next(&mut self) -> Result<Option<std::result::Result<Vec<Row>, BoxedError>>> {
124 match self {
125 CursorDataChunkStream::PgResponse(row_stream) => Ok(row_stream.next().await),
126 _ => Err(ErrorCode::InternalError(
127 "Only 'CursorDataChunkStream' can call next and return rows".to_owned(),
128 )
129 .into()),
130 }
131 }
132}
133pub enum Cursor {
134 Subscription(SubscriptionCursor),
135 Query(QueryCursor),
136}
137impl Cursor {
138 pub async fn next(
139 &mut self,
140 count: u32,
141 handler_args: HandlerArgs,
142 formats: &Vec<Format>,
143 timeout_seconds: Option<u64>,
144 cancel_handle: &mut FetchCursorCancelHandle,
145 ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
146 match self {
147 Cursor::Subscription(cursor) => cursor
148 .next(count, handler_args, formats, timeout_seconds, cancel_handle)
149 .await
150 .inspect_err(|_| cursor.cursor_metrics.subscription_cursor_error_count.inc()),
151 Cursor::Query(cursor) => {
152 cursor
153 .next(count, formats, handler_args, timeout_seconds)
154 .await
155 }
156 }
157 }
158
159 pub fn get_fields(&mut self) -> Vec<Field> {
160 match self {
161 Cursor::Subscription(cursor) => cursor.fields_manager.get_output_fields(),
162 Cursor::Query(cursor) => cursor.fields.clone(),
163 }
164 }
165}
166
167pub struct QueryCursor {
168 chunk_stream: CursorDataChunkStream,
169 fields: Vec<Field>,
170 remaining_rows: VecDeque<Row>,
171}
172
173impl QueryCursor {
174 pub fn new(chunk_stream: CursorDataChunkStream, fields: Vec<Field>) -> Result<Self> {
175 Ok(Self {
176 chunk_stream,
177 fields,
178 remaining_rows: VecDeque::<Row>::new(),
179 })
180 }
181
182 pub async fn next_once(&mut self) -> Result<Option<Row>> {
183 while self.remaining_rows.is_empty() {
184 let rows = self.chunk_stream.next().await?;
185 let rows = match rows {
186 None => return Ok(None),
187 Some(row) => row?,
188 };
189 self.remaining_rows = rows.into_iter().collect();
190 }
191 let row = self.remaining_rows.pop_front().unwrap();
192 Ok(Some(row))
193 }
194
195 pub async fn next(
196 &mut self,
197 count: u32,
198 formats: &Vec<Format>,
199 handler_args: HandlerArgs,
200 timeout_seconds: Option<u64>,
201 ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
202 let timeout_instant = timeout_seconds.map(|s| Instant::now() + Duration::from_secs(s));
205 let session = handler_args.session;
206 let mut ans = Vec::with_capacity(std::cmp::min(100, count) as usize);
207 let mut cur = 0;
208 let desc = self.fields.iter().map(to_pg_field).collect();
209 self.chunk_stream
210 .init_row_stream(&self.fields, formats, session);
211 while cur < count
212 && let Some(row) = self.next_once().await?
213 {
214 cur += 1;
215 ans.push(row);
216 if let Some(timeout_instant) = timeout_instant
217 && Instant::now() > timeout_instant
218 {
219 break;
220 }
221 }
222 Ok((ans, desc))
223 }
224}
225
226enum State {
227 InitLogStoreQuery {
228 seek_timestamp: u64,
230
231 expected_timestamp: Option<u64>,
233 },
234 Fetch {
235 from_snapshot: bool,
239
240 rw_timestamp: u64,
242
243 chunk_stream: CursorDataChunkStream,
246
247 remaining_rows: VecDeque<Row>,
249
250 expected_timestamp: Option<u64>,
251
252 init_query_timer: Instant,
253 },
254 Invalid,
255}
256
257impl Display for State {
258 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
259 match self {
260 State::InitLogStoreQuery {
261 seek_timestamp,
262 expected_timestamp,
263 } => write!(
264 f,
265 "InitLogStoreQuery {{ seek_timestamp: {}, expected_timestamp: {:?} }}",
266 seek_timestamp, expected_timestamp
267 ),
268 State::Fetch {
269 from_snapshot,
270 rw_timestamp,
271 expected_timestamp,
272 remaining_rows,
273 init_query_timer,
274 ..
275 } => write!(
276 f,
277 "Fetch {{ from_snapshot: {}, rw_timestamp: {}, expected_timestamp: {:?}, cached rows: {}, query init at {}ms before }}",
278 from_snapshot,
279 rw_timestamp,
280 expected_timestamp,
281 remaining_rows.len(),
282 init_query_timer.elapsed().as_millis()
283 ),
284 State::Invalid => write!(f, "Invalid"),
285 }
286 }
287}
288
289struct FieldsManager {
290 columns_catalog: Vec<ColumnCatalog>,
291 row_fields: Vec<Field>,
293 row_output_col_indices: Vec<usize>,
295 row_pk_indices: Vec<usize>,
297 stream_chunk_row_indices: Vec<usize>,
299 op_index: usize,
301}
302
303impl FieldsManager {
304 pub fn new(catalog: &TableCatalog) -> Self {
308 let mut row_fields = Vec::new();
309 let mut row_output_col_indices = Vec::new();
310 let mut row_pk_indices = Vec::new();
311 let mut stream_chunk_row_indices = Vec::new();
312 let mut output_idx = 0_usize;
313 let pk_set: HashSet<usize> = catalog
314 .pk
315 .iter()
316 .map(|col_order| col_order.column_index)
317 .collect();
318
319 for (index, v) in catalog.columns.iter().enumerate() {
320 if pk_set.contains(&index) {
321 row_pk_indices.push(output_idx);
322 stream_chunk_row_indices.push(output_idx);
323 row_fields.push(Field::with_name(v.data_type().clone(), v.name()));
324 if !v.is_hidden {
325 row_output_col_indices.push(output_idx);
326 }
327 output_idx += 1;
328 } else if !v.is_hidden {
329 row_output_col_indices.push(output_idx);
330 stream_chunk_row_indices.push(output_idx);
331 row_fields.push(Field::with_name(v.data_type().clone(), v.name()));
332 output_idx += 1;
333 }
334 }
335
336 row_fields.push(Field::with_name(DataType::Varchar, "op".to_owned()));
337 row_output_col_indices.push(output_idx);
338 let op_index = output_idx;
339 output_idx += 1;
340 row_fields.push(Field::with_name(DataType::Int64, "rw_timestamp".to_owned()));
341 row_output_col_indices.push(output_idx);
342 Self {
343 columns_catalog: catalog.columns.clone(),
344 row_fields,
345 row_output_col_indices,
346 row_pk_indices,
347 stream_chunk_row_indices,
348 op_index,
349 }
350 }
351
352 pub fn try_refill_fields(&mut self, catalog: &TableCatalog) -> bool {
353 if self.columns_catalog.ne(&catalog.columns) {
354 *self = Self::new(catalog);
355 true
356 } else {
357 false
358 }
359 }
360
361 pub fn process_output_desc_row(&self, mut rows: Vec<Row>) -> (Vec<Row>, Option<Row>) {
362 let last_row = rows.last_mut().map(|row| {
363 let mut row = row.clone();
364 row.project(&self.row_pk_indices)
365 });
366 let rows = rows
367 .iter_mut()
368 .map(|row| row.project(&self.row_output_col_indices))
369 .collect();
370 (rows, last_row)
371 }
372
373 pub fn get_output_fields(&self) -> Vec<Field> {
374 self.row_output_col_indices
375 .iter()
376 .map(|&idx| self.row_fields[idx].clone())
377 .collect()
378 }
379
380 pub fn get_row_stream_fields_and_formats(
383 &self,
384 formats: &Vec<Format>,
385 from_snapshot: bool,
386 ) -> (Vec<Field>, Vec<Format>) {
387 let mut fields = Vec::new();
388 let need_format = !(formats.is_empty() || formats.len() == 1);
389 let mut new_formats = formats.clone();
390 let stream_chunk_row_indices_iter = if from_snapshot {
391 self.stream_chunk_row_indices.iter().chain(None)
392 } else {
393 self.stream_chunk_row_indices
394 .iter()
395 .chain(Some(&self.op_index))
396 };
397 for index in stream_chunk_row_indices_iter {
398 fields.push(self.row_fields[*index].clone());
399 if need_format && !self.row_output_col_indices.contains(index) {
400 new_formats.insert(*index, Format::Text);
401 }
402 }
403 (fields, new_formats)
404 }
405}
406
407pub struct SubscriptionCursor {
408 cursor_name: String,
409 subscription: Arc<SubscriptionCatalog>,
410 dependent_table_id: TableId,
411 cursor_need_drop_time: Instant,
412 state: State,
413 fields_manager: FieldsManager,
416 cursor_metrics: Arc<CursorMetrics>,
417 last_fetch: Instant,
418 seek_pk_row: Option<Row>,
419}
420
421impl SubscriptionCursor {
422 pub async fn new(
423 cursor_name: String,
424 start_timestamp: Option<u64>,
425 subscription: Arc<SubscriptionCatalog>,
426 dependent_table_id: TableId,
427 handler_args: &HandlerArgs,
428 cursor_metrics: Arc<CursorMetrics>,
429 ) -> Result<Self> {
430 let (state, fields_manager) = if let Some(start_timestamp) = start_timestamp {
431 let table_catalog = handler_args.session.get_table_by_id(dependent_table_id)?;
432 (
433 State::InitLogStoreQuery {
434 seek_timestamp: start_timestamp,
435 expected_timestamp: None,
436 },
437 FieldsManager::new(&table_catalog),
438 )
439 } else {
440 let (chunk_stream, init_query_timer, table_catalog) =
445 Self::initiate_query(None, dependent_table_id, handler_args.clone(), None).await?;
446 let pinned_epoch = match handler_args.session.get_pinned_snapshot().ok_or_else(
447 || ErrorCode::InternalError("Fetch Cursor can't find snapshot epoch".to_owned()),
448 )? {
449 ReadSnapshot::FrontendPinned { snapshot, .. } => {
450 snapshot
451 .version()
452 .state_table_info
453 .info()
454 .get(&dependent_table_id)
455 .ok_or_else(|| {
456 anyhow!("dependent_table_id {dependent_table_id} not exists")
457 })?
458 .committed_epoch
459 }
460 ReadSnapshot::Other(_) => {
461 return Err(ErrorCode::InternalError("Fetch Cursor can't start from specified query epoch. May run `set query_epoch = 0;`".to_owned()).into());
462 }
463 ReadSnapshot::ReadUncommitted => {
464 return Err(ErrorCode::InternalError(
465 "Fetch Cursor don't support read uncommitted".to_owned(),
466 )
467 .into());
468 }
469 };
470 let start_timestamp = pinned_epoch;
471
472 (
473 State::Fetch {
474 from_snapshot: true,
475 rw_timestamp: start_timestamp,
476 chunk_stream,
477 remaining_rows: VecDeque::new(),
478 expected_timestamp: None,
479 init_query_timer,
480 },
481 FieldsManager::new(&table_catalog),
482 )
483 };
484
485 let cursor_need_drop_time =
486 Instant::now() + Duration::from_secs(subscription.retention_seconds);
487 Ok(Self {
488 cursor_name,
489 subscription,
490 dependent_table_id,
491 cursor_need_drop_time,
492 state,
493 fields_manager,
494 cursor_metrics,
495 last_fetch: Instant::now(),
496 seek_pk_row: None,
497 })
498 }
499
500 async fn next_row(
501 &mut self,
502 handler_args: &HandlerArgs,
503 formats: &Vec<Format>,
504 ) -> Result<Option<Row>> {
505 loop {
506 match &mut self.state {
507 State::InitLogStoreQuery {
508 seek_timestamp,
509 expected_timestamp,
510 } => {
511 let from_snapshot = false;
512
513 match Self::get_next_rw_timestamp(
515 *seek_timestamp,
516 self.dependent_table_id,
517 *expected_timestamp,
518 handler_args.clone(),
519 &self.subscription,
520 )
521 .await
522 {
523 Ok((Some(rw_timestamp), expected_timestamp)) => {
524 let (mut chunk_stream, init_query_timer, catalog) =
525 Self::initiate_query(
526 Some(rw_timestamp),
527 self.dependent_table_id,
528 handler_args.clone(),
529 None,
530 )
531 .await?;
532 let table_schema_changed =
533 self.fields_manager.try_refill_fields(&catalog);
534 let (fields, formats) = self
535 .fields_manager
536 .get_row_stream_fields_and_formats(formats, from_snapshot);
537 chunk_stream.init_row_stream(
538 &fields,
539 &formats,
540 handler_args.session.clone(),
541 );
542
543 self.cursor_need_drop_time = Instant::now()
544 + Duration::from_secs(self.subscription.retention_seconds);
545 let mut remaining_rows = VecDeque::new();
546 Self::try_refill_remaining_rows(&mut chunk_stream, &mut remaining_rows)
547 .await?;
548 self.state = State::Fetch {
550 from_snapshot,
551 rw_timestamp,
552 chunk_stream,
553 remaining_rows,
554 expected_timestamp,
555 init_query_timer,
556 };
557 if table_schema_changed {
558 return Ok(None);
559 }
560 }
561 Ok((None, _)) => return Ok(None),
562 Err(e) => {
563 self.state = State::Invalid;
564 return Err(e);
565 }
566 }
567 }
568 State::Fetch {
569 from_snapshot,
570 rw_timestamp,
571 chunk_stream,
572 remaining_rows,
573 expected_timestamp,
574 init_query_timer,
575 } => {
576 let session_data = StaticSessionData {
577 timezone: handler_args.session.config().timezone(),
578 };
579 let from_snapshot = *from_snapshot;
580 let rw_timestamp = *rw_timestamp;
581
582 Self::try_refill_remaining_rows(chunk_stream, remaining_rows).await?;
584
585 if let Some(row) = remaining_rows.pop_front() {
586 if from_snapshot {
588 return Ok(Some(Self::build_row(
589 row.take(),
590 None,
591 formats,
592 &session_data,
593 )?));
594 } else {
595 return Ok(Some(Self::build_row(
596 row.take(),
597 Some(rw_timestamp),
598 formats,
599 &session_data,
600 )?));
601 }
602 } else {
603 self.cursor_metrics
604 .subscription_cursor_query_duration
605 .with_label_values(&[&self.subscription.name])
606 .observe(init_query_timer.elapsed().as_millis() as _);
607 if let Some(expected_timestamp) = expected_timestamp {
609 self.state = State::InitLogStoreQuery {
610 seek_timestamp: *expected_timestamp,
611 expected_timestamp: Some(*expected_timestamp),
612 };
613 } else {
614 self.state = State::InitLogStoreQuery {
615 seek_timestamp: rw_timestamp + 1,
616 expected_timestamp: None,
617 };
618 }
619 }
620 }
621 State::Invalid => {
622 return Err(ErrorCode::InternalError(
624 "Cursor is in invalid state. Please close and re-create the cursor."
625 .to_owned(),
626 )
627 .into());
628 }
629 }
630 }
631 }
632
633 pub async fn next(
634 &mut self,
635 count: u32,
636 handler_args: HandlerArgs,
637 formats: &Vec<Format>,
638 timeout_seconds: Option<u64>,
639 cancel_handle: &mut FetchCursorCancelHandle,
640 ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
641 let timeout_instant = timeout_seconds.map(|s| Instant::now() + Duration::from_secs(s));
642 if Instant::now() > self.cursor_need_drop_time {
643 return Err(ErrorCode::InternalError(
644 "The cursor has exceeded its maximum lifetime, please recreate it (close then declare cursor).".to_owned(),
645 )
646 .into());
647 }
648
649 let session = &handler_args.session;
650 let mut ans = Vec::with_capacity(std::cmp::min(100, count) as usize);
651 let mut cur = 0;
652 if let State::Fetch {
653 from_snapshot,
654 chunk_stream,
655 ..
656 } = &mut self.state
657 {
658 let (fields, fotmats) = self
659 .fields_manager
660 .get_row_stream_fields_and_formats(formats, *from_snapshot);
661 chunk_stream.init_row_stream(&fields, &fotmats, session.clone());
662 }
663 while cur < count {
664 if cancel_handle.is_cancelled() {
665 return Err(SchedulerError::QueryCancelled("Cancelled by user".to_owned()).into());
666 }
667 let fetch_cursor_timer = Instant::now();
668 let row = self.next_row(&handler_args, formats).await?;
669 self.cursor_metrics
670 .subscription_cursor_fetch_duration
671 .with_label_values(&[&self.subscription.name])
672 .observe(fetch_cursor_timer.elapsed().as_millis() as _);
673 match row {
674 Some(row) => {
675 cur += 1;
676 ans.push(row);
677 }
678 None => {
679 let timeout_seconds = timeout_seconds.unwrap_or(0);
680 if cur > 0 || timeout_seconds == 0 {
681 break;
682 }
683 let State::InitLogStoreQuery { seek_timestamp, .. } = &self.state else {
684 continue;
686 };
687 cancel_handle.register(session);
692 let timeout = tokio::time::sleep(Duration::from_secs(timeout_seconds));
693 tokio::pin!(timeout);
694 tokio::select! {
695 biased;
696 _ = cancel_handle.cancelled() => {
697 return Err(SchedulerError::QueryCancelled(
698 "Cancelled by user".to_owned(),
699 )
700 .into());
701 }
702 result = session
703 .env
704 .hummock_snapshot_manager()
705 .wait_table_change_log_notification(
706 self.dependent_table_id,
707 *seek_timestamp,
708 ) => {
709 result?;
710 }
711 _ = &mut timeout => {
712 tracing::debug!("Cursor wait next epoch timeout");
713 break;
714 }
715 }
716 if cancel_handle.is_cancelled() {
717 return Err(
718 SchedulerError::QueryCancelled("Cancelled by user".to_owned()).into(),
719 );
720 }
721 }
722 }
723 if let Some(timeout_instant) = timeout_instant
725 && Instant::now() > timeout_instant
726 {
727 break;
728 }
729 }
730 self.last_fetch = Instant::now();
731 let (rows, seek_pk_row) = self.fields_manager.process_output_desc_row(ans);
732 if let Some(seek_pk_row) = seek_pk_row {
733 self.seek_pk_row = Some(seek_pk_row);
734 }
735 let desc = self
736 .fields_manager
737 .get_output_fields()
738 .iter()
739 .map(to_pg_field)
740 .collect();
741
742 Ok((rows, desc))
743 }
744
745 async fn get_next_rw_timestamp(
746 seek_timestamp: u64,
747 table_id: TableId,
748 expected_timestamp: Option<u64>,
749 handler_args: HandlerArgs,
750 dependent_subscription: &SubscriptionCatalog,
751 ) -> Result<(Option<u64>, Option<u64>)> {
752 let session = handler_args.session;
753 session.get_subscription_by_schema_id_name(
755 dependent_subscription.schema_id,
756 &dependent_subscription.name,
757 )?;
758
759 let Some(new_epochs) = session
761 .list_change_log_epochs(table_id, seek_timestamp, 2)
762 .await?
763 else {
764 return Ok((None, None));
765 };
766 if let Some(expected_timestamp) = expected_timestamp
767 && (new_epochs.is_empty() || &expected_timestamp != new_epochs.first().unwrap())
768 {
769 return Err(ErrorCode::CatalogError(
770 format!(
771 " No data found for rw_timestamp {:?}, data may have been recycled, please recreate cursor",
772 convert_logstore_u64_to_unix_millis(expected_timestamp)
773 )
774 .into(),
775 )
776 .into());
777 }
778 Ok((new_epochs.get(0).cloned(), new_epochs.get(1).cloned()))
779 }
780
781 pub fn gen_batch_plan_result(
782 &self,
783 handler_args: HandlerArgs,
784 ) -> Result<RwBatchQueryPlanResult> {
785 match self.state {
786 State::InitLogStoreQuery { .. } => Self::init_batch_plan_for_subscription_cursor(
788 Some(0),
789 self.dependent_table_id,
790 handler_args,
791 self.seek_pk_row.clone(),
792 ),
793 State::Fetch {
794 from_snapshot,
795 rw_timestamp,
796 ..
797 } => {
798 if from_snapshot {
799 Self::init_batch_plan_for_subscription_cursor(
800 None,
801 self.dependent_table_id,
802 handler_args,
803 self.seek_pk_row.clone(),
804 )
805 } else {
806 Self::init_batch_plan_for_subscription_cursor(
807 Some(rw_timestamp),
808 self.dependent_table_id,
809 handler_args,
810 self.seek_pk_row.clone(),
811 )
812 }
813 }
814 State::Invalid => Err(ErrorCode::InternalError(
815 "Cursor is in invalid state. Please close and re-create the cursor.".to_owned(),
816 )
817 .into()),
818 }
819 }
820
821 fn init_batch_plan_for_subscription_cursor(
822 rw_timestamp: Option<u64>,
823 dependent_table_id: TableId,
824 handler_args: HandlerArgs,
825 seek_pk_row: Option<Row>,
826 ) -> Result<RwBatchQueryPlanResult> {
827 let session = handler_args.clone().session;
828 let table_catalog = session.get_table_by_id(dependent_table_id)?;
829 let context = OptimizerContext::from_handler_args(handler_args);
830 let version_id = {
831 let version = session.env.hummock_snapshot_manager.acquire();
832 let version = version.version();
833 if !version
834 .state_table_info
835 .info()
836 .contains_key(&dependent_table_id)
837 {
838 return Err(anyhow!("table id {dependent_table_id} has been dropped").into());
839 }
840 version.id
841 };
842 Self::create_batch_plan_for_cursor(
843 table_catalog,
844 &session,
845 context.into(),
846 rw_timestamp.map(|rw_timestamp| (rw_timestamp, rw_timestamp)),
847 version_id,
848 seek_pk_row,
849 )
850 }
851
852 async fn initiate_query(
853 rw_timestamp: Option<u64>,
854 dependent_table_id: TableId,
855 handler_args: HandlerArgs,
856 seek_pk_row: Option<Row>,
857 ) -> Result<(CursorDataChunkStream, Instant, Arc<TableCatalog>)> {
858 let init_query_timer = Instant::now();
859 let session = handler_args.clone().session;
860 let table_catalog = session.get_table_by_id(dependent_table_id)?;
861 let plan_result = Self::init_batch_plan_for_subscription_cursor(
862 rw_timestamp,
863 dependent_table_id,
864 handler_args.clone(),
865 seek_pk_row,
866 )?;
867 let plan_fragmenter_result = gen_batch_plan_fragmenter(&handler_args.session, plan_result)?;
868 let (chunk_stream, _) =
869 create_chunk_stream_for_cursor(handler_args.session, plan_fragmenter_result).await?;
870 Ok((chunk_stream, init_query_timer, table_catalog))
871 }
872
873 async fn try_refill_remaining_rows(
874 chunk_stream: &mut CursorDataChunkStream,
875 remaining_rows: &mut VecDeque<Row>,
876 ) -> Result<()> {
877 if remaining_rows.is_empty()
878 && let Some(row_set) = chunk_stream.next().await?
879 {
880 remaining_rows.extend(row_set?);
881 }
882 Ok(())
883 }
884
885 pub fn build_row(
886 mut row: Vec<Option<Bytes>>,
887 rw_timestamp: Option<u64>,
888 formats: &Vec<Format>,
889 session_data: &StaticSessionData,
890 ) -> Result<Row> {
891 let row_len = row.len();
892 let new_row = if let Some(rw_timestamp) = rw_timestamp {
893 let rw_timestamp_formats = formats.get(row_len).unwrap_or(&Format::Text);
894 let rw_timestamp = convert_logstore_u64_to_unix_millis(rw_timestamp);
895 let rw_timestamp = pg_value_format(
896 &DataType::Int64,
897 risingwave_common::types::ScalarRefImpl::Int64(rw_timestamp as i64),
898 *rw_timestamp_formats,
899 session_data,
900 )?;
901 vec![Some(rw_timestamp)]
902 } else {
903 let op_formats = formats.get(row_len).unwrap_or(&Format::Text);
904 let op = pg_value_format(
905 &DataType::Varchar,
906 risingwave_common::types::ScalarRefImpl::Utf8("Insert"),
907 *op_formats,
908 session_data,
909 )?;
910 vec![Some(op), None]
911 };
912 row.extend(new_row);
913 Ok(Row::new(row))
914 }
915
916 pub fn build_desc(mut descs: Vec<Field>, from_snapshot: bool) -> Vec<Field> {
917 if from_snapshot {
918 descs.push(Field::with_name(DataType::Varchar, "op"));
919 }
920 descs.push(Field::with_name(DataType::Int64, "rw_timestamp"));
921 descs
922 }
923
924 pub fn create_batch_plan_for_cursor(
925 table_catalog: Arc<TableCatalog>,
926 session: &SessionImpl,
927 context: OptimizerContextRef,
928 epoch_range: Option<(u64, u64)>,
929 version_id: HummockVersionId,
930 seek_pk_rows: Option<Row>,
931 ) -> Result<RwBatchQueryPlanResult> {
932 let output_col_idx = table_catalog
934 .columns
935 .iter()
936 .enumerate()
937 .filter_map(|(index, v)| {
938 if !v.is_hidden || table_catalog.pk.iter().any(|pk| pk.column_index == index) {
939 Some(index)
940 } else {
941 None
942 }
943 })
944 .collect::<Vec<_>>();
945 let max_split_range_gap = context.session_ctx().config().max_split_range_gap() as u64;
946 let pks = table_catalog.pk();
947 let pks = pks
948 .iter()
949 .map(|f| {
950 let pk = table_catalog.columns.get(f.column_index).unwrap();
951 (pk.data_type(), f.column_index)
952 })
953 .collect_vec();
954 let (scan, predicate) = if let Some(seek_pk_rows) = seek_pk_rows {
955 let mut pk_rows = vec![];
956 let mut values = vec![];
957 for (seek_pk, (data_type, column_index)) in
958 seek_pk_rows.take().into_iter().zip_eq_fast(pks.into_iter())
959 {
960 if let Some(seek_pk) = seek_pk {
961 pk_rows.push(InputRef {
962 index: column_index,
963 data_type: data_type.clone(),
964 });
965 let value_string = String::from_utf8(seek_pk.clone().into()).unwrap();
966 let value_data = ScalarImpl::from_text(&value_string, data_type).unwrap();
967 values.push((Some(value_data), data_type.clone()));
968 }
969 }
970 if pk_rows.is_empty() {
971 (None, None)
972 } else {
973 let (right_data, right_types): (Vec<_>, Vec<_>) = values.into_iter().unzip();
974 let right_data = ScalarImpl::Struct(StructValue::new(right_data));
975 let right_type = DataType::Struct(StructType::row_expr_type(right_types));
976 let left = FunctionCall::new_unchecked(
977 ExprType::Row,
978 pk_rows.into_iter().map(|pk| pk.into()).collect(),
979 right_type.clone(),
980 );
981 let right = Literal::new(Some(right_data), right_type);
982 let (scan, predicate) = Condition {
983 conjunctions: vec![
984 FunctionCall::new(ExprType::GreaterThan, vec![left.into(), right.into()])?
985 .into(),
986 ],
987 }
988 .split_to_scan_ranges(&table_catalog, max_split_range_gap)?;
989 if scan.len() > 1 {
990 return Err(ErrorCode::InternalError(
991 "Seek pk row should only generate one scan range".to_owned(),
992 )
993 .into());
994 }
995 (scan.first().cloned(), Some(predicate))
996 }
997 } else {
998 (None, None)
999 };
1000
1001 let (seq_scan, out_fields, out_names) = if let Some(epoch_range) = epoch_range {
1002 let core = generic::LogScan::new(
1003 table_catalog.name.clone(),
1004 output_col_idx,
1005 table_catalog.clone(),
1006 context,
1007 epoch_range,
1008 version_id,
1009 );
1010 let batch_log_seq_scan = BatchLogSeqScan::new(core, scan);
1011 let out_fields = batch_log_seq_scan.core().out_fields();
1012 let out_names = batch_log_seq_scan.core().column_names();
1013 (batch_log_seq_scan.into(), out_fields, out_names)
1014 } else {
1015 let core = generic::TableScan::new(
1016 output_col_idx,
1017 table_catalog.clone(),
1018 vec![],
1019 vec![],
1020 context,
1021 Condition {
1022 conjunctions: vec![],
1023 },
1024 None,
1025 );
1026 let scans = match scan {
1027 Some(scan) => vec![scan],
1028 None => vec![],
1029 };
1030 let table_scan = BatchSeqScan::new(core, scans, None);
1031 let out_fields = table_scan.core().out_fields();
1032 let out_names = table_scan.core().column_names();
1033 (table_scan.into(), out_fields, out_names)
1034 };
1035
1036 let plan = if let Some(predicate) = predicate
1037 && !predicate.always_true()
1038 {
1039 BatchFilter::new(generic::Filter::new(predicate, seq_scan)).into()
1040 } else {
1041 seq_scan
1042 };
1043
1044 let order = Order::new(table_catalog.pk().to_vec());
1046
1047 let plan_root = PlanRoot::new_with_batch_plan(
1049 plan,
1050 RequiredDist::single(),
1051 order,
1052 out_fields,
1053 out_names,
1054 );
1055 let schema = plan_root.schema();
1056 let (batch_log_seq_scan, query_mode) = match session.config().query_mode() {
1057 QueryMode::Auto | QueryMode::Local => {
1058 (plan_root.gen_batch_local_plan()?, QueryMode::Local)
1059 }
1060 QueryMode::Distributed => (
1061 plan_root.gen_batch_distributed_plan()?,
1062 QueryMode::Distributed,
1063 ),
1064 };
1065 Ok(RwBatchQueryPlanResult {
1066 plan: batch_log_seq_scan,
1067 query_mode,
1068 schema,
1069 stmt_type: StatementType::SELECT,
1070 dependent_relations: vec![],
1071 dependent_secrets: vec![],
1072 })
1073 }
1074
1075 pub fn idle_duration(&self) -> Duration {
1076 self.last_fetch.elapsed()
1077 }
1078
1079 pub fn subscription_name(&self) -> &str {
1080 self.subscription.name.as_str()
1081 }
1082
1083 pub fn state_info_string(&self) -> String {
1084 format!("{}", self.state)
1085 }
1086}
1087
1088pub struct CursorManager {
1089 cursor_map: tokio::sync::Mutex<HashMap<String, Cursor>>,
1090 cursor_metrics: Arc<CursorMetrics>,
1091}
1092
1093impl CursorManager {
1094 pub fn new(cursor_metrics: Arc<CursorMetrics>) -> Self {
1095 Self {
1096 cursor_map: tokio::sync::Mutex::new(HashMap::new()),
1097 cursor_metrics,
1098 }
1099 }
1100
1101 pub async fn add_subscription_cursor(
1102 &self,
1103 cursor_name: String,
1104 start_timestamp: Option<u64>,
1105 dependent_table_id: TableId,
1106 subscription: Arc<SubscriptionCatalog>,
1107 handler_args: &HandlerArgs,
1108 ) -> Result<()> {
1109 let create_cursor_timer = Instant::now();
1110 let subscription_name = subscription.name.clone();
1111 let cursor = SubscriptionCursor::new(
1112 cursor_name,
1113 start_timestamp,
1114 subscription,
1115 dependent_table_id,
1116 handler_args,
1117 self.cursor_metrics.clone(),
1118 )
1119 .await?;
1120 let mut cursor_map = self.cursor_map.lock().await;
1121 self.cursor_metrics
1122 .subscription_cursor_declare_duration
1123 .with_label_values(&[&subscription_name])
1124 .observe(create_cursor_timer.elapsed().as_millis() as _);
1125
1126 cursor_map.retain(|_, v| {
1127 if let Cursor::Subscription(cursor) = v
1128 && matches!(cursor.state, State::Invalid)
1129 {
1130 false
1131 } else {
1132 true
1133 }
1134 });
1135
1136 cursor_map
1137 .try_insert(cursor.cursor_name.clone(), Cursor::Subscription(cursor))
1138 .map_err(|error| {
1139 ErrorCode::CatalogError(
1140 format!("cursor `{}` already exists", error.entry.key()).into(),
1141 )
1142 })?;
1143 Ok(())
1144 }
1145
1146 pub async fn add_query_cursor(
1147 &self,
1148 cursor_name: String,
1149 chunk_stream: CursorDataChunkStream,
1150 fields: Vec<Field>,
1151 ) -> Result<()> {
1152 let cursor = QueryCursor::new(chunk_stream, fields)?;
1153 self.cursor_map
1154 .lock()
1155 .await
1156 .try_insert(cursor_name, Cursor::Query(cursor))
1157 .map_err(|error| {
1158 ErrorCode::CatalogError(
1159 format!("cursor `{}` already exists", error.entry.key()).into(),
1160 )
1161 })?;
1162
1163 Ok(())
1164 }
1165
1166 pub async fn remove_cursor(&self, cursor_name: &str) -> Result<()> {
1167 self.cursor_map
1168 .lock()
1169 .await
1170 .remove(cursor_name)
1171 .ok_or_else(|| {
1172 ErrorCode::CatalogError(format!("cursor `{}` don't exists", cursor_name).into())
1173 })?;
1174 Ok(())
1175 }
1176
1177 pub async fn remove_all_cursor(&self) {
1178 self.cursor_map.lock().await.clear();
1179 }
1180
1181 pub async fn remove_all_query_cursor(&self) {
1182 self.cursor_map
1183 .lock()
1184 .await
1185 .retain(|_, v| matches!(v, Cursor::Subscription(_)));
1186 }
1187
1188 pub async fn get_rows_with_cursor(
1189 &self,
1190 cursor_name: &str,
1191 count: u32,
1192 handler_args: HandlerArgs,
1193 formats: &Vec<Format>,
1194 timeout_seconds: Option<u64>,
1195 cancel_handle: &mut FetchCursorCancelHandle,
1196 ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
1197 if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1198 cursor
1199 .next(count, handler_args, formats, timeout_seconds, cancel_handle)
1200 .await
1201 } else {
1202 Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1203 }
1204 }
1205
1206 pub async fn get_fields_with_cursor(&self, cursor_name: &str) -> Result<Vec<Field>> {
1207 if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1208 Ok(cursor.get_fields())
1209 } else {
1210 Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1211 }
1212 }
1213
1214 pub async fn get_periodic_cursor_metrics(&self) -> PeriodicCursorMetrics {
1215 let mut subscription_cursor_nums = 0;
1216 let mut invalid_subscription_cursor_nums = 0;
1217 let mut subscription_cursor_last_fetch_duration = HashMap::new();
1218 for cursor in self.cursor_map.lock().await.values() {
1219 if let Cursor::Subscription(subscription_cursor) = cursor {
1220 subscription_cursor_nums += 1;
1221 if matches!(subscription_cursor.state, State::Invalid) {
1222 invalid_subscription_cursor_nums += 1;
1223 } else {
1224 let fetch_duration =
1225 subscription_cursor.last_fetch.elapsed().as_millis() as f64;
1226 subscription_cursor_last_fetch_duration.insert(
1227 subscription_cursor.subscription.name.clone(),
1228 fetch_duration,
1229 );
1230 }
1231 }
1232 }
1233 PeriodicCursorMetrics {
1234 subscription_cursor_nums,
1235 invalid_subscription_cursor_nums,
1236 subscription_cursor_last_fetch_duration,
1237 }
1238 }
1239
1240 pub async fn iter_query_cursors(&self, mut f: impl FnMut(&String, &QueryCursor)) {
1241 self.cursor_map
1242 .lock()
1243 .await
1244 .iter()
1245 .for_each(|(cursor_name, cursor)| {
1246 if let Cursor::Query(cursor) = cursor {
1247 f(cursor_name, cursor)
1248 }
1249 });
1250 }
1251
1252 pub async fn iter_subscription_cursors(&self, mut f: impl FnMut(&String, &SubscriptionCursor)) {
1253 self.cursor_map
1254 .lock()
1255 .await
1256 .iter()
1257 .for_each(|(cursor_name, cursor)| {
1258 if let Cursor::Subscription(cursor) = cursor {
1259 f(cursor_name, cursor)
1260 }
1261 });
1262 }
1263
1264 pub async fn gen_batch_plan_with_subscription_cursor(
1265 &self,
1266 cursor_name: &str,
1267 handler_args: HandlerArgs,
1268 ) -> Result<RwBatchQueryPlanResult> {
1269 match self.cursor_map.lock().await.get(cursor_name).ok_or_else(|| {
1270 ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name))
1271 })? {
1272 Cursor::Subscription(cursor) => {
1273 cursor.gen_batch_plan_result(handler_args.clone())
1274 },
1275 Cursor::Query(_) => Err(ErrorCode::InternalError("The plan of the cursor is the same as the query statement of the as when it was created.".to_owned()).into()),
1276 }
1277 }
1278}