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 new_epochs = session
761 .list_change_log_epochs(table_id, seek_timestamp, 2)
762 .await?;
763 if let Some(expected_timestamp) = expected_timestamp
764 && (new_epochs.is_empty() || &expected_timestamp != new_epochs.first().unwrap())
765 {
766 return Err(ErrorCode::CatalogError(
767 format!(
768 " No data found for rw_timestamp {:?}, data may have been recycled, please recreate cursor",
769 convert_logstore_u64_to_unix_millis(expected_timestamp)
770 )
771 .into(),
772 )
773 .into());
774 }
775 Ok((new_epochs.get(0).cloned(), new_epochs.get(1).cloned()))
776 }
777
778 pub fn gen_batch_plan_result(
779 &self,
780 handler_args: HandlerArgs,
781 ) -> Result<RwBatchQueryPlanResult> {
782 match self.state {
783 State::InitLogStoreQuery { .. } => Self::init_batch_plan_for_subscription_cursor(
785 Some(0),
786 self.dependent_table_id,
787 handler_args,
788 self.seek_pk_row.clone(),
789 ),
790 State::Fetch {
791 from_snapshot,
792 rw_timestamp,
793 ..
794 } => {
795 if from_snapshot {
796 Self::init_batch_plan_for_subscription_cursor(
797 None,
798 self.dependent_table_id,
799 handler_args,
800 self.seek_pk_row.clone(),
801 )
802 } else {
803 Self::init_batch_plan_for_subscription_cursor(
804 Some(rw_timestamp),
805 self.dependent_table_id,
806 handler_args,
807 self.seek_pk_row.clone(),
808 )
809 }
810 }
811 State::Invalid => Err(ErrorCode::InternalError(
812 "Cursor is in invalid state. Please close and re-create the cursor.".to_owned(),
813 )
814 .into()),
815 }
816 }
817
818 fn init_batch_plan_for_subscription_cursor(
819 rw_timestamp: Option<u64>,
820 dependent_table_id: TableId,
821 handler_args: HandlerArgs,
822 seek_pk_row: Option<Row>,
823 ) -> Result<RwBatchQueryPlanResult> {
824 let session = handler_args.clone().session;
825 let table_catalog = session.get_table_by_id(dependent_table_id)?;
826 let context = OptimizerContext::from_handler_args(handler_args);
827 let version_id = {
828 let version = session.env.hummock_snapshot_manager.acquire();
829 let version = version.version();
830 if !version
831 .state_table_info
832 .info()
833 .contains_key(&dependent_table_id)
834 {
835 return Err(anyhow!("table id {dependent_table_id} has been dropped").into());
836 }
837 version.id
838 };
839 Self::create_batch_plan_for_cursor(
840 table_catalog,
841 &session,
842 context.into(),
843 rw_timestamp.map(|rw_timestamp| (rw_timestamp, rw_timestamp)),
844 version_id,
845 seek_pk_row,
846 )
847 }
848
849 async fn initiate_query(
850 rw_timestamp: Option<u64>,
851 dependent_table_id: TableId,
852 handler_args: HandlerArgs,
853 seek_pk_row: Option<Row>,
854 ) -> Result<(CursorDataChunkStream, Instant, Arc<TableCatalog>)> {
855 let init_query_timer = Instant::now();
856 let session = handler_args.clone().session;
857 let table_catalog = session.get_table_by_id(dependent_table_id)?;
858 let plan_result = Self::init_batch_plan_for_subscription_cursor(
859 rw_timestamp,
860 dependent_table_id,
861 handler_args.clone(),
862 seek_pk_row,
863 )?;
864 let plan_fragmenter_result = gen_batch_plan_fragmenter(&handler_args.session, plan_result)?;
865 let (chunk_stream, _) =
866 create_chunk_stream_for_cursor(handler_args.session, plan_fragmenter_result).await?;
867 Ok((chunk_stream, init_query_timer, table_catalog))
868 }
869
870 async fn try_refill_remaining_rows(
871 chunk_stream: &mut CursorDataChunkStream,
872 remaining_rows: &mut VecDeque<Row>,
873 ) -> Result<()> {
874 if remaining_rows.is_empty()
875 && let Some(row_set) = chunk_stream.next().await?
876 {
877 remaining_rows.extend(row_set?);
878 }
879 Ok(())
880 }
881
882 pub fn build_row(
883 mut row: Vec<Option<Bytes>>,
884 rw_timestamp: Option<u64>,
885 formats: &Vec<Format>,
886 session_data: &StaticSessionData,
887 ) -> Result<Row> {
888 let row_len = row.len();
889 let new_row = if let Some(rw_timestamp) = rw_timestamp {
890 let rw_timestamp_formats = formats.get(row_len).unwrap_or(&Format::Text);
891 let rw_timestamp = convert_logstore_u64_to_unix_millis(rw_timestamp);
892 let rw_timestamp = pg_value_format(
893 &DataType::Int64,
894 risingwave_common::types::ScalarRefImpl::Int64(rw_timestamp as i64),
895 *rw_timestamp_formats,
896 session_data,
897 )?;
898 vec![Some(rw_timestamp)]
899 } else {
900 let op_formats = formats.get(row_len).unwrap_or(&Format::Text);
901 let op = pg_value_format(
902 &DataType::Varchar,
903 risingwave_common::types::ScalarRefImpl::Utf8("Insert"),
904 *op_formats,
905 session_data,
906 )?;
907 vec![Some(op), None]
908 };
909 row.extend(new_row);
910 Ok(Row::new(row))
911 }
912
913 pub fn build_desc(mut descs: Vec<Field>, from_snapshot: bool) -> Vec<Field> {
914 if from_snapshot {
915 descs.push(Field::with_name(DataType::Varchar, "op"));
916 }
917 descs.push(Field::with_name(DataType::Int64, "rw_timestamp"));
918 descs
919 }
920
921 pub fn create_batch_plan_for_cursor(
922 table_catalog: Arc<TableCatalog>,
923 session: &SessionImpl,
924 context: OptimizerContextRef,
925 epoch_range: Option<(u64, u64)>,
926 version_id: HummockVersionId,
927 seek_pk_rows: Option<Row>,
928 ) -> Result<RwBatchQueryPlanResult> {
929 let output_col_idx = table_catalog
931 .columns
932 .iter()
933 .enumerate()
934 .filter_map(|(index, v)| {
935 if !v.is_hidden || table_catalog.pk.iter().any(|pk| pk.column_index == index) {
936 Some(index)
937 } else {
938 None
939 }
940 })
941 .collect::<Vec<_>>();
942 let max_split_range_gap = context.session_ctx().config().max_split_range_gap() as u64;
943 let pks = table_catalog.pk();
944 let pks = pks
945 .iter()
946 .map(|f| {
947 let pk = table_catalog.columns.get(f.column_index).unwrap();
948 (pk.data_type(), f.column_index)
949 })
950 .collect_vec();
951 let (scan, predicate) = if let Some(seek_pk_rows) = seek_pk_rows {
952 let mut pk_rows = vec![];
953 let mut values = vec![];
954 for (seek_pk, (data_type, column_index)) in
955 seek_pk_rows.take().into_iter().zip_eq_fast(pks.into_iter())
956 {
957 if let Some(seek_pk) = seek_pk {
958 pk_rows.push(InputRef {
959 index: column_index,
960 data_type: data_type.clone(),
961 });
962 let value_string = String::from_utf8(seek_pk.clone().into()).unwrap();
963 let value_data = ScalarImpl::from_text(&value_string, data_type).unwrap();
964 values.push((Some(value_data), data_type.clone()));
965 }
966 }
967 if pk_rows.is_empty() {
968 (None, None)
969 } else {
970 let (right_data, right_types): (Vec<_>, Vec<_>) = values.into_iter().unzip();
971 let right_data = ScalarImpl::Struct(StructValue::new(right_data));
972 let right_type = DataType::Struct(StructType::row_expr_type(right_types));
973 let left = FunctionCall::new_unchecked(
974 ExprType::Row,
975 pk_rows.into_iter().map(|pk| pk.into()).collect(),
976 right_type.clone(),
977 );
978 let right = Literal::new(Some(right_data), right_type);
979 let (scan, predicate) = Condition {
980 conjunctions: vec![
981 FunctionCall::new(ExprType::GreaterThan, vec![left.into(), right.into()])?
982 .into(),
983 ],
984 }
985 .split_to_scan_ranges(&table_catalog, max_split_range_gap)?;
986 if scan.len() > 1 {
987 return Err(ErrorCode::InternalError(
988 "Seek pk row should only generate one scan range".to_owned(),
989 )
990 .into());
991 }
992 (scan.first().cloned(), Some(predicate))
993 }
994 } else {
995 (None, None)
996 };
997
998 let (seq_scan, out_fields, out_names) = if let Some(epoch_range) = epoch_range {
999 let core = generic::LogScan::new(
1000 table_catalog.name.clone(),
1001 output_col_idx,
1002 table_catalog.clone(),
1003 context,
1004 epoch_range,
1005 version_id,
1006 );
1007 let batch_log_seq_scan = BatchLogSeqScan::new(core, scan);
1008 let out_fields = batch_log_seq_scan.core().out_fields();
1009 let out_names = batch_log_seq_scan.core().column_names();
1010 (batch_log_seq_scan.into(), out_fields, out_names)
1011 } else {
1012 let core = generic::TableScan::new(
1013 output_col_idx,
1014 table_catalog.clone(),
1015 vec![],
1016 vec![],
1017 context,
1018 Condition {
1019 conjunctions: vec![],
1020 },
1021 None,
1022 );
1023 let scans = match scan {
1024 Some(scan) => vec![scan],
1025 None => vec![],
1026 };
1027 let table_scan = BatchSeqScan::new(core, scans, None);
1028 let out_fields = table_scan.core().out_fields();
1029 let out_names = table_scan.core().column_names();
1030 (table_scan.into(), out_fields, out_names)
1031 };
1032
1033 let plan = if let Some(predicate) = predicate
1034 && !predicate.always_true()
1035 {
1036 BatchFilter::new(generic::Filter::new(predicate, seq_scan)).into()
1037 } else {
1038 seq_scan
1039 };
1040
1041 let order = Order::new(table_catalog.pk().to_vec());
1043
1044 let plan_root = PlanRoot::new_with_batch_plan(
1046 plan,
1047 RequiredDist::single(),
1048 order,
1049 out_fields,
1050 out_names,
1051 );
1052 let schema = plan_root.schema();
1053 let (batch_log_seq_scan, query_mode) = match session.config().query_mode() {
1054 QueryMode::Auto | QueryMode::Local => {
1055 (plan_root.gen_batch_local_plan()?, QueryMode::Local)
1056 }
1057 QueryMode::Distributed => (
1058 plan_root.gen_batch_distributed_plan()?,
1059 QueryMode::Distributed,
1060 ),
1061 };
1062 Ok(RwBatchQueryPlanResult {
1063 plan: batch_log_seq_scan,
1064 query_mode,
1065 schema,
1066 stmt_type: StatementType::SELECT,
1067 dependent_relations: vec![],
1068 dependent_secrets: vec![],
1069 })
1070 }
1071
1072 pub fn idle_duration(&self) -> Duration {
1073 self.last_fetch.elapsed()
1074 }
1075
1076 pub fn subscription_name(&self) -> &str {
1077 self.subscription.name.as_str()
1078 }
1079
1080 pub fn state_info_string(&self) -> String {
1081 format!("{}", self.state)
1082 }
1083}
1084
1085pub struct CursorManager {
1086 cursor_map: tokio::sync::Mutex<HashMap<String, Cursor>>,
1087 cursor_metrics: Arc<CursorMetrics>,
1088}
1089
1090impl CursorManager {
1091 pub fn new(cursor_metrics: Arc<CursorMetrics>) -> Self {
1092 Self {
1093 cursor_map: tokio::sync::Mutex::new(HashMap::new()),
1094 cursor_metrics,
1095 }
1096 }
1097
1098 pub async fn add_subscription_cursor(
1099 &self,
1100 cursor_name: String,
1101 start_timestamp: Option<u64>,
1102 dependent_table_id: TableId,
1103 subscription: Arc<SubscriptionCatalog>,
1104 handler_args: &HandlerArgs,
1105 ) -> Result<()> {
1106 let create_cursor_timer = Instant::now();
1107 let subscription_name = subscription.name.clone();
1108 let cursor = SubscriptionCursor::new(
1109 cursor_name,
1110 start_timestamp,
1111 subscription,
1112 dependent_table_id,
1113 handler_args,
1114 self.cursor_metrics.clone(),
1115 )
1116 .await?;
1117 let mut cursor_map = self.cursor_map.lock().await;
1118 self.cursor_metrics
1119 .subscription_cursor_declare_duration
1120 .with_label_values(&[&subscription_name])
1121 .observe(create_cursor_timer.elapsed().as_millis() as _);
1122
1123 cursor_map.retain(|_, v| {
1124 if let Cursor::Subscription(cursor) = v
1125 && matches!(cursor.state, State::Invalid)
1126 {
1127 false
1128 } else {
1129 true
1130 }
1131 });
1132
1133 cursor_map
1134 .try_insert(cursor.cursor_name.clone(), Cursor::Subscription(cursor))
1135 .map_err(|error| {
1136 ErrorCode::CatalogError(
1137 format!("cursor `{}` already exists", error.entry.key()).into(),
1138 )
1139 })?;
1140 Ok(())
1141 }
1142
1143 pub async fn add_query_cursor(
1144 &self,
1145 cursor_name: String,
1146 chunk_stream: CursorDataChunkStream,
1147 fields: Vec<Field>,
1148 ) -> Result<()> {
1149 let cursor = QueryCursor::new(chunk_stream, fields)?;
1150 self.cursor_map
1151 .lock()
1152 .await
1153 .try_insert(cursor_name, Cursor::Query(cursor))
1154 .map_err(|error| {
1155 ErrorCode::CatalogError(
1156 format!("cursor `{}` already exists", error.entry.key()).into(),
1157 )
1158 })?;
1159
1160 Ok(())
1161 }
1162
1163 pub async fn remove_cursor(&self, cursor_name: &str) -> Result<()> {
1164 self.cursor_map
1165 .lock()
1166 .await
1167 .remove(cursor_name)
1168 .ok_or_else(|| {
1169 ErrorCode::CatalogError(format!("cursor `{}` don't exists", cursor_name).into())
1170 })?;
1171 Ok(())
1172 }
1173
1174 pub async fn remove_all_cursor(&self) {
1175 self.cursor_map.lock().await.clear();
1176 }
1177
1178 pub async fn remove_all_query_cursor(&self) {
1179 self.cursor_map
1180 .lock()
1181 .await
1182 .retain(|_, v| matches!(v, Cursor::Subscription(_)));
1183 }
1184
1185 pub async fn get_rows_with_cursor(
1186 &self,
1187 cursor_name: &str,
1188 count: u32,
1189 handler_args: HandlerArgs,
1190 formats: &Vec<Format>,
1191 timeout_seconds: Option<u64>,
1192 cancel_handle: &mut FetchCursorCancelHandle,
1193 ) -> Result<(Vec<Row>, Vec<PgFieldDescriptor>)> {
1194 if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1195 cursor
1196 .next(count, handler_args, formats, timeout_seconds, cancel_handle)
1197 .await
1198 } else {
1199 Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1200 }
1201 }
1202
1203 pub async fn get_fields_with_cursor(&self, cursor_name: &str) -> Result<Vec<Field>> {
1204 if let Some(cursor) = self.cursor_map.lock().await.get_mut(cursor_name) {
1205 Ok(cursor.get_fields())
1206 } else {
1207 Err(ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name)).into())
1208 }
1209 }
1210
1211 pub async fn get_periodic_cursor_metrics(&self) -> PeriodicCursorMetrics {
1212 let mut subscription_cursor_nums = 0;
1213 let mut invalid_subscription_cursor_nums = 0;
1214 let mut subscription_cursor_last_fetch_duration = HashMap::new();
1215 for cursor in self.cursor_map.lock().await.values() {
1216 if let Cursor::Subscription(subscription_cursor) = cursor {
1217 subscription_cursor_nums += 1;
1218 if matches!(subscription_cursor.state, State::Invalid) {
1219 invalid_subscription_cursor_nums += 1;
1220 } else {
1221 let fetch_duration =
1222 subscription_cursor.last_fetch.elapsed().as_millis() as f64;
1223 subscription_cursor_last_fetch_duration.insert(
1224 subscription_cursor.subscription.name.clone(),
1225 fetch_duration,
1226 );
1227 }
1228 }
1229 }
1230 PeriodicCursorMetrics {
1231 subscription_cursor_nums,
1232 invalid_subscription_cursor_nums,
1233 subscription_cursor_last_fetch_duration,
1234 }
1235 }
1236
1237 pub async fn iter_query_cursors(&self, mut f: impl FnMut(&String, &QueryCursor)) {
1238 self.cursor_map
1239 .lock()
1240 .await
1241 .iter()
1242 .for_each(|(cursor_name, cursor)| {
1243 if let Cursor::Query(cursor) = cursor {
1244 f(cursor_name, cursor)
1245 }
1246 });
1247 }
1248
1249 pub async fn iter_subscription_cursors(&self, mut f: impl FnMut(&String, &SubscriptionCursor)) {
1250 self.cursor_map
1251 .lock()
1252 .await
1253 .iter()
1254 .for_each(|(cursor_name, cursor)| {
1255 if let Cursor::Subscription(cursor) = cursor {
1256 f(cursor_name, cursor)
1257 }
1258 });
1259 }
1260
1261 pub async fn gen_batch_plan_with_subscription_cursor(
1262 &self,
1263 cursor_name: &str,
1264 handler_args: HandlerArgs,
1265 ) -> Result<RwBatchQueryPlanResult> {
1266 match self.cursor_map.lock().await.get(cursor_name).ok_or_else(|| {
1267 ErrorCode::InternalError(format!("Cannot find cursor `{}`", cursor_name))
1268 })? {
1269 Cursor::Subscription(cursor) => {
1270 cursor.gen_batch_plan_result(handler_args.clone())
1271 },
1272 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()),
1273 }
1274 }
1275}