Skip to main content

reifydb_rql/
nodes.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use std::{collections, fmt, time};
5
6use reifydb_catalog::catalog::{
7	ringbuffer::RingBufferColumnToCreate, series::SeriesColumnToCreate, subscription::SubscriptionColumnToCreate,
8	table::TableColumnToCreate, view::ViewColumnToCreate,
9};
10use reifydb_core::{
11	common::{JoinType, WindowSize, WindowSlide, WindowType},
12	interface::{
13		catalog::{
14			id::{NamespaceId, RingBufferId, SeriesId, TableId, ViewId},
15			namespace::NamespaceDef,
16			procedure::{ProcedureParamDef, ProcedureTrigger},
17			property::ColumnPropertyKind,
18			series::TimestampPrecision,
19		},
20		resolved::{
21			ResolvedColumn, ResolvedDictionary, ResolvedNamespace, ResolvedPrimitive, ResolvedRingBuffer,
22			ResolvedSequence, ResolvedSeries, ResolvedTable, ResolvedTableVirtual, ResolvedView,
23		},
24	},
25	sort::{SortDirection, SortKey},
26};
27use reifydb_type::{
28	fragment::Fragment,
29	value::{constraint::TypeConstraint, dictionary::DictionaryId, sumtype::SumTypeId, r#type::Type},
30};
31
32use crate::{
33	expression::{AliasExpression, Expression, VariableExpression},
34	query::QueryPlan,
35};
36
37/// Owned primary key definition for physical plan nodes (materialized from bump-allocated logical plan)
38#[derive(Debug, Clone)]
39pub struct PrimaryKeyDef {
40	pub columns: Vec<PrimaryKeyColumn>,
41}
42
43/// Owned primary key column for physical plan nodes
44#[derive(Debug, Clone)]
45pub struct PrimaryKeyColumn {
46	pub column: Fragment,
47	pub order: Option<SortDirection>,
48}
49
50#[derive(Debug, Clone)]
51pub enum PhysicalPlan {
52	CreateDeferredView(CreateDeferredViewNode),
53	CreateTransactionalView(CreateTransactionalViewNode),
54	CreateNamespace(CreateNamespaceNode),
55	CreateTable(CreateTableNode),
56	CreateRingBuffer(CreateRingBufferNode),
57	CreateDictionary(CreateDictionaryNode),
58	CreateSumType(CreateSumTypeNode),
59	CreateSubscription(CreateSubscriptionNode),
60	CreatePrimaryKey(CreatePrimaryKeyNode),
61	CreateColumnProperty(CreateColumnPropertyNode),
62	CreateProcedure(CreateProcedureNode),
63	CreateSeries(CreateSeriesNode),
64	CreateEvent(CreateEventNode),
65	CreateTag(CreateTagNode),
66
67	CreateMigration(CreateMigrationNode),
68	Migrate(MigrateNode),
69	RollbackMigration(RollbackMigrationNode),
70	Dispatch(DispatchNode),
71	// Alter
72	AlterSequence(AlterSequenceNode),
73	AlterTable(AlterTableNode),
74	// Mutate
75	Delete(DeleteTableNode),
76	DeleteRingBuffer(DeleteRingBufferNode),
77	InsertTable(InsertTableNode),
78	InsertRingBuffer(InsertRingBufferNode),
79	InsertDictionary(InsertDictionaryNode),
80	Update(UpdateTableNode),
81	UpdateRingBuffer(UpdateRingBufferNode),
82	UpdateSeries(UpdateSeriesNode),
83	// Variable assignment
84	Declare(DeclareNode),
85	Assign(AssignNode),
86	Append(AppendPhysicalNode),
87	// Variable resolution
88	Variable(VariableNode),
89	Environment(EnvironmentNode),
90	// Control flow
91	Conditional(ConditionalNode),
92	Loop(LoopPhysicalNode),
93	While(WhilePhysicalNode),
94	For(ForPhysicalNode),
95	Break,
96	Continue,
97	// User-defined functions
98	DefineFunction(DefineFunctionNode),
99	Return(ReturnNode),
100	CallFunction(CallFunctionNode),
101
102	// Query
103	Aggregate(AggregateNode),
104	Distinct(DistinctNode),
105	Filter(FilterNode),
106	IndexScan(IndexScanNode),
107	// Row-number optimized access
108	RowPointLookup(RowPointLookupNode),
109	RowListLookup(RowListLookupNode),
110	RowRangeScan(RowRangeScanNode),
111	JoinInner(JoinInnerNode),
112	JoinLeft(JoinLeftNode),
113	JoinNatural(JoinNaturalNode),
114	Take(TakeNode),
115	Sort(SortNode),
116	Map(MapNode),
117	Extend(ExtendNode),
118	Patch(PatchNode),
119	Apply(ApplyNode),
120	InlineData(InlineDataNode),
121	TableScan(TableScanNode),
122	TableVirtualScan(TableVirtualScanNode),
123	ViewScan(ViewScanNode),
124	RingBufferScan(RingBufferScanNode),
125	DictionaryScan(DictionaryScanNode),
126	SeriesScan(SeriesScanNode),
127	// Series DML
128	InsertSeries(InsertSeriesNode),
129	DeleteSeries(DeleteSeriesNode),
130	Generator(GeneratorNode),
131	Window(WindowNode),
132	// Auto-scalarization for 1x1 frames
133	Scalarize(ScalarizeNode),
134	// Auth/Permissions
135	CreateUser(CreateUserNode),
136	CreateRole(CreateRoleNode),
137	Grant(GrantNode),
138	Revoke(RevokeNode),
139	DropUser(DropUserNode),
140	DropRole(DropRoleNode),
141	CreateAuthentication(CreateAuthenticationNode),
142	DropAuthentication(DropAuthenticationNode),
143	CreatePolicy(CreatePolicyNode),
144	AlterPolicy(AlterPolicyNode),
145	DropPolicy(DropPolicyNode),
146}
147
148#[derive(Debug, Clone)]
149pub struct CreateDeferredViewNode {
150	pub namespace: NamespaceDef, // FIXME REsolvedNamespace
151	pub view: Fragment,
152	pub if_not_exists: bool,
153	pub columns: Vec<ViewColumnToCreate>,
154	pub as_clause: Box<QueryPlan>,
155}
156
157#[derive(Debug, Clone)]
158pub struct CreateTransactionalViewNode {
159	pub namespace: NamespaceDef, // FIXME REsolvedNamespace
160	pub view: Fragment,
161	pub if_not_exists: bool,
162	pub columns: Vec<ViewColumnToCreate>,
163	pub as_clause: Box<QueryPlan>,
164}
165
166#[derive(Debug, Clone)]
167pub struct CreateNamespaceNode {
168	pub segments: Vec<Fragment>,
169	pub if_not_exists: bool,
170}
171
172#[derive(Debug, Clone)]
173pub struct CreateTableNode {
174	pub namespace: ResolvedNamespace,
175	pub table: Fragment,
176	pub if_not_exists: bool,
177	pub columns: Vec<TableColumnToCreate>,
178}
179
180#[derive(Debug, Clone)]
181pub struct CreateRingBufferNode {
182	pub namespace: ResolvedNamespace,
183	pub ringbuffer: Fragment,
184	pub if_not_exists: bool,
185	pub columns: Vec<RingBufferColumnToCreate>,
186	pub capacity: u64,
187}
188
189#[derive(Debug, Clone)]
190pub struct CreateDictionaryNode {
191	pub namespace: NamespaceDef,
192	pub dictionary: Fragment,
193	pub if_not_exists: bool,
194	pub value_type: Type,
195	pub id_type: Type,
196}
197
198#[derive(Debug, Clone)]
199pub struct CreateSumTypeNode {
200	pub namespace: NamespaceDef,
201	pub name: Fragment,
202	pub if_not_exists: bool,
203	pub variants: Vec<CreateSumTypeVariant>,
204}
205
206#[derive(Debug, Clone)]
207pub struct CreateSumTypeVariant {
208	pub name: String,
209	pub columns: Vec<CreateSumTypeColumn>,
210}
211
212#[derive(Debug, Clone)]
213pub struct CreateSumTypeColumn {
214	pub name: String,
215	pub column_type: TypeConstraint,
216}
217
218#[derive(Debug, Clone)]
219pub struct CreateSubscriptionNode {
220	pub columns: Vec<SubscriptionColumnToCreate>,
221	pub as_clause: Option<Box<QueryPlan>>,
222}
223
224#[derive(Debug, Clone)]
225pub struct AlterSequenceNode {
226	pub sequence: ResolvedSequence,
227	pub column: ResolvedColumn,
228	pub value: Expression,
229}
230
231#[derive(Debug, Clone)]
232pub struct AlterTableNode {
233	pub namespace: ResolvedNamespace,
234	pub table: Fragment,
235	pub action: AlterTableAction,
236}
237
238#[derive(Debug, Clone)]
239pub enum AlterTableAction {
240	AddColumn {
241		column: TableColumnToCreate,
242	},
243	DropColumn {
244		column: Fragment,
245	},
246	RenameColumn {
247		old_name: Fragment,
248		new_name: Fragment,
249	},
250}
251
252// Create Primary Key node
253#[derive(Debug, Clone)]
254pub struct CreatePrimaryKeyNode {
255	pub namespace: ResolvedNamespace,
256	pub table: Fragment,
257	pub columns: Vec<PrimaryKeyColumn>,
258}
259
260// Create Procedure node
261#[derive(Debug, Clone)]
262pub struct CreateProcedureNode {
263	pub namespace: NamespaceDef,
264	pub name: Fragment,
265	pub params: Vec<ProcedureParamDef>,
266	pub body_source: String,
267	pub trigger: ProcedureTrigger,
268}
269
270/// Physical node for CREATE SERIES
271#[derive(Debug, Clone)]
272pub struct CreateSeriesNode {
273	pub namespace: ResolvedNamespace,
274	pub series: Fragment,
275	pub columns: Vec<SeriesColumnToCreate>,
276	pub tag: Option<SumTypeId>,
277	pub precision: TimestampPrecision,
278}
279
280/// Physical node for CREATE EVENT
281#[derive(Debug, Clone)]
282pub struct CreateEventNode {
283	pub namespace: NamespaceDef,
284	pub name: Fragment,
285	pub variants: Vec<CreateSumTypeVariant>,
286}
287
288/// Physical node for CREATE TAG
289#[derive(Debug, Clone)]
290pub struct CreateTagNode {
291	pub namespace: NamespaceDef,
292	pub name: Fragment,
293	pub variants: Vec<CreateSumTypeVariant>,
294}
295
296/// Physical node for CREATE MIGRATION
297#[derive(Debug, Clone)]
298pub struct CreateMigrationNode {
299	pub name: String,
300	pub body_source: String,
301	pub rollback_body_source: Option<String>,
302}
303
304/// Physical node for MIGRATE
305#[derive(Debug, Clone)]
306pub struct MigrateNode {
307	pub target: Option<String>,
308}
309
310/// Physical node for ROLLBACK MIGRATION
311#[derive(Debug, Clone)]
312pub struct RollbackMigrationNode {
313	pub target: Option<String>,
314}
315
316/// Physical node for DISPATCH
317#[derive(Debug, Clone)]
318pub struct DispatchNode {
319	pub namespace: NamespaceDef,
320	pub on_sumtype_id: SumTypeId,
321	pub variant_name: String,
322	pub fields: Vec<(String, Expression)>,
323}
324
325// Create Policy node
326#[derive(Debug, Clone)]
327pub struct CreateColumnPropertyNode {
328	pub namespace: ResolvedNamespace,
329	pub table: Fragment,
330	pub column: Fragment,
331	pub properties: Vec<ColumnPropertyKind>,
332}
333
334#[derive(Debug, Clone)]
335pub enum LetValue {
336	Expression(Expression),
337	Statement(QueryPlan),
338	EmptyFrame,
339}
340
341impl fmt::Display for LetValue {
342	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343		match self {
344			LetValue::Expression(expr) => write!(f, "{}", expr),
345			LetValue::Statement(query) => write!(f, "Statement({:?})", query),
346			LetValue::EmptyFrame => write!(f, "EmptyFrame"),
347		}
348	}
349}
350
351#[derive(Debug, Clone)]
352pub struct DeclareNode {
353	pub name: Fragment,
354	pub value: LetValue,
355}
356
357#[derive(Debug, Clone)]
358pub enum AssignValue {
359	Expression(Expression),
360	Statement(QueryPlan),
361}
362
363impl fmt::Display for AssignValue {
364	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365		match self {
366			AssignValue::Expression(expr) => write!(f, "{}", expr),
367			AssignValue::Statement(query) => write!(f, "Statement({:?})", query),
368		}
369	}
370}
371
372#[derive(Debug, Clone)]
373pub struct AssignNode {
374	pub name: Fragment,
375	pub value: AssignValue,
376}
377
378#[derive(Debug, Clone)]
379pub struct VariableNode {
380	pub variable_expr: VariableExpression,
381}
382
383#[derive(Debug, Clone)]
384pub struct EnvironmentNode {}
385
386/// A function parameter in the physical plan
387#[derive(Debug, Clone)]
388pub struct FunctionParameter {
389	/// Parameter name (includes $)
390	pub name: Fragment,
391	/// Optional type constraint
392	pub type_constraint: Option<TypeConstraint>,
393}
394
395#[derive(Debug, Clone)]
396pub struct ScalarizeNode {
397	pub input: Box<QueryPlan>,
398	pub fragment: Fragment,
399}
400
401#[derive(Debug, Clone)]
402pub struct AggregateNode {
403	pub input: Box<QueryPlan>,
404	pub by: Vec<Expression>,
405	pub map: Vec<Expression>,
406}
407
408#[derive(Debug, Clone)]
409pub struct DistinctNode {
410	pub input: Box<QueryPlan>,
411	pub columns: Vec<ResolvedColumn>,
412}
413
414#[derive(Debug, Clone)]
415pub struct AssertNode {
416	pub input: Option<Box<QueryPlan>>,
417	pub conditions: Vec<Expression>,
418	pub message: Option<String>,
419}
420
421#[derive(Debug, Clone)]
422pub struct FilterNode {
423	pub input: Box<QueryPlan>,
424	pub conditions: Vec<Expression>,
425}
426
427#[derive(Debug, Clone)]
428pub struct GateNode {
429	pub input: Box<QueryPlan>,
430	pub conditions: Vec<Expression>,
431}
432
433#[derive(Debug, Clone)]
434pub struct DeleteTableNode {
435	pub input: Option<Box<QueryPlan>>,
436	pub target: Option<ResolvedTable>,
437}
438
439#[derive(Debug, Clone)]
440pub struct InsertTableNode {
441	pub input: Box<QueryPlan>,
442	pub target: ResolvedTable,
443}
444
445#[derive(Debug, Clone)]
446pub struct InsertRingBufferNode {
447	pub input: Box<QueryPlan>,
448	pub target: ResolvedRingBuffer,
449}
450
451#[derive(Debug, Clone)]
452pub struct InsertDictionaryNode {
453	pub input: Box<QueryPlan>,
454	pub target: ResolvedDictionary,
455}
456
457#[derive(Debug, Clone)]
458pub struct UpdateTableNode {
459	pub input: Box<QueryPlan>,
460	pub target: Option<ResolvedTable>,
461}
462
463#[derive(Debug, Clone)]
464pub struct DeleteRingBufferNode {
465	pub input: Option<Box<QueryPlan>>,
466	pub target: ResolvedRingBuffer,
467}
468
469#[derive(Debug, Clone)]
470pub struct UpdateRingBufferNode {
471	pub input: Box<QueryPlan>,
472	pub target: ResolvedRingBuffer,
473}
474
475#[derive(Debug, Clone)]
476pub struct UpdateSeriesNode {
477	pub input: Box<QueryPlan>,
478	pub target: ResolvedSeries,
479}
480
481#[derive(Debug, Clone)]
482pub struct JoinInnerNode {
483	pub left: Box<QueryPlan>,
484	pub right: Box<QueryPlan>,
485	pub on: Vec<Expression>,
486	pub alias: Option<Fragment>,
487}
488
489#[derive(Debug, Clone)]
490pub struct JoinLeftNode {
491	pub left: Box<QueryPlan>,
492	pub right: Box<QueryPlan>,
493	pub on: Vec<Expression>,
494	pub alias: Option<Fragment>,
495}
496
497#[derive(Debug, Clone)]
498pub struct JoinNaturalNode {
499	pub left: Box<QueryPlan>,
500	pub right: Box<QueryPlan>,
501	pub join_type: JoinType,
502	pub alias: Option<Fragment>,
503}
504
505#[derive(Debug, Clone)]
506pub struct AppendQueryNode {
507	pub left: Box<QueryPlan>,
508	pub right: Box<QueryPlan>,
509}
510
511#[derive(Debug, Clone)]
512pub struct SortNode {
513	pub input: Box<QueryPlan>,
514	pub by: Vec<SortKey>,
515}
516
517#[derive(Debug, Clone)]
518pub struct MapNode {
519	pub input: Option<Box<QueryPlan>>,
520	pub map: Vec<Expression>,
521}
522
523#[derive(Debug, Clone)]
524pub struct ExtendNode {
525	pub input: Option<Box<QueryPlan>>,
526	pub extend: Vec<Expression>,
527}
528
529#[derive(Debug, Clone)]
530pub struct PatchNode {
531	pub input: Option<Box<QueryPlan>>,
532	pub assignments: Vec<Expression>,
533}
534
535#[derive(Debug, Clone)]
536pub struct ApplyNode {
537	pub input: Option<Box<QueryPlan>>,
538	pub operator: Fragment, // FIXME becomes OperatorIdentifier
539	pub expressions: Vec<Expression>,
540}
541
542#[derive(Debug, Clone)]
543pub struct InlineDataNode {
544	pub rows: Vec<Vec<AliasExpression>>,
545}
546
547#[derive(Debug, Clone)]
548pub struct IndexScanNode {
549	pub source: ResolvedTable,
550	pub index_name: String,
551}
552
553#[derive(Debug, Clone)]
554pub struct TableScanNode {
555	pub source: ResolvedTable,
556}
557
558#[derive(Debug, Clone)]
559pub struct ViewScanNode {
560	pub source: ResolvedView,
561}
562
563#[derive(Debug, Clone)]
564pub struct RingBufferScanNode {
565	pub source: ResolvedRingBuffer,
566}
567
568#[derive(Debug, Clone)]
569pub struct DictionaryScanNode {
570	pub source: ResolvedDictionary,
571}
572
573#[derive(Debug, Clone)]
574pub struct SeriesScanNode {
575	pub source: ResolvedSeries,
576	pub time_range_start: Option<i64>,
577	pub time_range_end: Option<i64>,
578	pub variant_tag: Option<u8>,
579}
580
581#[derive(Debug, Clone)]
582pub struct InsertSeriesNode {
583	pub input: Box<QueryPlan>,
584	pub target: ResolvedSeries,
585}
586
587#[derive(Debug, Clone)]
588pub struct DeleteSeriesNode {
589	pub input: Option<Box<QueryPlan>>,
590	pub target: ResolvedSeries,
591}
592
593#[derive(Debug, Clone)]
594pub struct GeneratorNode {
595	pub name: Fragment,
596	pub expressions: Vec<Expression>,
597}
598
599#[derive(Debug, Clone)]
600pub struct TableVirtualScanNode {
601	pub source: ResolvedTableVirtual,
602	pub pushdown_context: Option<TableVirtualPushdownContext>,
603}
604
605#[derive(Debug, Clone)]
606pub struct TableVirtualPushdownContext {
607	pub filters: Vec<Expression>,
608	pub projections: Vec<Expression>,
609	pub order_by: Vec<SortKey>,
610	pub limit: Option<usize>,
611}
612
613#[derive(Debug, Clone)]
614pub struct TakeNode {
615	pub input: Box<QueryPlan>,
616	pub take: usize,
617}
618
619#[derive(Debug, Clone)]
620pub struct WindowNode {
621	pub input: Option<Box<QueryPlan>>,
622	pub window_type: WindowType,
623	pub size: WindowSize,
624	pub slide: Option<WindowSlide>,
625	pub group_by: Vec<Expression>,
626	pub aggregations: Vec<Expression>,
627	pub min_events: usize,
628	pub max_window_count: Option<usize>,
629	pub max_window_age: Option<time::Duration>,
630}
631
632/// O(1) point lookup by row number: `filter rownum == N`
633#[derive(Debug, Clone)]
634pub struct RowPointLookupNode {
635	/// The source to look up in (table, ring buffer, etc.)
636	pub source: ResolvedPrimitive,
637	/// The row number to fetch
638	pub row_number: u64,
639}
640
641/// O(k) list lookup by row numbers: `filter rownum in [a, b, c]`
642#[derive(Debug, Clone)]
643pub struct RowListLookupNode {
644	/// The source to look up in
645	pub source: ResolvedPrimitive,
646	/// The row numbers to fetch
647	pub row_numbers: Vec<u64>,
648}
649
650/// Range scan by row numbers: `filter rownum between X and Y`
651#[derive(Debug, Clone)]
652pub struct RowRangeScanNode {
653	/// The source to scan
654	pub source: ResolvedPrimitive,
655	/// Start of the range (inclusive)
656	pub start: u64,
657	/// End of the range (inclusive)
658	pub end: u64,
659}
660
661/// APPEND statement physical plan node
662#[derive(Debug, Clone)]
663pub enum AppendPhysicalNode {
664	IntoVariable {
665		target: Fragment,
666		source: AppendPhysicalSource,
667	},
668	Query {
669		left: Box<QueryPlan>,
670		right: Box<QueryPlan>,
671	},
672}
673
674/// Source for an APPEND physical plan
675#[derive(Debug, Clone)]
676pub enum AppendPhysicalSource {
677	Statement(Vec<PhysicalPlan>),
678	Inline(InlineDataNode),
679}
680
681// --- Control flow and function nodes (owned, for PhysicalPlan enum) ---
682
683#[derive(Debug, Clone)]
684pub struct ConditionalNode {
685	pub condition: Expression,
686	pub then_branch: Box<PhysicalPlan>,
687	pub else_ifs: Vec<ElseIfBranch>,
688	pub else_branch: Option<Box<PhysicalPlan>>,
689}
690
691#[derive(Debug, Clone)]
692pub struct ElseIfBranch {
693	pub condition: Expression,
694	pub then_branch: Box<PhysicalPlan>,
695}
696
697#[derive(Debug, Clone)]
698pub struct LoopPhysicalNode {
699	pub body: Vec<PhysicalPlan>,
700}
701
702#[derive(Debug, Clone)]
703pub struct WhilePhysicalNode {
704	pub condition: Expression,
705	pub body: Vec<PhysicalPlan>,
706}
707
708#[derive(Debug, Clone)]
709pub struct ForPhysicalNode {
710	pub variable_name: Fragment,
711	pub iterable: Box<PhysicalPlan>,
712	pub body: Vec<PhysicalPlan>,
713}
714
715#[derive(Debug, Clone)]
716pub struct DefineFunctionNode {
717	pub name: Fragment,
718	pub parameters: Vec<FunctionParameter>,
719	pub return_type: Option<TypeConstraint>,
720	pub body: Vec<PhysicalPlan>,
721}
722
723#[derive(Debug, Clone)]
724pub struct ReturnNode {
725	pub value: Option<Expression>,
726}
727
728#[derive(Debug, Clone)]
729pub struct CallFunctionNode {
730	pub name: Fragment,
731	pub arguments: Vec<Expression>,
732	pub is_procedure_call: bool,
733}
734
735// === Drop nodes ===
736
737#[derive(Debug, Clone)]
738pub struct DropNamespaceNode {
739	pub namespace_name: Fragment,
740	pub namespace_id: Option<NamespaceId>,
741	pub if_exists: bool,
742	pub cascade: bool,
743}
744
745#[derive(Debug, Clone)]
746pub struct DropTableNode {
747	pub namespace_name: Fragment,
748	pub table_name: Fragment,
749	pub table_id: Option<TableId>,
750	pub if_exists: bool,
751	pub cascade: bool,
752}
753
754#[derive(Debug, Clone)]
755pub struct DropViewNode {
756	pub namespace_name: Fragment,
757	pub view_name: Fragment,
758	pub view_id: Option<ViewId>,
759	pub if_exists: bool,
760	pub cascade: bool,
761}
762
763#[derive(Debug, Clone)]
764pub struct DropRingBufferNode {
765	pub namespace_name: Fragment,
766	pub ringbuffer_name: Fragment,
767	pub ringbuffer_id: Option<RingBufferId>,
768	pub if_exists: bool,
769	pub cascade: bool,
770}
771
772#[derive(Debug, Clone)]
773pub struct DropDictionaryNode {
774	pub namespace_name: Fragment,
775	pub dictionary_name: Fragment,
776	pub dictionary_id: Option<DictionaryId>,
777	pub if_exists: bool,
778	pub cascade: bool,
779}
780
781#[derive(Debug, Clone)]
782pub struct DropSumTypeNode {
783	pub namespace_name: Fragment,
784	pub sumtype_name: Fragment,
785	pub sumtype_id: Option<SumTypeId>,
786	pub if_exists: bool,
787	pub cascade: bool,
788}
789
790#[derive(Debug, Clone)]
791pub struct DropSubscriptionNode {
792	pub subscription_name: Fragment,
793	pub if_exists: bool,
794	pub cascade: bool,
795}
796
797#[derive(Debug, Clone)]
798pub struct DropSeriesNode {
799	pub namespace_name: Fragment,
800	pub series_name: Fragment,
801	pub series_id: Option<SeriesId>,
802	pub if_exists: bool,
803	pub cascade: bool,
804}
805
806// === Auth/Permissions physical plan nodes ===
807
808#[derive(Debug, Clone)]
809pub struct CreateUserNode {
810	pub name: Fragment,
811}
812
813#[derive(Debug, Clone)]
814pub struct CreateRoleNode {
815	pub name: Fragment,
816}
817
818#[derive(Debug, Clone)]
819pub struct GrantNode {
820	pub role: Fragment,
821	pub user: Fragment,
822}
823
824#[derive(Debug, Clone)]
825pub struct RevokeNode {
826	pub role: Fragment,
827	pub user: Fragment,
828}
829
830#[derive(Debug, Clone)]
831pub struct DropUserNode {
832	pub name: Fragment,
833	pub if_exists: bool,
834}
835
836#[derive(Debug, Clone)]
837pub struct DropRoleNode {
838	pub name: Fragment,
839	pub if_exists: bool,
840}
841
842#[derive(Debug, Clone)]
843pub struct CreateAuthenticationNode {
844	pub user: Fragment,
845	pub method: Fragment,
846	pub config: collections::HashMap<String, String>,
847}
848
849#[derive(Debug, Clone)]
850pub struct DropAuthenticationNode {
851	pub user: Fragment,
852	pub method: Fragment,
853	pub if_exists: bool,
854}
855
856#[derive(Debug, Clone)]
857pub struct CreatePolicyNode {
858	pub name: Option<Fragment>,
859	pub target_type: String,
860	pub scope_namespace: Option<Fragment>,
861	pub scope_object: Option<Fragment>,
862	pub operations: Vec<PolicyOperationNode>,
863}
864
865#[derive(Debug, Clone)]
866pub struct PolicyOperationNode {
867	pub operation: String,
868	pub body_source: String,
869}
870
871#[derive(Debug, Clone)]
872pub struct AlterPolicyNode {
873	pub target_type: String,
874	pub name: Fragment,
875	pub enable: bool,
876}
877
878#[derive(Debug, Clone)]
879pub struct DropPolicyNode {
880	pub target_type: String,
881	pub name: Fragment,
882	pub if_exists: bool,
883}