surrealdb_core/sql/statements/
select.rs

1use crate::ctx::{Context, MutableContext};
2use crate::dbs::{Iterable, Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::idx::planner::{GrantedPermission, QueryPlanner, RecordStrategy, StatementContext};
6use crate::sql::{
7	order::{OldOrders, Order, OrderList, Ordering},
8	Cond, Explain, Fetchs, Field, Fields, Groups, Idioms, Limit, Splits, Start, Timeout, Value,
9	Values, Version, With,
10};
11
12use reblessive::tree::Stk;
13use revision::revisioned;
14use serde::{Deserialize, Serialize};
15use std::fmt;
16use std::sync::Arc;
17
18#[revisioned(revision = 4)]
19#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
20#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
21#[non_exhaustive]
22pub struct SelectStatement {
23	/// The foo,bar part in SELECT foo,bar FROM baz.
24	pub expr: Fields,
25	pub omit: Option<Idioms>,
26	#[revision(start = 2)]
27	pub only: bool,
28	/// The baz part in SELECT foo,bar FROM baz.
29	pub what: Values,
30	pub with: Option<With>,
31	pub cond: Option<Cond>,
32	pub split: Option<Splits>,
33	pub group: Option<Groups>,
34	#[revision(end = 4, convert_fn = "convert_old_orders")]
35	pub old_order: Option<OldOrders>,
36	#[revision(start = 4)]
37	pub order: Option<Ordering>,
38	pub limit: Option<Limit>,
39	pub start: Option<Start>,
40	pub fetch: Option<Fetchs>,
41	pub version: Option<Version>,
42	pub timeout: Option<Timeout>,
43	pub parallel: bool,
44	pub explain: Option<Explain>,
45	#[revision(start = 3)]
46	pub tempfiles: bool,
47}
48
49impl SelectStatement {
50	fn convert_old_orders(
51		&mut self,
52		_rev: u16,
53		old_value: Option<OldOrders>,
54	) -> Result<(), revision::Error> {
55		let Some(x) = old_value else {
56			// nothing to do.
57			return Ok(());
58		};
59
60		if x.0.iter().any(|x| x.random) {
61			self.order = Some(Ordering::Random);
62			return Ok(());
63		}
64
65		let new_ord =
66			x.0.into_iter()
67				.map(|x| Order {
68					value: x.order,
69					collate: x.collate,
70					numeric: x.numeric,
71					direction: x.direction,
72				})
73				.collect();
74
75		self.order = Some(Ordering::Order(OrderList(new_ord)));
76
77		Ok(())
78	}
79
80	/// Check if we require a writeable transaction
81	pub(crate) fn writeable(&self) -> bool {
82		if self.expr.iter().any(|v| match v {
83			Field::All => false,
84			Field::Single {
85				expr,
86				..
87			} => expr.writeable(),
88		}) {
89			return true;
90		}
91		if self.what.iter().any(|v| v.writeable()) {
92			return true;
93		}
94		self.cond.as_deref().is_some_and(Value::writeable)
95	}
96
97	/// Process this type returning a computed simple Value
98	pub(crate) async fn compute(
99		&self,
100		stk: &mut Stk,
101		ctx: &Context,
102		opt: &Options,
103		doc: Option<&CursorDoc>,
104	) -> Result<Value, Error> {
105		// Valid options?
106		opt.valid_for_db()?;
107		// Assign the statement
108		let stm = Statement::from(self);
109		// Create a new iterator
110		let mut i = Iterator::new();
111		// Ensure futures are stored and the version is set if specified
112		let version = match &self.version {
113			Some(v) => Some(v.compute(stk, ctx, opt, doc).await?),
114			_ => None,
115		};
116		let opt = Arc::new(opt.new_with_futures(false).with_version(version));
117		// Extract the limit
118		let limit = i.setup_limit(stk, ctx, &opt, &stm).await?;
119		// Used for ONLY: is the limit 1?
120		let limit_is_one_or_zero = match limit {
121			Some(l) => l <= 1,
122			_ => false,
123		};
124		// Fail for multiple targets without a limit
125		if self.only && !limit_is_one_or_zero && self.what.0.len() > 1 {
126			return Err(Error::SingleOnlyOutput);
127		}
128		// Check if there is a timeout
129		let ctx = match self.timeout.as_ref() {
130			Some(timeout) => {
131				let mut ctx = MutableContext::new(ctx);
132				ctx.add_timeout(*timeout.0)?;
133				ctx.freeze()
134			}
135			None => ctx.clone(),
136		};
137		// Get a query planner
138		let mut planner = QueryPlanner::new();
139		let stm_ctx = StatementContext::new(&ctx, &opt, &stm)?;
140		// Loop over the select targets
141		for w in self.what.0.iter() {
142			let v = w.compute(stk, &ctx, &opt, doc).await?;
143			match v {
144				Value::Thing(v) => {
145					let p = planner.check_table_permission(&stm_ctx, &v.tb).await?;
146					// We prepare it only if wer have a permission
147					if !matches!(p, GrantedPermission::None) {
148						match v.is_range() {
149							true => {
150								// Evaluate if we can only scan keys (rather than keys AND values), or count
151								let rs = stm_ctx.check_record_strategy(false, p).await?;
152								i.prepare_range(&stm, v, rs)?
153							}
154							false => i.prepare_thing(&stm, v)?,
155						}
156					}
157				}
158				Value::Edges(v) => {
159					if self.only && !limit_is_one_or_zero {
160						return Err(Error::SingleOnlyOutput);
161					}
162					i.prepare_edges(&stm, *v)?;
163				}
164				Value::Mock(v) => {
165					if self.only && !limit_is_one_or_zero {
166						return Err(Error::SingleOnlyOutput);
167					}
168					i.prepare_mock(&stm, v)?;
169				}
170				Value::Table(t) => {
171					if self.only && !limit_is_one_or_zero {
172						return Err(Error::SingleOnlyOutput);
173					}
174					let p = planner.check_table_permission(&stm_ctx, &t).await?;
175					// We add the iterable only if we have a permission
176					if !matches!(p, GrantedPermission::None) {
177						planner.add_iterables(stk, &stm_ctx, t, p, &mut i).await?;
178					}
179				}
180				Value::Array(v) => {
181					if self.only && !limit_is_one_or_zero {
182						return Err(Error::SingleOnlyOutput);
183					}
184					for v in v {
185						match v {
186							Value::Table(t) => {
187								let p = planner.check_table_permission(&stm_ctx, &t).await?;
188								// We add the iterable only if we have a permission
189								if !matches!(p, GrantedPermission::None) {
190									planner.add_iterables(stk, &stm_ctx, t, p, &mut i).await?;
191								}
192							}
193							Value::Mock(v) => i.prepare_mock(&stm, v)?,
194							Value::Edges(v) => i.prepare_edges(&stm, *v)?,
195							Value::Thing(v) => {
196								let p = planner.check_table_permission(&stm_ctx, &v.tb).await?;
197								// We prepare it only if wer have a permission
198								if !matches!(p, GrantedPermission::None) {
199									match v.is_range() {
200										true => {
201											// Evaluate if we can only scan keys (rather than keys AND values) or just count
202											let rs =
203												stm_ctx.check_record_strategy(false, p).await?;
204											i.prepare_range(&stm, v, rs)?
205										}
206										false => i.prepare_thing(&stm, v)?,
207									}
208								}
209							}
210							_ => i.ingest(Iterable::Value(v)),
211						}
212					}
213				}
214				v => i.ingest(Iterable::Value(v)),
215			};
216		}
217		// Create a new context
218		let mut ctx = MutableContext::new(&ctx);
219		// Add query executors if any
220		if planner.has_executors() {
221			ctx.set_query_planner(planner);
222		}
223		let ctx = ctx.freeze();
224		// Process the statement
225		let res = i.output(stk, &ctx, &opt, &stm, RecordStrategy::KeysAndValues).await?;
226		// Catch statement timeout
227		if ctx.is_timedout() {
228			return Err(Error::QueryTimedout);
229		}
230		// Output the results
231		match res {
232			// This is a single record result
233			Value::Array(mut a) if self.only => match a.len() {
234				// There were no results
235				0 => Ok(Value::None),
236				// There was exactly one result
237				1 => Ok(a.remove(0)),
238				// There were no results
239				_ => Err(Error::SingleOnlyOutput),
240			},
241			// This is standard query result
242			v => Ok(v),
243		}
244	}
245}
246
247impl fmt::Display for SelectStatement {
248	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249		write!(f, "SELECT {}", self.expr)?;
250		if let Some(ref v) = self.omit {
251			write!(f, " OMIT {v}")?
252		}
253		write!(f, " FROM")?;
254		if self.only {
255			f.write_str(" ONLY")?
256		}
257		write!(f, " {}", self.what)?;
258		if let Some(ref v) = self.with {
259			write!(f, " {v}")?
260		}
261		if let Some(ref v) = self.cond {
262			write!(f, " {v}")?
263		}
264		if let Some(ref v) = self.split {
265			write!(f, " {v}")?
266		}
267		if let Some(ref v) = self.group {
268			write!(f, " {v}")?
269		}
270		if let Some(ref v) = self.order {
271			write!(f, " {v}")?
272		}
273		if let Some(ref v) = self.limit {
274			write!(f, " {v}")?
275		}
276		if let Some(ref v) = self.start {
277			write!(f, " {v}")?
278		}
279		if let Some(ref v) = self.fetch {
280			write!(f, " {v}")?
281		}
282		if let Some(ref v) = self.version {
283			write!(f, " {v}")?
284		}
285		if let Some(ref v) = self.timeout {
286			write!(f, " {v}")?
287		}
288		if self.parallel {
289			f.write_str(" PARALLEL")?
290		}
291		if let Some(ref v) = self.explain {
292			write!(f, " {v}")?
293		}
294		Ok(())
295	}
296}