The ZetaSQL analyzer produces an abstract syntax tree (AST). The nodes of this AST (ResolveAST) are generated by [https://github.com/google/zetasql/blob/master/zetasql/resolved_ast/gen_resolved_ast.py] for both C++ and Java using bazel genrules. This document provides a summary of the nodes and their hierarchy.
The base class ResolvedNode
is defined in
https://github.com/google/zetasql/blob/master/zetasql/resolved_ast/resolved_node.h
The generated classes are specified in https://github.com/google/zetasql/blob/master/zetasql/resolved_ast/gen_resolved_ast.py See that file for comments on specific nodes and fields.
Additional non-generated classes that are documented separately:
The base class ResolvedNode
is defined in
https://github.com/google/zetasql/blob/master/java/com/google/zetasql/resolvedast/ResolvedNode.java
The generated classes are specified in https://github.com/google/zetasql/blob/master/zetasql/resolved_ast/gen_resolved_ast.py See that file for comments on specific nodes and fields.
Additional non-generated classes that are documented separately:
ResolvedNode
ResolvedArgument
ResolvedAggregateHavingModifier
ResolvedAlterAction
ResolvedAddColumnAction
ResolvedAddConstraintAction
ResolvedAddSubEntityAction
ResolvedAddToRestricteeListAction
ResolvedAlterColumnAction
ResolvedAlterColumnDropDefaultAction
ResolvedAlterColumnDropGeneratedAction
ResolvedAlterColumnDropNotNullAction
ResolvedAlterColumnOptionsAction
ResolvedAlterColumnSetDataTypeAction
ResolvedAlterColumnSetDefaultAction
ResolvedAlterSubEntityAction
ResolvedDropColumnAction
ResolvedDropConstraintAction
ResolvedDropPrimaryKeyAction
ResolvedDropSubEntityAction
ResolvedFilterUsingAction
ResolvedGrantToAction
ResolvedRemoveFromRestricteeListAction
ResolvedRenameColumnAction
ResolvedRenameToAction
ResolvedRestrictToAction
ResolvedRevokeFromAction
ResolvedSetAsAction
ResolvedSetCollateClause
ResolvedSetOptionsAction
ResolvedAnalyticFunctionGroup
ResolvedArgumentDef
ResolvedArgumentList
ResolvedAssertRowsModified
ResolvedAuxLoadDataPartitionFilter
ResolvedColumnAnnotations
ResolvedColumnDefaultValue
ResolvedColumnDefinition
ResolvedColumnHolder
ResolvedComputedColumnBase
ResolvedComputedColumnImpl
ResolvedComputedColumn
ResolvedDeferredComputedColumn
ResolvedConnection
ResolvedConstraint
ResolvedCheckConstraint
ResolvedForeignKey
ResolvedPrimaryKey
ResolvedCreateModelAliasedQuery
ResolvedDMLValue
ResolvedDescriptor
ResolvedExecuteImmediateArgument
ResolvedExtendedCast
ResolvedExtendedCastElement
ResolvedFilterFieldArg
ResolvedFunctionArgument
ResolvedFunctionSignatureHolder
ResolvedGeneralizedQuerySubpipeline
ResolvedGeneratedColumnInfo
ResolvedGraphElementIdentifier
ResolvedGraphElementLabel
ResolvedGraphElementProperty
ResolvedGraphElementTable
ResolvedGraphLabelExpr
ResolvedGraphLabel
ResolvedGraphLabelNaryExpr
ResolvedGraphWildCardLabel
ResolvedGraphMakeArrayVariable
ResolvedGraphNodeTableReference
ResolvedGraphPathMode
ResolvedGraphPathPatternQuantifier
ResolvedGraphPathSearchPrefix
ResolvedGraphPropertyDeclaration
ResolvedGraphPropertyDefinition
ResolvedGroupingCall
ResolvedGroupingSetBase
ResolvedCube
ResolvedGroupingSet
ResolvedRollup
ResolvedGroupingSetMultiColumn
ResolvedIdentityColumnInfo
ResolvedIndexItem
ResolvedInlineLambda
ResolvedInsertRow
ResolvedLockMode
ResolvedMakeProtoField
ResolvedMatchRecognizePatternExpr
ResolvedMatchRecognizePatternAnchor
ResolvedMatchRecognizePatternEmpty
ResolvedMatchRecognizePatternOperation
ResolvedMatchRecognizePatternQuantification
ResolvedMatchRecognizePatternVariableRef
ResolvedMatchRecognizeVariableDefinition
ResolvedMeasureGroup
ResolvedMergeWhen
ResolvedModel
ResolvedObjectUnit
ResolvedOnConflictClause
ResolvedOption
ResolvedOrderByItem
ResolvedOutputColumn
ResolvedOutputSchema
ResolvedPipeIfCase
ResolvedPivotColumn
ResolvedPrivilege
ResolvedRecursionDepthModifier
ResolvedReplaceFieldItem
ResolvedReturningClause
ResolvedSequence
ResolvedSetOperationItem
ResolvedSubpipeline
ResolvedTableAndColumnInfo
ResolvedUnnestItem
ResolvedUnpivotArg
ResolvedUpdateArrayItem
ResolvedUpdateItem
ResolvedWindowFrame
ResolvedWindowFrameExpr
ResolvedWindowOrdering
ResolvedWindowPartitioning
ResolvedWithEntry
ResolvedWithPartitionColumns
ResolvedExpr
ResolvedArgumentRef
ResolvedArrayAggregate
ResolvedCast
ResolvedCatalogColumnRef
ResolvedColumnRef
ResolvedConstant
ResolvedDMLDefault
ResolvedExpressionColumn
ResolvedFilterField
ResolvedFlatten
ResolvedFlattenedArg
ResolvedFunctionCallBase
ResolvedFunctionCall
ResolvedNonScalarFunctionCallBase
ResolvedAggregateFunctionCall
ResolvedAnalyticFunctionCall
ResolvedGetJsonField
ResolvedGetProtoField
ResolvedGetProtoOneof
ResolvedGetStructField
ResolvedGraphGetElementProperty
ResolvedGraphIsLabeledPredicate
ResolvedGraphMakeElement
ResolvedLiteral
ResolvedMakeProto
ResolvedMakeStruct
ResolvedParameter
ResolvedReplaceField
ResolvedSubqueryExpr
ResolvedSystemVariable
ResolvedWithExpr
ResolvedScan
ResolvedAggregateScanBase
ResolvedAggregateScan
ResolvedAggregationThresholdAggregateScan
ResolvedAnonymizedAggregateScan
ResolvedDifferentialPrivacyAggregateScan
ResolvedAnalyticScan
ResolvedArrayScan
ResolvedAssertScan
ResolvedBarrierScan
ResolvedExecuteAsRoleScan
ResolvedFilterScan
ResolvedGraphPathScanBase
ResolvedGraphElementScan
ResolvedGraphEdgeScan
ResolvedGraphNodeScan
ResolvedGraphPathScan
ResolvedGraphRefScan
ResolvedGraphScanBase
ResolvedGraphLinearScan
ResolvedGraphScan
ResolvedGraphTableScan
ResolvedGroupRowsScan
ResolvedJoinScan
ResolvedLimitOffsetScan
ResolvedLogScan
ResolvedMatchRecognizeScan
ResolvedOrderByScan
ResolvedPipeExportDataScan
ResolvedPipeForkScan
ResolvedPipeIfScan
ResolvedPivotScan
ResolvedProjectScan
ResolvedRecursiveRefScan
ResolvedRecursiveScan
ResolvedRelationArgumentScan
ResolvedSampleScan
ResolvedSetOperationScan
ResolvedSingleRowScan
ResolvedStaticDescribeScan
ResolvedSubpipelineInputScan
ResolvedTVFScan
ResolvedTableScan
ResolvedUnpivotScan
ResolvedWithRefScan
ResolvedWithScan
ResolvedStatement
ResolvedAbortBatchStmt
ResolvedAlterObjectStmt
ResolvedAlterAllRowAccessPoliciesStmt
ResolvedAlterApproxViewStmt
ResolvedAlterConnectionStmt
ResolvedAlterDatabaseStmt
ResolvedAlterEntityStmt
ResolvedAlterExternalSchemaStmt
ResolvedAlterMaterializedViewStmt
ResolvedAlterModelStmt
ResolvedAlterPrivilegeRestrictionStmt
ResolvedAlterRowAccessPolicyStmt
ResolvedAlterSchemaStmt
ResolvedAlterTableStmt
ResolvedAlterViewStmt
ResolvedAlterTableSetOptionsStmt
ResolvedAnalyzeStmt
ResolvedAssertStmt
ResolvedAssignmentStmt
ResolvedAuxLoadDataStmt
ResolvedBeginStmt
ResolvedCallStmt
ResolvedCloneDataStmt
ResolvedCommitStmt
ResolvedCreateDatabaseStmt
ResolvedCreateRowAccessPolicyStmt
ResolvedCreateStatement
ResolvedCreateConnectionStmt
ResolvedCreateConstantStmt
ResolvedCreateEntityStmt
ResolvedCreateFunctionStmt
ResolvedCreateIndexStmt
ResolvedCreateModelStmt
ResolvedCreatePrivilegeRestrictionStmt
ResolvedCreateProcedureStmt
ResolvedCreatePropertyGraphStmt
ResolvedCreateSchemaStmtBase
ResolvedCreateExternalSchemaStmt
ResolvedCreateSchemaStmt
ResolvedCreateSnapshotTableStmt
ResolvedCreateTableFunctionStmt
ResolvedCreateTableStmtBase
ResolvedCreateExternalTableStmt
ResolvedCreateTableAsSelectStmt
ResolvedCreateTableStmt
ResolvedCreateViewBase
ResolvedCreateApproxViewStmt
ResolvedCreateMaterializedViewStmt
ResolvedCreateViewStmt
ResolvedDefineTableStmt
ResolvedDeleteStmt
ResolvedDescribeStmt
ResolvedDropFunctionStmt
ResolvedDropIndexStmt
ResolvedDropMaterializedViewStmt
ResolvedDropPrivilegeRestrictionStmt
ResolvedDropRowAccessPolicyStmt
ResolvedDropSnapshotTableStmt
ResolvedDropStmt
ResolvedDropTableFunctionStmt
ResolvedExecuteImmediateStmt
ResolvedExplainStmt
ResolvedExportDataStmt
ResolvedExportMetadataStmt
ResolvedExportModelStmt
ResolvedGeneralizedQueryStmt
ResolvedGrantOrRevokeStmt
ResolvedGrantStmt
ResolvedRevokeStmt
ResolvedImportStmt
ResolvedInsertStmt
ResolvedMergeStmt
ResolvedModuleStmt
ResolvedQueryStmt
ResolvedRenameStmt
ResolvedRollbackStmt
ResolvedRunBatchStmt
ResolvedSetTransactionStmt
ResolvedShowStmt
ResolvedStartBatchStmt
ResolvedTruncateStmt
ResolvedUndropStmt
ResolvedUpdateStmt
NOTE: This documentation includes only the public field accessors. It excludes constructors, setters, and boilerplate implementation of virtual methods from the base class.
// Argument nodes are not self-contained nodes in the tree. They exist
// only to describe parameters to another node (e.g. columns in an OrderBy).
// This node is here for organizational purposes only, to cluster these
// argument nodes.
class ResolvedArgument : public ResolvedNode {
};
class ResolvedExpr : public ResolvedNode { bool IsExpression() const final { return true; }
AnnotatedType annotated_type() const { return {type(), type_annotation_map()}; }
const Type* type() const;
const AnnotationMap* type_annotation_map() const; };
// Any literal value, including NULL literals. // There is a special-cased constructor here that gets the type from the // Value. class ResolvedLiteral : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_LITERAL;
const Value& value() const;
// If true, then the literal is explicitly typed and cannot be used // for literal coercions. // // This exists mainly for resolver bookkeeping and should be ignored // by engines. bool has_explicit_type() const;
// Distinct ID of the literal, if it is a floating point value, // within the resolved AST. When coercing from floating point // to NUMERIC, the resolver uses the float_literal_id to find the // original image of the literal to avoid precision loss. An ID of 0 // represents a literal without a cached image. int float_literal_id() const;
// Indicates whether ReplaceLiteralsByParameters() should leave // this literal value in place, rather than replace it with a query // parameter. bool preserve_in_literal_remover() const; };
class ResolvedParameter : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_PARAMETER;
// If non-empty, the name of the parameter. // // A ResolvedParameter will have either a name or a position but not // both. const std::string& name() const;
// If non-zero, the 1-based position of the positional parameter. // // A ResolvedParameter will have either a name or a position but not // both. int position() const;
// If true, then the parameter has no specified type. // // This exists mainly for resolver bookkeeping and should be ignored // by engines. bool is_untyped() const; };
// This represents a column when analyzing a standalone expression. // This is only used when the analyzer was called using AnalyzeExpression. // Expression column names and types come from // AnalyzerOptions::AddExpressionColumn. // <name> will always be in lowercase. class ResolvedExpressionColumn : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_EXPRESSION_COLUMN;
const std::string& name() const; };
// An expression referencing a Column from the Catalog. This is used to // represent a column reference in an expression inside a DDL statement. // The DDL statement will normally define the Table context, and the // referenced Column should be a Column of that Table. class ResolvedCatalogColumnRef : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_CATALOG_COLUMN_REF;
const Column* column() const; };
// An expression referencing the value of some column visible in the // current Scan node. // // If <is_correlated> is false, this must be a column visible in the Scan // containing this expression, either because it was produced inside that // Scan or it is on the <column_list> of some child of this Scan. // // If <is_correlated> is true, this references a column from outside a // subquery that is visible as a correlated column inside. // The column referenced here must show up on the parameters list for the // subquery. See ResolvedSubqueryExpr. class ResolvedColumnRef : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_COLUMN_REF;
const ResolvedColumn& column() const;
bool is_correlated() const; };
// A list of ResolvedColumnRef expression references that will be batched // together in rollup/cube when being expanded to grouping sets. For // example, ROLLUP((a, b), c) will be expanded to 3 grouping sets [(a, b, c), // (a, b), ()], (a, b) is a multi-column. // // Duplicated columns are not allowed in the ResolvedGroupingSetMultiColumn // as they are equivalent to deduplicated columns. column_list must have // at least one element inside. class ResolvedGroupingSetMultiColumn : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GROUPING_SET_MULTI_COLUMN;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& column_list() const; int column_list_size() const; const ResolvedColumnRef* column_list(int i) const; };
// A reference to a named constant. class ResolvedConstant : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_CONSTANT;
// The matching Constant from the Catalog. const Constant* constant() const; };
// A reference to a system variable. class ResolvedSystemVariable : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_SYSTEM_VARIABLE;
// Path to system variable. const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const; };
// A lambda expression, used inline as a function argument. // This represents both the definition of the lambda and the resolution of // its templated signature and body for this function call. // Currently can only be used as an argument of a function. // // <argument_list> defines the argument types and names for the lambda, and // creates new ResolvedColumns which can be used to reference the arguments // inside <body>. // // The return type of the lambda function is the type of <body>. // // In addition to the <argument_list>, the body of a lambda expression can // reference columns visible to the scope of the function call for which this // lambda is provided as an argument. Columns in this scope accessed by the // body are stored in <parameter_list>. // // For example, the following query // SELECT ARRAY_FILTER([1,2,3], e -> e = key) FROM KeyValue; // would have a lambda with <parameter_list> ['key'] and <argument_list> // ['e']. // // <body> is the body expression of the lambda. The expression can only // reference columns in <parameter_list> and <argument_list>. class ResolvedInlineLambda : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_INLINE_LAMBDA;
const std::vector<ResolvedColumn>& argument_list() const; int argument_list_size() const; ResolvedColumn argument_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& parameter_list() const; int parameter_list_size() const; const ResolvedColumnRef* parameter_list(int i) const;
const ResolvedExpr* body() const; };
// Represents a sequence as a function argument class ResolvedSequence : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_SEQUENCE;
const Sequence* sequence() const; };
// An argument to the FILTER_FIELDS() function which specifies a sign to show // inclusion/exclusion status and a field path to include or exclude. class ResolvedFilterFieldArg : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_FILTER_FIELD_ARG;
// True if we want to include this proto path in the resulting proto // (though we may still remove paths below it). // If False, we will remove this path (but may still include paths // below it). bool include() const;
// A vector of FieldDescriptors that denotes the path to a proto // field that will be include or exclude. const std::vector<const google::protobuf::FieldDescriptor*>& field_descriptor_path() const; int field_descriptor_path_size() const; const google::protobuf::FieldDescriptor* field_descriptor_path(int i) const; };
// Represents a call to the FILTER_FIELDS() function. This function can be // used to modify a proto, prune fields and output the resulting proto. The // SQL syntax for this function is // FILTER_FIELDS(<expr>, <filter_field_arg_list>). // // <expr> must have proto type. <filter_field_arg> contains a sign ('+' or // '-') and a field path starting from the proto. // // For example: // FILTER_FIELDS(proto, +field1, -field1.field2) // means the resulting proto only contains field1.* except field1.field2.*. // // Field paths are evaluated and processed in order, // ``` // IF filter_field_arg_list[0].include: // CLEAR all fields // FOR filter_field_arg IN filter_field_arg_list: // IF filter_field_arg.include: // UNCLEAR filter_field_arg.field_descriptor_path (and all children) // ELSE: // CLEAR filter_field_arg.field_descriptor_path (and all children) // ``` // // The order of field_field args have following constraints: // 1. There must be at least one filter_field arg. // 2. Args for ancestor fields must precede descendants. // 3. Each arg must have opposite `include` compared to the last preceding // ancestor field. // // See (broken link) for more detail. class ResolvedFilterField : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_FILTER_FIELD;
// The proto to modify. const ResolvedExpr* expr() const;
// The list of field paths to include or exclude. The path starts // from the proto type of <expr>. const std::vector<std::unique_ptr<const ResolvedFilterFieldArg>>& filter_field_arg_list() const; int filter_field_arg_list_size() const; const ResolvedFilterFieldArg* filter_field_arg_list(int i) const;
// If true, will reset cleared required fields into a // default value. bool reset_cleared_required_fields() const; };
// Common base class for scalar and aggregate function calls. // // <argument_list> contains a list of arguments of type ResolvedExpr. // // <generic_argument_list> contains an alternative list of generic arguments. // This is used for function calls that accept non-expression arguments (i.e. // arguments that aren't part of the type system, like lambdas). // // If all arguments of this function call are ResolvedExprs, <argument_list> // is used. If any of the argument is not a ResolvedExpr, // <generic_argument_list> will be used. Only one of <argument_list> or // <generic_argument_list> can be non-empty. // // <collation_list> (only set when FEATURE_V_1_3_COLLATION_SUPPORT is // enabled) is the operation collation to use. // (broken link) lists the functions affected by // collation, where this can show up. // <collation_list> is a vector for future extension. For now, functions // could have at most one element in the <collation_list>. class ResolvedFunctionCallBase : public ResolvedExpr { typedef ResolvedFunctionCallBaseEnums::ErrorMode ErrorMode; static const ErrorMode DEFAULT_ERROR_MODE = ResolvedFunctionCallBaseEnums::DEFAULT_ERROR_MODE; static const ErrorMode SAFE_ERROR_MODE = ResolvedFunctionCallBaseEnums::SAFE_ERROR_MODE;
// The matching Function from the Catalog. const Function* function() const;
// The concrete FunctionSignature reflecting the matching Function // signature and the function's resolved input <argument_list>. // The function has the mode AGGREGATE iff it is an aggregate // function, in which case this node must be either // ResolvedAggregateFunctionCall or ResolvedAnalyticFunctionCall. const FunctionSignature& signature() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& argument_list() const; int argument_list_size() const; const ResolvedExpr* argument_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedFunctionArgument>>& generic_argument_list() const; int generic_argument_list_size() const; const ResolvedFunctionArgument* generic_argument_list(int i) const;
// If error_mode=SAFE_ERROR_MODE, and if this function call returns a // semantic error (based on input data, not transient server // problems), return NULL instead of an error. This is used for // functions called using SAFE, as in SAFE.FUNCTION(...). ResolvedFunctionCallBase::ErrorMode error_mode() const;
// Function call hints. const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const;
const std::vector<ResolvedCollation>& collation_list() const; int collation_list_size() const; ResolvedCollation collation_list(int i) const; };
// A regular function call. The signature will always have mode SCALAR. // Most scalar expressions show up as FunctionCalls using builtin signatures. class ResolvedFunctionCall : public ResolvedFunctionCallBase { static const ResolvedNodeKind TYPE = RESOLVED_FUNCTION_CALL;
// This contains optional custom information about a particular // function call. // // If some Function subclass requires computing additional // information at resolving time, that extra information can be // stored as a subclass of ResolvedFunctionCallInfo here. // For example, TemplatedSQLFunction stores the resolved template // body here as a TemplatedSQLFunctionCall. // // This field is ignorable because for most types of function calls, // there is no extra information to consider besides the arguments // and other fields from ResolvedFunctionCallBase. const std::shared_ptr<ResolvedFunctionCallInfo>& function_call_info() const; };
// Common base class for analytic and aggregate function calls. class ResolvedNonScalarFunctionCallBase : public ResolvedFunctionCallBase { typedef ResolvedNonScalarFunctionCallBaseEnums::NullHandlingModifier NullHandlingModifier; static const NullHandlingModifier DEFAULT_NULL_HANDLING = ResolvedNonScalarFunctionCallBaseEnums::DEFAULT_NULL_HANDLING; static const NullHandlingModifier IGNORE_NULLS = ResolvedNonScalarFunctionCallBaseEnums::IGNORE_NULLS; static const NullHandlingModifier RESPECT_NULLS = ResolvedNonScalarFunctionCallBaseEnums::RESPECT_NULLS;
// Apply DISTINCT to the stream of input values before calling // function. bool distinct() const;
// Apply IGNORE/RESPECT NULLS filtering to the stream of input // values. ResolvedNonScalarFunctionCallBase::NullHandlingModifier null_handling_modifier() const;
// Holds a table subquery defined in WITH GROUP ROWS(...) that is // evaluated over the input rows of a ResolvedAggregateScan // corresponding to the current group. The function itself is // evaluated over the rows returned from the subquery. // // The subquery should refer to a special TVF GROUP_ROWS(), which // resolves as ResolvedGroupRowsScan. The subquery will be run for // each group produced by ResolvedAggregateScan. // // GROUP_ROWS() produces a row for each source row in the // ResolvedAggregateScan's input that matches current group. // // The subquery cannot reference any ResolvedColumns from the outer // query except what comes in via <with_group_rows_parameter_list>, // and GROUP_ROWS(). // // The subquery can return more than one column, and these columns // can be referenced by the function. // // The subquery can be correlated. In this case the // <with_group_rows_parameter_list> gives the set of ResolvedColumns // from outside the subquery that are used inside. The subuery cannot // refer to correlated columns that are used as aggregation input in // the immediate outer query. The same rules apply to // <with_group_rows_parameter_list> as in ResolvedSubqueryExpr. const ResolvedScan* with_group_rows_subquery() const;
// Correlated parameters to <with_group_rows_subquery> const std::vector<std::unique_ptr<const ResolvedColumnRef>>& with_group_rows_parameter_list() const; int with_group_rows_parameter_list_size() const; const ResolvedColumnRef* with_group_rows_parameter_list(int i) const; };
// An aggregate function call. The signature always has mode AGGREGATE. // // FEATURE_V_1_4_MULTILEVEL_AGGREGATION enables multi-level aggregate // expressions (e.g. 'SUM(AVG(1 + X) GROUP BY key)' ). The GROUP BY modifier // within an aggregate function body indicates the presence of a multi-level // aggregate expression. // // `group_by_aggregate_list` can only be present if `group_by_list` is // present. `group_by_list` and `group_by_aggregate_list` are mutually // exclusive with `having_modifier`. // // If `group_by_list` is empty, then standard column visibility rules apply // (i.e. columns supplied by input scan to the enclosing AggregateScan are // visible to argument expressions and aggregate function modifiers, as are // correlated columns). // // If `group_by_list` is non-empty, the initial aggregation is applied first, // computing the aggregate and grouping columns in `group_by_aggregate_list` // `group_by_list`. Only these computed columns (plus correlated columns) // are visible to argument expressions and aggregate function modifiers // (e.g. DISTINCT, IGNORE / RESPECT NULLS, LIMIT, ORDER BY). These // modifiers are applied on the output rows from the initial aggregation, // as input to the final aggregation. class ResolvedAggregateFunctionCall : public ResolvedNonScalarFunctionCallBase { static const ResolvedNodeKind TYPE = RESOLVED_AGGREGATE_FUNCTION_CALL;
// Apply HAVING MAX/MIN filtering to the stream of input values. const ResolvedAggregateHavingModifier* having_modifier() const;
// Apply ordering to the stream of input values before calling // function. const std::vector<std::unique_ptr<const ResolvedOrderByItem>>& order_by_item_list() const; int order_by_item_list_size() const; const ResolvedOrderByItem* order_by_item_list(int i) const;
const ResolvedExpr* limit() const;
// This contains optional custom information about a particular // function call. Functions may introduce subclasses of this class to // add custom information as needed on a per-function basis. // // This field is ignorable because for most types of function calls, // there is no extra information to consider besides the arguments // and other fields from ResolvedFunctionCallBase. However, for // example, the TemplateSQLFunction in // zetasql/public/templated_sql_function.h defines the // TemplatedSQLFunctionCall subclass which includes the // fully-resolved function body in context of the actual concrete // types of the arguments provided to the function call. const std::shared_ptr<ResolvedFunctionCallInfo>& function_call_info() const;
// Group the stream of input values by columns in this list, and // compute the aggregates defined in
group_by_aggregate_list
. // Used only for multi-level aggregation, when // FEATURE_V_1_4_MULTILEVEL_AGGREGATION is enabled. const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& group_by_list() const; int group_by_list_size() const; const ResolvedComputedColumn* group_by_list(int i) const;
// Aggregate columns to compute over the grouping keys defined in //
group_by_list
. Used only for multi-level aggregation, when // FEATURE_V_1_4_MULTILEVEL_AGGREGATION is enabled. const std::vector<std::unique_ptr<const ResolvedComputedColumnBase>>& group_by_aggregate_list() const; int group_by_aggregate_list_size() const; const ResolvedComputedColumnBase* group_by_aggregate_list(int i) const; };
// An analytic function call. The mode of the function is either AGGREGATE // or ANALYTIC. This node only ever shows up as a function call in a // ResolvedAnalyticFunctionGroup::analytic_function_list. Its associated // window is not under this node but as a sibling of its parent node. // // <window_frame> can be NULL. class ResolvedAnalyticFunctionCall : public ResolvedNonScalarFunctionCallBase { static const ResolvedNodeKind TYPE = RESOLVED_ANALYTIC_FUNCTION_CALL;
const ResolvedWindowFrame* window_frame() const; };
// Describes a leaf extended cast of ResolvedExtendedCast. See the comment // for element_list field of ResolvedExtendedCast for more details. class ResolvedExtendedCastElement : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_EXTENDED_CAST_ELEMENT;
const Type* from_type() const;
const Type* to_type() const;
const Function* function() const; };
// Describes overall cast operation between two values where at least one // value's type is or contains an extended type (e.g. on a struct field). class ResolvedExtendedCast : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_EXTENDED_CAST;
// Stores the list of leaf extended casts required as elements of // this cast. Each element is a cast where at least one of the input // or output is an extended type. For structs or arrays, the elements // will be casts for the field or element types. For structs, there // can be multiple cast elements (one for each distinct pair of field // types). For non-struct types, there will be just a single element. const std::vector<std::unique_ptr<const ResolvedExtendedCastElement>>& element_list() const; int element_list_size() const; const ResolvedExtendedCastElement* element_list(int i) const; };
// A cast expression, casting the result of an input expression to the // target Type. // // Valid casts are defined in the CastHashMap (see cast.cc), which identifies // valid from-Type, to-Type pairs. Consumers can access it through // GetZetaSQLCasts(). class ResolvedCast : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_CAST;
// Helper getter, setter of <type_parameters> field for backward // compatibility. // TODO: We could consider dropping this after we clean up // all references. ABSL_DEPRECATED("use type_modifiers().type_parameters() instead.") const TypeParameters& type_parameters() const { return type_modifiers().type_parameters(); }
ABSL_DEPRECATED("use set_type_modifiers() instead.") void set_type_parameters(const TypeParameters& v);
const ResolvedExpr* expr() const;
// Whether to return NULL if the cast fails. This is set to true for // SAFE_CAST. bool return_null_on_error() const;
// If at least one of types involved in this cast is or contains an // extended (TYPE_EXTENDED) type, this field contains information // necessary to execute this cast. const ResolvedExtendedCast* extended_cast() const;
// The format string specified by the optional FORMAT clause. It is // nullptr when the clause does not exist. const ResolvedExpr* format() const;
// The time zone expression by the optional AT TIME ZONE clause. It // is nullptr when the clause does not exist. const ResolvedExpr* time_zone() const;
// Contains the TypeModifiers object which wraps all modifiers // following the type name in a type string (e.g. type parameters, // collation) in a cast. If there are no type modifiers specified, // this object will be empty. // // Type parameters can be specified inside parentheses following the // type name (e.g. STRING(2)). If specified, the result of the cast // should conform to the type parameters. Engines are expected to // enforce type parameter constraints by erroring out or truncating // the cast result, depending on the output type. See // (broken link) for more details. // // For example: // CAST("ABC" as STRING(2)) should error out // CAST(1234 as NUMERIC(2)) should error out // CAST(1.234 as NUMERIC(2,1)) should return a NumericValue of 1.2 // // Collation can be specified with the COLLATE keyword on a string // type, e.g. STRING COLLATE 'und:ci'. If specified, the // <type_annotation_map> of the ResolvedCast node will have equal // collation annotations. See // (broken link) for more details. // // For example: // CAST("abc" AS STRING COLLATE "und:ci") should return value "abc" // in STRING type with collation "und:ci". // CAST(["abc"] AS ARRAY<STRING COLLATE "und:ci">) should return // the array ["abc"] with collation "und:ci" at the element type. const TypeModifiers& type_modifiers() const; };
// Construct a struct value. <type> is always a StructType. // <field_list> matches 1:1 with the fields in <type> position-wise. // Each field's type will match the corresponding field in <type>. class ResolvedMakeStruct : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_MAKE_STRUCT;
const std::vector<std::unique_ptr<const ResolvedExpr>>& field_list() const; int field_list_size() const; const ResolvedExpr* field_list(int i) const; };
// Construct a proto value. <type> is always a ProtoType. // <field_list> is a vector of (FieldDescriptor, expr) pairs to write. // <field_list> will contain all required fields, and no duplicate fields. class ResolvedMakeProto : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_MAKE_PROTO;
const std::vector<std::unique_ptr<const ResolvedMakeProtoField>>& field_list() const; int field_list_size() const; const ResolvedMakeProtoField* field_list(int i) const; };
// One field assignment in a ResolvedMakeProto expression. // The type of expr will match with the zetasql type of the proto field. // The type will be an array iff the field is repeated. // // For NULL values of <expr>, the proto field should be cleared. // // If any value of <expr> cannot be written into the field, this query // should fail. class ResolvedMakeProtoField : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_MAKE_PROTO_FIELD;
const google::protobuf::FieldDescriptor* field_descriptor() const;
// Provides the Format annotation that should be used when building // this field. The annotation specifies both the ZetaSQL type and // the encoding format for this field. FieldFormat::Format format() const;
const ResolvedExpr* expr() const; };
// Get the field in position <field_idx> (0-based) from <expr>, which has a // STRUCT type. class ResolvedGetStructField : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GET_STRUCT_FIELD;
const ResolvedExpr* expr() const;
int field_idx() const;
// True if using s[OFFSET(0)] syntax rather than // specifying field name, Only for preserving user intent; no // semantic consequences bool field_expr_is_positional() const; };
class ResolvedGetProtoField : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GET_PROTO_FIELD;
const ResolvedExpr* expr() const;
// The proto2 FieldDescriptor to extract. This provides the tag // number and wire type. Additional decoding may be necessary if any // of the other modifiers below are set. Consumers should use those // ZetaSQL-computed modifiers rather than examining field // annotations directly. // // The field is an extension field iff // field_descriptor->is_extension() is true. NOTE: The extended // descriptor's full_name must match the <expr>'s type's full_name, // but may not be the same Descriptor. Extension FieldDescriptors may // come from a different DescriptorPool. // // The field is required if field_descriptor->is_required(). If the // field is required and not present, an error should result. const google::protobuf::FieldDescriptor* field_descriptor() const;
// Default value to use when the proto field is not set. The default // may be NULL (e.g. for proto2 fields with a use_defaults=false // annotation). // // This will not be filled in (the Value will be uninitialized) if // get_has_bit is true, or the field is required. // // If field_descriptor->is_required() and the field is not present, // the engine should return an error. // // If the <expr> itself returns NULL, then extracting a field should // also return NULL, unless <return_default_value_when_unset> is // true. In that case, the default value is returned. // // TODO Make un-ignorable after clients migrate to start // using it. const Value& default_value() const;
// Indicates whether to return a bool indicating if a value was // present, rather than return the value (or NULL). Never set for // repeated fields. This field cannot be set if // <return_default_value_when_unset> is true, and vice versa. // Expression type will be BOOL. bool get_has_bit() const;
// Provides the Format annotation that should be used when reading // this field. The annotation specifies both the ZetaSQL type and // the encoding format for this field. This cannot be set when // get_has_bit is true. FieldFormat::Format format() const;
// Indicates that the default value should be returned if <expr> // (the parent message) is NULL. Note that this does not affect // the return value when the extracted field itself is unset, in // which case the return value depends on the extracted field's // annotations (e.g., use_field_defaults). // // This can only be set for non-message fields. If the field is a // proto2 field, then it must be annotated with // zetasql.use_defaults=true. This cannot be set when <get_has_bit> // is true or the field is required. bool return_default_value_when_unset() const; };
// Get the field <field_name> from <expr>, which has a JSON type. class ResolvedGetJsonField : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GET_JSON_FIELD;
const ResolvedExpr* expr() const;
const std::string& field_name() const; };
// Constructs an initial input ARRAY<T> from expr. For each get_field_list // expr, we evaluate the expression once with each array input element and // use the output as a new array of inputs for the next get_field_list expr. // If the result of a single expr is an array, we add each element from that // array as input to the next step instead of adding the array itself. // // The array elements are evaluated and kept in order. For example, if only // expr is an array, the result will be equivalent to that array having the // get_field_list evaluated on each array element retaining order. class ResolvedFlatten : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_FLATTEN;
const ResolvedExpr* expr() const;
// List of 'get' fields to evaluate in order (0 or more struct get // fields followed by 0 or more proto or json get fields) starting // from expr. Each get is evaluated N times where N is the number of // array elements from the previous get (or expr for the first // expression) generated. // // The 'get' fields may either be a ResolvedGetField or an array // offset function around a ResolvedGetField. const std::vector<std::unique_ptr<const ResolvedExpr>>& get_field_list() const; int get_field_list_size() const; const ResolvedExpr* get_field_list(int i) const; };
// Argument for a child of ResolvedFlatten. This is a placeholder to indicate // that it will be invoked once for each array element from ResolvedFlatten's // expr or previous get_field_list entry. class ResolvedFlattenedArg : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_FLATTENED_ARG;
};
// An argument to the REPLACE_FIELDS() function which specifies a field path // and a value that this field will be set to. The field path to be modified // can be constructed through the <struct_index_path> and <proto_field_path> // fields. These vectors correspond to field paths in a STRUCT and PROTO, // respectively. At least one of these vectors must be non-empty. // // If only <struct_index_path> is non-empty, then the field path only // references top-level and nested struct fields. // // If only <proto_field_path> is non-empty, then the field path only // references top-level and nested message fields. // // If both <struct_index_path> and <proto_field_path> are non-empty, then the // field path should be expanded starting with <struct_index_path>. The last // field in <struct_index_path> will be the proto from which the first field // in <proto_field_path> is extracted. // // <expr> and the field to be modified must be the same type. class ResolvedReplaceFieldItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_REPLACE_FIELD_ITEM;
// The value that the final field in <proto_field_path> will be set // to. // // If <expr> is NULL, the field will be unset. If <proto_field_path> // is a required field, the engine must return an error if it is set // to NULL. const ResolvedExpr* expr() const;
// A vector of integers that denotes the path to a struct field that // will be modified. The integer values in this vector correspond to // field positions (0-based) in a STRUCT. If <proto_field_path> // is also non-empty, then the field corresponding to the last index // in this vector should be of proto type. const std::vector<int>& struct_index_path() const; int struct_index_path_size() const; int struct_index_path(int i) const;
// A vector of FieldDescriptors that denotes the path to a proto // field that will be modified. If <struct_index_path> is also // non-empty, then the first element in this vector should be a // subfield of the proto corresponding to the last element in // <struct_index_path>. const std::vector<const google::protobuf::FieldDescriptor*>& proto_field_path() const; int proto_field_path_size() const; const google::protobuf::FieldDescriptor* proto_field_path(int i) const; };
// Represents a call to the REPLACE_FIELDS() function. This function // can be used to copy a proto or struct, modify a few fields and // output the resulting proto or struct. The SQL syntax for this // function is REPLACE_FIELDS(<expr>, <replace_field_item_list>). // // See (broken link) for more detail. class ResolvedReplaceField : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_REPLACE_FIELD;
// The proto/struct to modify. const ResolvedExpr* expr() const;
// The list of field paths to be modified along with their new // values. // // Engines must check at evaluation time that the modifications in // <replace_field_item_list> obey the following rules // regarding updating protos in ZetaSQL: // - Modifying a subfield of a NULL-valued proto-valued field is an // error. // - Clearing a required field or subfield is an error. const std::vector<std::unique_ptr<const ResolvedReplaceFieldItem>>& replace_field_item_list() const; int replace_field_item_list_size() const; const ResolvedReplaceFieldItem* replace_field_item_list(int i) const; };
// Returns a string value indicating which field of <oneof_descriptor> is // set in the containing proto <expr>. If none of the fields are set, an // empty string is returned. // // See (broken link) for more detail. class ResolvedGetProtoOneof : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GET_PROTO_ONEOF;
const ResolvedExpr* expr() const;
// The google::protobuf::OneofDescriptor for a Oneof contained in <expr>. // This descriptor provides google::protobuf::FieldDescriptors for each of // the fields contained in the Oneof. const google::protobuf::OneofDescriptor* oneof_descriptor() const; };
// A subquery in an expression (not a FROM clause). The subquery runs // in the context of a single input row and produces a single output value. // // Correlated subqueries can be thought of like functions, with a parameter // list. The <parameter_list> gives the set of ResolvedColumns from outside // the subquery that are used inside. // // Inside the subquery, the only allowed references to values outside the // subquery are to the named ColumnRefs listed in <parameter_list>. // Any reference to one of these parameters will be represented as a // ResolvedColumnRef with <is_correlated> set to true. // // These parameters are only visible through one level of expression // subquery. An expression subquery inside an expression has to list // parameters again if parameters from the outer query are passed down // further. (This does not apply for table subqueries inside an expression // subquery. Table subqueries are never indicated in the resolved AST, so // Scan nodes inside an expression query may have come from a nested table // subquery, and they can still reference the expression subquery's // parameters.) // // An empty <parameter_list> means that the subquery is uncorrelated. It is // permissable to run an uncorrelated subquery only once and reuse the result. // TODO Do we want to specify semantics more firmly here? // // The semantics vary based on SubqueryType: // SCALAR // Usage: ( <subquery> ) // If the subquery produces zero rows, the output value is NULL. // If the subquery produces exactly one row, that row is the output value. // If the subquery produces more than one row, raise a runtime error. // // ARRAY // Usage: ARRAY( <subquery> ) // The subquery produces an array value with zero or more rows, with // one array element per subquery row produced. // // EXISTS // Usage: EXISTS( <subquery> ) // The output type is always bool. The result is true if the subquery // produces at least one row, and false otherwise. // // IN // Usage: <in_expr> [NOT] IN ( <subquery> ) // The output type is always bool. The result is true when <in_expr> is // equal to at least one row, and false otherwise. The <subquery> row // contains only one column, and the types of <in_expr> and the // subquery column must exactly match a built-in signature for the // '$equals' comparison function (they must be the same type or one // must be INT64 and the other UINT64). NOT will be expressed as a $not // FunctionCall wrapping this SubqueryExpr. // // LIKE // Usage: <in_expr> [NOT] LIKE ANY|SOME|ALL ( <subquery> ) // The output type is always bool. The result is true when <in_expr> // matches at least one row for LIKE ANY|SOME or matches all rows for // LIKE ALL, and false otherwise. The <subquery> row contains only one // column, and the types of <in_expr> and the subquery column must // exactly match a built-in signature for the relevant '$like_any' or // '$like_all' comparison function (both must be the same type of either // STRING or BYTES). NOT will be expressed as a $not FunctionCall // wrapping this SubqueryExpr. // // The subquery for a SCALAR, ARRAY, IN or LIKE subquery must have exactly // one output column. // The output type for a SCALAR or ARRAY subquery is that column's type or // an array of that column's type. (The subquery scan may include a Project // with a MakeStruct or MakeProto expression to construct a single value // from multiple columns.) class ResolvedSubqueryExpr : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_SUBQUERY_EXPR;
typedef ResolvedSubqueryExprEnums::SubqueryType SubqueryType; static const SubqueryType SCALAR = ResolvedSubqueryExprEnums::SCALAR; static const SubqueryType ARRAY = ResolvedSubqueryExprEnums::ARRAY; static const SubqueryType EXISTS = ResolvedSubqueryExprEnums::EXISTS; static const SubqueryType IN = ResolvedSubqueryExprEnums::IN; static const SubqueryType LIKE_ANY = ResolvedSubqueryExprEnums::LIKE_ANY; static const SubqueryType LIKE_ALL = ResolvedSubqueryExprEnums::LIKE_ALL;
ResolvedSubqueryExpr::SubqueryType subquery_type() const;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& parameter_list() const; int parameter_list_size() const; const ResolvedColumnRef* parameter_list(int i) const;
// Field is only populated for subqueries of type IN or LIKE // ANY|SOME|ALL. const ResolvedExpr* in_expr() const;
// Field is only populated for subqueries of type IN to specify the // operation collation to use to compare <in_expr> with the rows from // <subquery>. const ResolvedCollation& in_collation() const;
const ResolvedScan* subquery() const;
// Note: Hints currently happen only for EXISTS, IN, or a LIKE // expression subquery but not for ARRAY or SCALAR subquery. const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const; };
// ResolvedWithExpr introduces one or more columns in <assignment_list> that // can then be referenced inside <expr>. Each assigned expression is // evaluated once, and each reference to that column in <expr> sees the same // value even if the assigned expression is volatile. Multiple assignment // expressions are independent and cannot reference other columns in the // <assignment_list>. // // <assignment_list> One or more columns that are computed before evaluating // <expr>, and which may be referenced by <expr>. // <expr> Computes the result of the ResolvedWithExpr. May reference columns // from <assignment_list>. class ResolvedWithExpr : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_WITH_EXPR;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& assignment_list() const; int assignment_list_size() const; const ResolvedComputedColumn* assignment_list(int i) const;
const ResolvedExpr* expr() const; };
// Common superclass for all Scans, which are nodes that produce rows // (e.g. scans, joins, table subqueries). A query's FROM clause is // represented as a single Scan that composes all input sources into // a single row stream. // // Each Scan has a `column_list` that says what columns are produced. // The Scan logically produces a stream of output rows, where each row // has exactly these columns. // // Each Scan may have an attached `hint_list`, storing each hint as // a ResolvedOption. // // If `is_ordered` is true, this Scan produces an ordered output, either // by generating order itself (OrderByScan) or by preserving the order // of its single input scan (LimitOffsetScan, ProjectScan, or WithScan). // // Each Scan has a `node_source` field that, if populated, represents where // the scan was from or why it was added. This is used in some cases by the // resolver, rewriters or the random query generator to record why a node was // added. The SQLBuilder may also use `node_source` to influence which query // patterns to generate. class ResolvedScan : public ResolvedNode { bool IsScan() const final { return true; }
const std::vector<ResolvedColumn>& column_list() const; int column_list_size() const; ResolvedColumn column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const;
bool is_ordered() const;
const std::string& node_source() const; };
// This node provides the role context for its subtree. Currently, it only // handles subtrees from inlined TVFs and VIEWs created with DEFINER rights. // Due to the lack of a ROLE catalog object, we are using the original // catalog object (VIEW or TVF) as a proxy. The engine is expected to extract // the target role of these objects. // // In the future, when we have catalog objects for roles, this node should // be updated to attach role object, rather than the original inlined object. // // The node's role context covers the whole subtree underneath it, except // subtrees under other nested ResolvedExecuteAsRoleScan nodes. // // Always creates new output columns in <column_list>, which map 1:1 with // the <input_scan>'s output columns. Most rewriters trace their columns all // the way back to the scan that defined them so this makes this node a // boundary, as desired. class ResolvedExecuteAsRoleScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_EXECUTE_AS_ROLE_SCAN;
// The input scan whose subtree is to be encompassed by the current // role context. const ResolvedScan* input_scan() const;
// The original view that was inlined. If set, then // 'original_inlined_tvf' is null. The validator checks that this // table is indeed a SqlView, not some other subclass of Table. const Table* original_inlined_view() const;
// The original TVF that was inlined. If set, then // 'original_inlined_view' is null. const TableValuedFunction* original_inlined_tvf() const; };
// Represents a machine learning model as a TVF argument. // <model> is the machine learning model object known to the resolver // (usually through the catalog). class ResolvedModel : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_MODEL;
const Model* model() const; };
// Represents a connection object, which encapsulates engine-specific // metadata used to connect to an external data source. class ResolvedConnection : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_CONNECTION;
const Connection* connection() const; };
// Represents a descriptor object as a TVF argument. // A descriptor is basically a list of unresolved column names, written // DESCRIPTOR(column1, column2) // // <descriptor_column_name_list> contains the column names. // // If FunctionArgumentTypeOptions.get_resolve_descriptor_names_table_offset() // is true, then <descriptor_column_list> contains resolved columns from // the sibling ResolvedFunctionArgument of scan type, and will match // positionally with <descriptor_column_name_list>. class ResolvedDescriptor : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_DESCRIPTOR;
const std::vector<ResolvedColumn>& descriptor_column_list() const; int descriptor_column_list_size() const; ResolvedColumn descriptor_column_list(int i) const;
const std::vector<std::string>& descriptor_column_name_list() const; int descriptor_column_name_list_size() const; std::string descriptor_column_name_list(int i) const; };
// Scan that produces a single row with no columns. Used for queries without // a FROM clause, where all output comes from the select list. class ResolvedSingleRowScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_SINGLE_ROW_SCAN;
};
// Scan a Table. // The <column_list>[i] should be matched to a Table column by // <table>.GetColumn(<column_index_list>[i]). // // If AnalyzerOptions::prune_unused_columns is true, the <column_list> and // <column_index_list> will include only columns that were referenced // in the user query. (SELECT * counts as referencing all columns.) // This column_list can then be used for column-level ACL checking on tables. // Pruning has no effect on value tables (the value is never pruned). // // for_system_time_expr when non NULL resolves to TIMESTAMP used in // FOR SYSTEM_TIME AS OF clause. The expression is expected to be constant // and no columns are visible to it. // // <column_index_list> This list matches 1-1 with the <column_list>, and // identifies the ordinal of the corresponding column in the <table>'s // column list. // // If provided, <alias> refers to an explicit alias which was used to // reference a Table in the user query. If the Table was given an implicitly // generated alias, then defaults to "". // // TODO: Enforce <column_index_list> in the constructor arg list. For // historical reasons, some clients match <column_list> to Table columns by // ResolvedColumn name. This violates the ResolvedColumn contract, which // explicitly states that the ResolvedColumn name has no semantic meaning. // All code building a ResolvedTableScan should always // set_column_index_list() immediately after construction. class ResolvedTableScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_TABLE_SCAN;
const Table* table() const;
const ResolvedExpr* for_system_time_expr() const;
const std::vector<int>& column_index_list() const; int column_index_list_size() const; int column_index_list(int i) const;
const std::string& alias() const;
const ResolvedLockMode* lock_mode() const; };
// A Scan that joins two input scans. // The <column_list> will contain columns selected from the union // of the input scan's <column_lists>. // When the join is a LEFT/RIGHT/FULL join, ResolvedColumns that came from // the non-joined side get NULL values. class ResolvedJoinScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_JOIN_SCAN;
typedef ResolvedJoinScanEnums::JoinType JoinType; static const JoinType INNER = ResolvedJoinScanEnums::INNER; static const JoinType LEFT = ResolvedJoinScanEnums::LEFT; static const JoinType RIGHT = ResolvedJoinScanEnums::RIGHT; static const JoinType FULL = ResolvedJoinScanEnums::FULL;
ResolvedJoinScan::JoinType join_type() const;
const ResolvedScan* left_scan() const;
const ResolvedScan* right_scan() const;
const ResolvedExpr* join_expr() const;
// This indicates this join was generated from syntax with USING. // The sql_builder will use this field only as a suggestion. // JOIN USING(...) syntax will be used if and only if //
has_using
is True andjoin_expr
has the correct shape. // Otherwise the sql_builder will generate JOIN ON. bool has_using() const; };
// Scan one or more (N) array values produced by evaluating N expressions, // merging them positionally. Without FEATURE_V_1_4_MULTIWAY_UNNEST, it must // be exactly one array (N=1). // // If `input_scan` is NULL, this produces one row for each array offset. // This can occur when using syntax: // UNNEST(expression [, expression [, ...]]) // // If `input_scan` is non-NULL, for each row in the stream produced by // `input_scan`, this evaluates the expressions in `array_expr_list` (each of // which must return an array type), and then produces a stream with one row // for each array offset. // // If `join_expr` is non-NULL, then this condition is evaluated as an ON // clause for the array join. The named columns produced by any array in // `array_expr_list` may be used inside `join_expr`. // // If the array is empty (after evaluating `join_expr`), then // 1. If `is_outer` is false, the scan produces zero rows. // 2. If `is_outer` is true, the scan produces one row with N NULL values. // // `element_column_list` are the new columns produced by this scan that store // the array element values for each row. `element_column_list` and // `array_expr_list` must have the same size N. // // If present, `array_offset_column` defines the column produced by this // scan that stores the array offset (0-based) for the corresponding // `element_column_list`. // // This node's `column_list` can have columns from `input_scan`, // `element_column_list` and `array_offset_column`. // // `array_zip_mode` specifies the zipping behavior when there are multiple // arrays in `array_expr_list` and they have different sizes. It must be NULL // when there is only one given array. // // The getters and setters for legacy fields `array_expr` and // `element_column` are added for backward compatibility purposes. If the // corresponding vector field has more than 1 element and only legacy // accessors are called, the field is not considered as accessed. class ResolvedArrayScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_ARRAY_SCAN;
const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& array_expr_list() const; int array_expr_list_size() const; const ResolvedExpr* array_expr_list(int i) const;
const std::vector<ResolvedColumn>& element_column_list() const; int element_column_list_size() const; ResolvedColumn element_column_list(int i) const;
const ResolvedColumnHolder* array_offset_column() const;
const ResolvedExpr* join_expr() const;
bool is_outer() const;
// Stores a builtin ENUM ARRAY_ZIP_MODE with three possible values: // PAD, TRUNCATE or STRICT. const ResolvedExpr* array_zip_mode() const; };
// This wrapper is used for an optional ResolvedColumn inside another node. class ResolvedColumnHolder : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_COLUMN_HOLDER;
const ResolvedColumn& column() const; };
// Scan rows from input_scan, and emit all rows where filter_expr // evaluates to true. filter_expr is always of type bool. // This node's column_list will be a subset of input_scan's column_list. class ResolvedFilterScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_FILTER_SCAN;
const ResolvedScan* input_scan() const;
const ResolvedExpr* filter_expr() const; };
// A GROUPING function call. `group_by_column` must be a column from // the `group_by_list` in `ResolvedAggregateScan`. // `output_column` is a new column of type int64. // Its output value is 0 if `group_by_column` is included in the current // grouping set, or 1 if not. class ResolvedGroupingCall : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GROUPING_CALL;
const ResolvedColumnRef* group_by_column() const;
const ResolvedColumn& output_column() const; };
// The parent node for grouping set, rollup and cube nodes.
//
// This node exists for organizational purposes only, to cluster
// grouping set, rollup and cube nodes. It doesn't have any actual fields.
class ResolvedGroupingSetBase : public ResolvedArgument {
};
// List of group by columns that form a grouping set. // // Columns must come from group_by_list in ResolvedAggregateScan. // group_by_column_list will not contain any duplicates. There may be more // than one ResolvedGroupingSet in the ResolvedAggregateScan with the same // columns, however. class ResolvedGroupingSet : public ResolvedGroupingSetBase { static const ResolvedNodeKind TYPE = RESOLVED_GROUPING_SET;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& group_by_column_list() const; int group_by_column_list_size() const; const ResolvedColumnRef* group_by_column_list(int i) const; };
// List of ResolvedGroupingSetMultiColumn that forms a rollup. // // Each ResolvedGroupingSetMultiColumn is a list of column references that // will be batched together when expanding to grouping sets. E.g. // ROLLUP((a, b), c) is expanded to grouping sets [(a, b, c), (a, b), ()]. // Both (a, b) and c are store in ResolvedGroupingSetMultiColumn for // convenience. // // Column references in each ResolvedGroupingSetMultiColumn must come from // group_by_list in ResolvedAggregateScan. It is allowed to have // duplicated ResolvedGroupingSetMultiColumn in rollup_column_list. class ResolvedRollup : public ResolvedGroupingSetBase { static const ResolvedNodeKind TYPE = RESOLVED_ROLLUP;
const std::vector<std::unique_ptr<const ResolvedGroupingSetMultiColumn>>& rollup_column_list() const; int rollup_column_list_size() const; const ResolvedGroupingSetMultiColumn* rollup_column_list(int i) const; };
// List of ResolvedGroupingSetMultiColumn that forms a cube in grouping sets. // // See comments in ResolvdRollup for explanation about // ResolvedGroupingSetMultiColumn. class ResolvedCube : public ResolvedGroupingSetBase { static const ResolvedNodeKind TYPE = RESOLVED_CUBE;
const std::vector<std::unique_ptr<const ResolvedGroupingSetMultiColumn>>& cube_column_list() const; int cube_column_list_size() const; const ResolvedGroupingSetMultiColumn* cube_column_list(int i) const; };
// Base class for aggregation scans. Apply aggregation to rows produced from // input_scan, and output aggregated rows. // // Group by keys in <group_by_list>. If <group_by_list> is empty, // aggregate all input rows into one output row. // // <collation_list> is either empty to indicate that all the elements in // <group_by_list> have the default collation, or <collation_list> has the // same number of elements as <group_by_list>. Each element is the collation // for the element in <group_by_list> with the same index, or can be empty to // indicate default collation or when the type is not collatable. // <collation_list> is only set when FEATURE_V_1_3_COLLATION_SUPPORT is // enabled. // See (broken link). // // Compute all aggregations in <aggregate_list>. All expressions in // <aggregate_list> have a ResolvedAggregateFunctionCall with mode // Function::AGGREGATE as their outermost node. // // The output <column_list> contains only columns produced from // <group_by_list> and <aggregate_list>. No other columns are visible after // aggregation. // // If <grouping_set_list> is empty, output rows grouped by the full // <group_by_list>. // // If <grouping_set_list> is non-empty, then // for each item in <grouping_set_list>, output rows computing the // same <aggregate_list> over the input rows using a particular grouping set. // Each item in <grouping_set_list> is either a ResolvedGroupingSet, // ResolvedRollup, or ResolvedCube before the grouping set rewriter expands // the grouping set list. After rewriting, it will only contain // ResolvedGroupingSet that are expanded from grouping set, rollup and cube. // // The aggregation input values, including <input_scan>, computed columns in // <group_by_list>, and aggregate function arguments in <aggregate_list>, // should be computed just once and then reused as aggregation input for each // grouping set. (This ensures that ROLLUP rows have correct totals, even // with non-stable functions in the input.) For each grouping set, the // <group_by_list> elements not included in the <group_by_column_list> are // replaced with NULL. // // <rollup_column_list> is the original list of columns from // GROUP BY ROLLUP(...), if there was a ROLLUP clause, and is used only for // rebuilding equivalent SQL for the resolved AST. Engines should refer to // <grouping_set_list> rather than <rollup_column_list>. // // <grouping_call_list> is the list of resolved group-by columns referenced // in GROUPING aggregate function calls. Each item in the grouping_call_list // is associated with a unique GROUPING function call in the SELECT list. class ResolvedAggregateScanBase : public ResolvedScan { const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& group_by_list() const; int group_by_list_size() const; const ResolvedComputedColumn* group_by_list(int i) const;
const std::vector<ResolvedCollation>& collation_list() const; int collation_list_size() const; ResolvedCollation collation_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedComputedColumnBase>>& aggregate_list() const; int aggregate_list_size() const; const ResolvedComputedColumnBase* aggregate_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedGroupingSetBase>>& grouping_set_list() const; int grouping_set_list_size() const; const ResolvedGroupingSetBase* grouping_set_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& rollup_column_list() const; int rollup_column_list_size() const; const ResolvedColumnRef* rollup_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedGroupingCall>>& grouping_call_list() const; int grouping_call_list_size() const; const ResolvedGroupingCall* grouping_call_list(int i) const; };
// Apply aggregation to rows produced from input_scan, and output aggregated // rows. class ResolvedAggregateScan : public ResolvedAggregateScanBase { static const ResolvedNodeKind TYPE = RESOLVED_AGGREGATE_SCAN;
};
// Apply differentially private aggregation (anonymization) to rows produced // from input_scan, and output anonymized rows. // Spec: (broken link) // // <k_threshold_expr> when non-null, is a function call that uses one or more // items from the <aggregate_list> as arguments. // The engine then adds a filter that acts like: // HAVING <k_threshold_expr> >= <implementation-defined k-threshold> // omitting any rows that would not pass this condition. // TODO: Update this comment after splitting the rewriter out // into a separate stage. // // <anonymization_option_list> provides user-specified options, and // requires that option names are one of: delta, epsilon, kappa, // max_groups_contributed, max_rows_contributed, or k_threshold. class ResolvedAnonymizedAggregateScan : public ResolvedAggregateScanBase { static const ResolvedNodeKind TYPE = RESOLVED_ANONYMIZED_AGGREGATE_SCAN;
const ResolvedExpr* k_threshold_expr() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& anonymization_option_list() const; int anonymization_option_list_size() const; const ResolvedOption* anonymization_option_list(int i) const; };
// Apply differentially private aggregation (anonymization) to rows produced // from input_scan, and output anonymized rows. // Spec: (broken link) // // // <group_selection_threshold_expr> when non-null, is a function call that // uses one or more items from the <aggregate_list> as arguments. // The engine then adds a filter that acts like: // HAVING <group_selection_threshold_expr> >= // <implementation-defined group_selection_threshold> // omitting any rows that would not pass this condition. // TODO: Update this comment after splitting the rewriter out // into a separate stage. // // <option_list> provides user-specified options, and // requires that option names are one of: delta, epsilon, // max_groups_contributed or max_rows_contributed. class ResolvedDifferentialPrivacyAggregateScan : public ResolvedAggregateScanBase { static const ResolvedNodeKind TYPE = RESOLVED_DIFFERENTIAL_PRIVACY_AGGREGATE_SCAN;
const ResolvedExpr* group_selection_threshold_expr() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// Apply aggregation to rows produced from input_scan and output rows to // that pass aggregation thresholds. It adds: // HAVING COUNT(DISTINCT `privacy_unit_column`) >= `threshold`. // Spec: (broken link) // // <option_list> provides user-specified options. Allowed options are defined // in GetAllowedAggregationThresholdOptions function. class ResolvedAggregationThresholdAggregateScan : public ResolvedAggregateScanBase { static const ResolvedNodeKind TYPE = RESOLVED_AGGREGATION_THRESHOLD_AGGREGATE_SCAN;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This is one input item in a ResolvedSetOperation. // The <output_column_list> matches 1:1 with the ResolvedSetOperation's // <column_list> and specifies how columns from <scan> map to output columns. // Each column from <scan> can map to zero or more output columns. class ResolvedSetOperationItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_SET_OPERATION_ITEM;
const ResolvedScan* scan() const;
const std::vector<ResolvedColumn>& output_column_list() const; int output_column_list_size() const; ResolvedColumn output_column_list(int i) const; };
// Apply a set operation (specified by <op_type>) on two or more input scans. // // <scan_list> will have at least two elements. // // <column_list> is a set of new ResolvedColumns created by this scan. // Each input ResolvedSetOperationItem has an <output_column_list> which // matches 1:1 with <column_list> and specifies how the input <scan>'s // columns map into the final <column_list>. // // - Results of {UNION, INTERSECT, EXCEPT} ALL can include duplicate rows. // More precisely, with two input scans, if a given row R appears exactly // m times in first input and n times in second input (m >= 0, n >= 0): // For UNION ALL, R will appear exactly m + n times in the result. // For INTERSECT ALL, R will appear exactly min(m, n) in the result. // For EXCEPT ALL, R will appear exactly max(m - n, 0) in the result. // // - Results of {UNION, INTERSECT, EXCEPT} DISTINCT cannot contain any // duplicate rows. For UNION and INTERSECT, the DISTINCT is computed // after the result above is computed. For EXCEPT DISTINCT, row R will // appear once in the output if m > 0 and n = 0. // // - For n (>2) input scans, the above operations generalize so the output is // the same as if the inputs were combined incrementally from left to // right. // // <column_match_mode> represents how columns from different queries were // matched, for example BY_POSITION or CORRESPONDING (by name). Engines can // ignore this field; it is included for informational purposes. // // <column_propagation_mode> represents how non-matching columns were // treated, for example INNER (non-matching columns are dropped) or STRICT // (non-matching columns are not allowed). Engines can ignore this field; // it is included for informational purposes. class ResolvedSetOperationScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_SET_OPERATION_SCAN;
typedef ResolvedSetOperationScanEnums::SetOperationType SetOperationType; typedef ResolvedSetOperationScanEnums::SetOperationColumnMatchMode SetOperationColumnMatchMode; typedef ResolvedSetOperationScanEnums::SetOperationColumnPropagationMode SetOperationColumnPropagationMode; static const SetOperationType UNION_ALL = ResolvedSetOperationScanEnums::UNION_ALL; static const SetOperationType UNION_DISTINCT = ResolvedSetOperationScanEnums::UNION_DISTINCT; static const SetOperationType INTERSECT_ALL = ResolvedSetOperationScanEnums::INTERSECT_ALL; static const SetOperationType INTERSECT_DISTINCT = ResolvedSetOperationScanEnums::INTERSECT_DISTINCT; static const SetOperationType EXCEPT_ALL = ResolvedSetOperationScanEnums::EXCEPT_ALL; static const SetOperationType EXCEPT_DISTINCT = ResolvedSetOperationScanEnums::EXCEPT_DISTINCT; static const SetOperationColumnMatchMode BY_POSITION = ResolvedSetOperationScanEnums::BY_POSITION; static const SetOperationColumnMatchMode CORRESPONDING = ResolvedSetOperationScanEnums::CORRESPONDING; static const SetOperationColumnMatchMode CORRESPONDING_BY = ResolvedSetOperationScanEnums::CORRESPONDING_BY; static const SetOperationColumnPropagationMode STRICT = ResolvedSetOperationScanEnums::STRICT; static const SetOperationColumnPropagationMode INNER = ResolvedSetOperationScanEnums::INNER; static const SetOperationColumnPropagationMode LEFT = ResolvedSetOperationScanEnums::LEFT; static const SetOperationColumnPropagationMode FULL = ResolvedSetOperationScanEnums::FULL;
ResolvedSetOperationScan::SetOperationType op_type() const;
const std::vector<std::unique_ptr<const ResolvedSetOperationItem>>& input_item_list() const; int input_item_list_size() const; const ResolvedSetOperationItem* input_item_list(int i) const;
ResolvedSetOperationScan::SetOperationColumnMatchMode column_match_mode() const;
ResolvedSetOperationScan::SetOperationColumnPropagationMode column_propagation_mode() const; };
// Apply ordering to rows produced from input_scan, and output ordered // rows. // // The <order_by_item_list> must not be empty. Each element identifies // a sort column and indicates direction (ascending or descending). // // Order Preservation: // A ResolvedScan produces an ordered output if it has <is_ordered>=true. // If <is_ordered>=false, the scan may discard order. This can happen // even for a ResolvedOrderByScan, if it is the top-level scan in a // subquery (which discards order). // // The following Scan nodes may have <is_ordered>=true, producing or // propagating an ordering: // * ResolvedOrderByScan // * ResolvedLimitOffsetScan // * ResolvedProjectScan // * ResolvedWithScan // Other Scan nodes will always discard ordering. class ResolvedOrderByScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_ORDER_BY_SCAN;
const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedOrderByItem>>& order_by_item_list() const; int order_by_item_list_size() const; const ResolvedOrderByItem* order_by_item_list(int i) const; };
// Apply a LIMIT and optional OFFSET to the rows from input_scan. Emit all // rows after OFFSET rows have been scanned and up to LIMIT total rows // emitted. The offset is the number of rows to skip. // E.g., OFFSET 1 means to skip one row, so the first row emitted will be the // second ROW, provided the LIMIT is greater than zero. // // The arguments to LIMIT <int64> OFFSET <int64> must be non-negative // integer literals or (possibly casted) query parameters. Query // parameter values must be checked at run-time by ZetaSQL compliant // backend systems. // // OFFSET is optional and the absence of OFFSET implies OFFSET 0. class ResolvedLimitOffsetScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_LIMIT_OFFSET_SCAN;
const ResolvedScan* input_scan() const;
const ResolvedExpr* limit() const;
const ResolvedExpr* offset() const; };
// Scan the subquery defined in a WITH statement. // See ResolvedWithScan for more detail. // The column_list produced here will match 1:1 with the column_list produced // by the referenced subquery and will given a new unique id to each column // produced for this scan. class ResolvedWithRefScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_WITH_REF_SCAN;
const std::string& with_query_name() const; };
// Apply analytic functions to rows produced from input_scan. // // The set of analytic functions are partitioned into a list of analytic // function groups <function_group_list> by the window PARTITION BY and the // window ORDER BY. // // The output <column_list> contains all columns from <input_scan>, // one column per analytic function. It may also contain partitioning/ordering // expression columns if they reference to select columns. // // Currently, the analyzer combines equivalent OVER clauses into the same // ResolvedAnalyticFunctionGroup only for OVER () or a named window. class ResolvedAnalyticScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_ANALYTIC_SCAN;
const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedAnalyticFunctionGroup>>& function_group_list() const; int function_group_list_size() const; const ResolvedAnalyticFunctionGroup* function_group_list(int i) const; };
// Samples rows from <input_scan>. // Specs: (broken link) // Specs for WITH WEIGHT and PARTITION BY: (broken link) // // <method> is the identifier for the sampling algorithm and will always be // in lowercase. // For example BERNOULLI, RESERVOIR, SYSTEM. Engines can also support their // own implementation-specific set of sampling algorithms. // // <size> and <unit> specifies the sample size. // If <unit> is "ROWS", <size> must be an <int64> and non-negative. // If <unit> is "PERCENT", <size> must either be a <double> or an <int64> and // in the range [0, 100]. // <size> can only be a literal value or a (possibly casted) parameter. // // <repeatable_argument> is present if we had a REPEATABLE(<argument>) in the // TABLESAMPLE clause and can only be a literal value or a (possibly // casted) parameter. // // If present, <weight_column> defines the column produced by this scan that // stores the scaling weight for the corresponding sampled row. // // <partition_by_list> can be empty. If <partition_by_list> is not empty, // <unit> must be ROWS and <method> must be RESERVOIR. class ResolvedSampleScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_SAMPLE_SCAN;
typedef ResolvedSampleScanEnums::SampleUnit SampleUnit; static const SampleUnit ROWS = ResolvedSampleScanEnums::ROWS; static const SampleUnit PERCENT = ResolvedSampleScanEnums::PERCENT;
const ResolvedScan* input_scan() const;
const std::string& method() const;
const ResolvedExpr* size() const;
ResolvedSampleScan::SampleUnit unit() const;
const ResolvedExpr* repeatable_argument() const;
const ResolvedColumnHolder* weight_column() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const; };
// This is used when an expression is computed and given a name (a new // ResolvedColumn) that can be referenced elsewhere. The new ResolvedColumn // can appear in a column_list or in ResolvedColumnRefs in other expressions, // when appropriate. This node is not an expression itself - it is a // container that holds an expression. // // There are 2 concrete subclasses: ResolvedComputedColumn and // ResolvedDeferredComputedColumn. // // ResolvedDeferredComputedColumn has extra information about deferring // side effects like errors. This can be used in cases like AggregateScans // before conditional expressions like IF(), where errors from the aggregate // function should only be exposed if the right IF branch is chosen. // // Nodes where deferred side effects are not possible (like GROUP BY // expressions) are declared as ResolvedComputedColumn directly. // // Nodes that might need to defer errors, such as AggregateScan's // aggregate_list(), are declared as ResolvedComputedColumnBase. // The runtime type will be either ResolvedComputedColumn or // ResolvedDeferredComputedColumn, depending on whether any side effects need // to be captured. // // If FEATURE_V_1_4_ENFORCE_CONDITIONAL_EVALUATION is not set, the runtime // type is always just ResolvedComputedColumn. // // See (broken link) for more details. class ResolvedComputedColumnBase : public ResolvedArgument { // Virtual getter to avoid changing ResolvedComputedColumnProto virtual const ResolvedColumn& column() const = 0;
// Virtual getter to avoid changing ResolvedComputedColumnProto virtual const ResolvedExpr* expr() const = 0;
};
// An intermediate abstract superclass that holds common getters for
// ResolvedComputedColumn and ResolvedDeferredComputedColumn. This class
// exists to ensure that callers static_cast to the appropriate subclass,
// rather than processing ResolvedComputedColumnBase directly.
class ResolvedComputedColumnImpl : public ResolvedComputedColumnBase {
};
// This is the usual ResolvedComputedColumn without deferred side effects. // See comments on ResolvedComputedColumnBase. class ResolvedComputedColumn : public ResolvedComputedColumnImpl { static const ResolvedNodeKind TYPE = RESOLVED_COMPUTED_COLUMN;
const ResolvedColumn& column() const;
const ResolvedExpr* expr() const; };
// This is a ResolvedColumnColumn variant that adds deferred side effect // capture. // // This is used for computations that get separated into multiple scans, // where side effects like errors in earlier scans need to be deferred // util conditional expressions in later scans are evalauted. // See (broken link) for details. // For example: // SELECT IF(C, SUM(A/B), -1) FROM T // The division A/B could produce an error when B is 0, but errors should not // be exposed when C is false, due to IF's conditional evaluation semantics. // // `side_effect_column` is a new column (of type BYTES) created at the same // time as `column`, storing side effects like errors from the computation. // This column will store an implementation-specific representation of the // side effect (e.g. util::StatusProto) and will get a NULL value if there // are no captured side effects. // // Typically, this column will be passed to a call to the internal function // $with_side_effect() later to expose the side effects. The validator checks // that it is consumed downstream. class ResolvedDeferredComputedColumn : public ResolvedComputedColumnImpl { static const ResolvedNodeKind TYPE = RESOLVED_DEFERRED_COMPUTED_COLUMN;
const ResolvedColumn& column() const;
const ResolvedExpr* expr() const;
// Creates the companion side effects columns for this // computation, of type BYTES. Instead of immediately exposing the // side effect (e.g. an error), the side effect is captured in the // side_effects_column. const ResolvedColumn& side_effect_column() const; };
// This represents one column of an ORDER BY clause, with the requested // ordering direction. // // <collation_name> is the ORDER BY COLLATE expression, and could be a string // literal or query parameter. <collation_name> can only be set when the // FEATURE_V_1_1_ORDER_BY_COLLATE is enabled. // See (broken link) for COLLATE clause. // <collation> (only set when FEATURE_V_1_3_COLLATION_SUPPORT is enabled) is // the derived collation to use. It comes from the <column_ref> and COLLATE // clause. It is unset if COLLATE is present and set to a parameter. // See (broken link) for general Collation Support. // When both features are enabled, if <collation_name> is present and is // - a parameter, then <collation> is empty // - a non-parameter, then <collation> is set to the same collation // An engine which supports both features could read the fields as: // If <collation> is set then use it, otherwise use <collation_name>, which // must be a query parameter if set. // // <null_order> indicates the ordering of NULL values relative to non-NULL // values. NULLS_FIRST indicates that NULLS sort prior to non-NULL values, // and NULLS_LAST indicates that NULLS sort after non-NULL values. class ResolvedOrderByItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ORDER_BY_ITEM;
typedef ResolvedOrderByItemEnums::NullOrderMode NullOrderMode; static const NullOrderMode ORDER_UNSPECIFIED = ResolvedOrderByItemEnums::ORDER_UNSPECIFIED; static const NullOrderMode NULLS_FIRST = ResolvedOrderByItemEnums::NULLS_FIRST; static const NullOrderMode NULLS_LAST = ResolvedOrderByItemEnums::NULLS_LAST;
const ResolvedColumnRef* column_ref() const;
const ResolvedExpr* collation_name() const;
bool is_descending() const;
ResolvedOrderByItem::NullOrderMode null_order() const;
const ResolvedCollation& collation() const; };
// This is used in CREATE TABLE statements to provide column annotations // such as collation, NOT NULL, type parameters, and OPTIONS(). // // This class is recursive. It mirrors the structure of the column type // except that child_list might be truncated. // // For ARRAY: // If the element or its subfield has annotations, then child_list.size() // is 1, and child_list(0) stores the element annotations. // Otherwise child_list is empty. // For STRUCT: // If the i-th field has annotations then child_list(i) stores the // field annotations. // Otherwise either child_list.size() <= i or child_list(i) is trivial. // If none of the fields and none of their subfields has annotations, then // child_list is empty. // For other types, child_list is empty. class ResolvedColumnAnnotations : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_COLUMN_ANNOTATIONS;
// Get the full TypeParameters object for these annotations given a // type, including parameters on nested fields. absl::StatusOr<TypeParameters> GetFullTypeParameters( const Type* type) const;
// <collation_name> can only be a string literal, and is only set // when FEATURE_V_1_3_COLLATION_SUPPORT is enabled. See // (broken link). const ResolvedExpr* collation_name() const;
bool not_null() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnAnnotations>>& child_list() const; int child_list_size() const; const ResolvedColumnAnnotations* child_list(int i) const;
// child_list in <type_parameters> is not used in here. // Instead we use child_list of this node (ResolvedColumnAnnotations) // to store type parameters of subfields of STRUCT or ARRAY. Users // can access the full type parameters with child_list by calling // ResolvedColumnDefinition.getFullTypeParameters() function. const TypeParameters& type_parameters() const; };
// <expression> indicates the expression that defines the column. The type of // the expression will always match the type of the column. // - The <expression> can contain ResolvedColumnRefs corresponding to // ResolvedColumnDefinition.<column> for any of the // ResolvedColumnDefinitions in the enclosing statement. // - The expression can never include a subquery. // // <stored_mode> is the mode of a generated column: Values are: // - 'NON_STORED': The <expression> must always be evaluated at read time. // - 'STORED': The <expression> should be pre-emptively computed at write // time (to save work at read time) and must not call any volatle // function (e.g. RAND). // - 'STORED_VOLATILE': The <expression> must be computed at write time and // may call volatile functions (e.g. RAND). // // `generated_mode` dictates how the generated column is populated. Values // are: // - 'ALWAYS' the generated value is always applied to the column, // meaning users cannot write to the column. // - 'BY_DEFAULT', the generated value is applied to to the column only if // the user does not write to the column. // This field is set to ALWAYS by default. // // `identity_column_info` contains the sequence attributes that dictate how // values are generated for the column. // - Each table can have at most one identity column. // // Note: Exactly one of `expression` and `identity_column_info` must be // populated. // // See (broken link) and // (broken link). class ResolvedGeneratedColumnInfo : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GENERATED_COLUMN_INFO;
typedef ResolvedGeneratedColumnInfoEnums::StoredMode StoredMode; typedef ResolvedGeneratedColumnInfoEnums::GeneratedMode GeneratedMode; static const StoredMode NON_STORED = ResolvedGeneratedColumnInfoEnums::NON_STORED; static const StoredMode STORED = ResolvedGeneratedColumnInfoEnums::STORED; static const StoredMode STORED_VOLATILE = ResolvedGeneratedColumnInfoEnums::STORED_VOLATILE; static const GeneratedMode ALWAYS = ResolvedGeneratedColumnInfoEnums::ALWAYS; static const GeneratedMode BY_DEFAULT = ResolvedGeneratedColumnInfoEnums::BY_DEFAULT;
const ResolvedExpr* expression() const;
ResolvedGeneratedColumnInfo::StoredMode stored_mode() const;
ResolvedGeneratedColumnInfo::GeneratedMode generated_mode() const;
const ResolvedIdentityColumnInfo* identity_column_info() const; };
// <expression> is the default value expression of the column. The type of // the expression must be coercible to the column type. // - <default_value> cannot contain any references to another column. // - <default_value> cannot include a subquery, aggregation, or window // function. // // <sql> is the original SQL string for the default value expression. // // Since we can't enforce engines to access at least one of the fields, we // leave both fields NOT_IGNORABLE to ensure engines access at least one of // them. class ResolvedColumnDefaultValue : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_COLUMN_DEFAULT_VALUE;
const ResolvedExpr* expression() const;
const std::string& sql() const; };
// This is used in CREATE TABLE statements to provide an explicit column // definition. // // if <is_hidden> is TRUE, then the column won't show up in SELECT * queries. // // if <generated_column_info> is non-NULL, then this column is a generated // column. // // if <default_value> is non-NULL, then this column has default value. // // <generated_column_info> and <default_value> cannot both be set at the // same time. // // <column> defines an ID for the column, which may appear in expressions in // the PARTITION BY, CLUSTER BY clause or <generated_column_info> if either // is present. class ResolvedColumnDefinition : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_COLUMN_DEFINITION;
// Get the full TypeParameters object for this column, including // parameters on nested fields. <annotations.type_parameters> includes // only parameters on the outermost type. absl::StatusOr<TypeParameters> GetFullTypeParameters() const;
const std::string& name() const;
const Type* type() const;
const ResolvedColumnAnnotations* annotations() const;
bool is_hidden() const;
const ResolvedColumn& column() const;
const ResolvedGeneratedColumnInfo* generated_column_info() const;
const ResolvedColumnDefaultValue* default_value() const; };
// Intermediate class for resolved constraints.
class ResolvedConstraint : public ResolvedArgument {
};
// This represents the PRIMARY KEY constraint on a table. // <column_offset_list> provides the offsets of the column definitions that // comprise the primary key. This is empty when a // 0-element primary key is defined or when the altered // table does not exist. // <unenforced> specifies whether the constraint is unenforced. // <constraint_name> specifies the constraint name, if present // <column_name_list> provides the column names used in column definitions // that comprise the primary key. class ResolvedPrimaryKey : public ResolvedConstraint { static const ResolvedNodeKind TYPE = RESOLVED_PRIMARY_KEY;
const std::vector<int>& column_offset_list() const; int column_offset_list_size() const; int column_offset_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
bool unenforced() const;
const std::string& constraint_name() const;
const std::vector<std::string>& column_name_list() const; int column_name_list_size() const; std::string column_name_list(int i) const; };
// This represents the FOREIGN KEY constraint on a table. It is of the form: // // CONSTRAINT <constraint_name> // FOREIGN KEY <referencing_column_offset_list> // REFERENCES <referenced_table> <referenced_column_offset_list> // <match_mode> // <update_action> // <delete_action> // <enforced> // <option_list> // // <constraint_name> uniquely identifies the constraint. // // <referencing_column_offset_list> provides the offsets of the column // definitions for the table defining the foreign key. // // <referenced_table> identifies the table this constraint references. // // <referenced_column_offset_list> provides the offsets of the column // definitions for the table referenced by the foreign key. // // <match_mode> specifies how referencing keys with null values are handled. // // <update_action> specifies what action to take, if any, when a referenced // value is updated. // // <delete_action> specifies what action to take, if any, when a row with a // referenced values is deleted. // // <enforced> specifies whether or not the constraint is enforced. // // <option_list> for foreign key table constraints. Empty for foreign key // column attributes (see instead ResolvedColumnAnnotations). // // <referencing_column_list> provides the names for the foreign key's // referencing columns. class ResolvedForeignKey : public ResolvedConstraint { static const ResolvedNodeKind TYPE = RESOLVED_FOREIGN_KEY;
typedef ResolvedForeignKeyEnums::MatchMode MatchMode; typedef ResolvedForeignKeyEnums::ActionOperation ActionOperation; static const MatchMode SIMPLE = ResolvedForeignKeyEnums::SIMPLE; static const MatchMode FULL = ResolvedForeignKeyEnums::FULL; static const MatchMode NOT_DISTINCT = ResolvedForeignKeyEnums::NOT_DISTINCT; static const ActionOperation NO_ACTION = ResolvedForeignKeyEnums::NO_ACTION; static const ActionOperation RESTRICT = ResolvedForeignKeyEnums::RESTRICT; static const ActionOperation CASCADE = ResolvedForeignKeyEnums::CASCADE; static const ActionOperation SET_NULL = ResolvedForeignKeyEnums::SET_NULL;
const std::string& constraint_name() const;
const std::vector<int>& referencing_column_offset_list() const; int referencing_column_offset_list_size() const; int referencing_column_offset_list(int i) const;
const Table* referenced_table() const;
const std::vector<int>& referenced_column_offset_list() const; int referenced_column_offset_list_size() const; int referenced_column_offset_list(int i) const;
ResolvedForeignKey::MatchMode match_mode() const;
ResolvedForeignKey::ActionOperation update_action() const;
ResolvedForeignKey::ActionOperation delete_action() const;
bool enforced() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::string>& referencing_column_list() const; int referencing_column_list_size() const; std::string referencing_column_list(int i) const; };
// This represents the ABSL_CHECK constraint on a table. It is of the form: // // CONSTRAINT <constraint_name> // ABSL_CHECK <expression> // <enforced> // <option_list> // // <constraint_name> uniquely identifies the constraint. // // <expression> defines a boolean expression to be evaluated when the row is // updated. If the result is FALSE, update to the row is not allowed. // // <enforced> specifies whether or not the constraint is enforced. // // <option_list> list of options for check constraint. // // See (broken link). class ResolvedCheckConstraint : public ResolvedConstraint { static const ResolvedNodeKind TYPE = RESOLVED_CHECK_CONSTRAINT;
const std::string& constraint_name() const;
const ResolvedExpr* expression() const;
bool enforced() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This is used in ResolvedQueryStmt (and other places) to provide a // user-visible name for each output column, and to map from // physical ResolvedColumns to user-visible output columns. class ResolvedOutputColumn : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_OUTPUT_COLUMN;
const std::string& name() const;
const ResolvedColumn& column() const; };
// This describes the output schema for table, like what is produced for // a query statement. // // <output_column_list> maps the physical ResolvedColumns available to // the user-visible column names that are returned, with their actual // column names. There may be duplicate names, and multiple output columns // may reference the same physical ResolvedColumn. // The list must be non-empty, since all output tables must have at least // one column. // // This node is used in some places, while many other older nodes just // have these two fields inlined into a parent object. // Ideally, all those cases could be migrated to use ResolvedOutputSchema. class ResolvedOutputSchema : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_OUTPUT_SCHEMA;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
// If true, the result of this query is a value table. Rather than // producing rows with named columns, it produces rows with a single // unnamed value type. output_column_list will have exactly one // column, with an empty name. See (broken link). bool is_value_table() const; };
// A Project node computes new expression values, and possibly drops // columns from the input Scan's column_list. // // Each entry in <expr_list> is a new column computed from an expression. // // The column_list can include any columns from input_scan, plus these // newly computed columns. // // NOTE: This scan will propagate the is_ordered property of <input_scan> // by default. To make this scan unordered, call set_is_ordered(false). class ResolvedProjectScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_PROJECT_SCAN;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& expr_list() const; int expr_list_size() const; const ResolvedComputedColumn* expr_list(int i) const;
const ResolvedScan* input_scan() const; };
// This scan represents a call to a table-valued function (TVF). Each TVF // returns an entire output relation instead of a single scalar value. The // enclosing query may refer to the TVF as if it were a table subquery. The // TVF may accept scalar arguments and/or other input relations. // // Scalar arguments work the same way as arguments for non-table-valued // functions: in the resolved AST, their types are equal to the required // argument types specified in the function signature. // // The function signature may also include relation arguments, and any such // relation argument may specify a required schema. If such a required schema // is present, then in the resolved AST, the ResolvedScan for each relational // ResolvedFunctionArgument is guaranteed to have the same number of columns // as the required schema, and the provided columns match position-wise with // the required columns. Each provided column has the same name and type as // the corresponding required column. // // If AnalyzerOptions::prune_unused_columns is true, the <column_list> and // <column_index_list> will include only columns that were referenced // in the user query. (SELECT * counts as referencing all columns.) // Pruning has no effect on value tables (the value is never pruned). // // <column_list> is a set of new ResolvedColumns created by this scan. // The <column_list>[i] should be matched to the related TVFScan's output // relation column by // <signature>.result_schema().column(<column_index_list>[i]). // // <tvf> The TableValuedFunction entry that the catalog returned for this TVF // scan. Contains non-concrete function signatures which may include // arguments with templated types. // <signature> The concrete table function signature for this TVF call, // including the types of all scalar arguments and the // number and types of columns of all table-valued // arguments. An engine may also subclass this object to // provide extra custom information and return an instance // of the subclass from the TableValuedFunction::Resolve // method. // <argument_list> The vector of resolved concrete arguments for this TVF // call, including the default values or NULLs injected for // the omitted arguments (Note the NULL injection is a // temporary solution to handle omitted named arguments. This // is subject to change by upcoming CLs). // // <column_index_list> This list matches 1-1 with the <column_list>, and // identifies the index of the corresponding column in the <signature>'s // result relation column list. // // <alias> The AS alias for the scan, or empty if none. // <function_call_signature> The FunctionSignature object from the // <tvf->signatures()> list that matched the // current call. The TVFScan's // <FunctionSignature::ConcreteArgument> list // matches 1:1 to <argument_list>, while its // <FunctionSignature::arguments> list still has // the full argument list. // The analyzer only sets this field when // it could be ambiguous for an engine to figure // out the actual arguments provided, e.g., when // there are arguments omitted from the call. When // it is provided, engines may use this object to // check for the argument names and omitted // arguments. SQLBuilder may also need this object // in cases when the named argument notation is // required for this call. class ResolvedTVFScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_TVFSCAN;
const TableValuedFunction* tvf() const;
const std::shared_ptr<TVFSignature>& signature() const;
const std::vector<std::unique_ptr<const ResolvedFunctionArgument>>& argument_list() const; int argument_list_size() const; const ResolvedFunctionArgument* argument_list(int i) const;
const std::vector<int>& column_index_list() const; int column_index_list_size() const; int column_index_list(int i) const;
const std::string& alias() const;
const std::shared_ptr<FunctionSignature>& function_call_signature() const; };
// ResolvedGroupRowsScan represents a call to a special TVF GROUP_ROWS(). // It can only show up inside WITH GROUP ROWS clause, which is resolved as // the field with_group_rows_subquery in ResolvedNonScalarFunctionCallBase // ResolvedGroupRowsScan. This scan produces rows corresponding to the input // of ResolvedAggregateScan that belong to the current group. // // <input_column_list> is a list of new columns created to store values // coming from the input of the aggregate scan. ResolvedComputedColumn can // only hold ResolvedColumnRef's and can reference anything from the // pre-aggregation scan. // // <alias> is the alias of the scan or empty if none. class ResolvedGroupRowsScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_GROUP_ROWS_SCAN;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& input_column_list() const; int input_column_list_size() const; const ResolvedComputedColumn* input_column_list(int i) const;
const std::string& alias() const; };
// This represents a generic argument to a function. The argument can be // semantically an expression, relation, model, connection descriptor, or // sequence. // // The following fields are mutally exclusive: // * `expr` represents a scalar function argument. // * `scan` represents a table-typed argument. // * `model` represents a ML model function argument. // * `connection` represents a connection object function argument. // * `descriptor_arg` represents a descriptor object function argument. // * `inline_lambda` represents a lambda function argument. // * `sequence` represents a sequence object function argument. // // This node could be used in multiple places: // * ResolvedTVFScan supports all of these. // * ResolvedFunctionCall supports `expr`, `inline_lambda`, and `sequence`. // * ResolvedCallStmt supports only `expr`. // // If the argument has type `scan`, `argument_column_list` maps columns from // `scan` into specific columns of the argument's input schema, matching // those columns positionally. i.e. `scan`'s column_list may have fewer // columns or out-of-order columns, and this vector maps those columns into // specific input columns. // // Some arguments may also have an alias, stored in the `argument_alias` // field, which is not mutally exclusive with the fields above. class ResolvedFunctionArgument : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_FUNCTION_ARGUMENT;
const ResolvedExpr* expr() const;
const ResolvedScan* scan() const;
const ResolvedModel* model() const;
const ResolvedConnection* connection() const;
const ResolvedDescriptor* descriptor_arg() const;
const std::vector<ResolvedColumn>& argument_column_list() const; int argument_column_list_size() const; ResolvedColumn argument_column_list(int i) const;
const ResolvedInlineLambda* inline_lambda() const;
const ResolvedSequence* sequence() const;
// Stores the alias of the argument, either provided by the user or // generated by the resolver. This can only be populated if allowed // by
FunctionArgumentTypeOptions::argument_alias_kind
. // // An argument alias is an identifier associated with a function // argument in the form of F(<arg> AS <alias>), where <alias> is the // argument alias for the function argument <arg>. // // Examples include // * STRUCT(1 AS x, 2 AS y) // * ARRAY_ZIP(arr1 AS a, arr2 AS b) // where the argument alias is used as a field name in an output // STRUCT value. For dynamic types like JSON, these aliases may be // used at run-time. // // This field will be empty if the argument does not support aliases, // or an alias could not be inferred. // // The current implementation only allows an argument to have an // alias if its type isexpr
, but the support may be extended to // other types, e.g.scan
ormodel
in the future. const std::string& argument_alias() const; };
// The superclass of all ZetaSQL statements. class ResolvedStatement : public ResolvedNode { typedef ResolvedStatementEnums::ObjectAccess ObjectAccess; static const ObjectAccess NONE = ResolvedStatementEnums::NONE; static const ObjectAccess READ = ResolvedStatementEnums::READ; static const ObjectAccess WRITE = ResolvedStatementEnums::WRITE; static const ObjectAccess READ_WRITE = ResolvedStatementEnums::READ_WRITE;
bool IsStatement() const final { return true; }
const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const; };
// An Explain statement. This is always the root of a statement hierarchy. // Its child may be any statement type except another ResolvedExplainStmt. // // It is implementation dependent what action a back end system takes for an // ExplainStatement. class ResolvedExplainStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_EXPLAIN_STMT;
const ResolvedStatement* statement() const; };
// A SQL query statement. This is the outermost query statement that runs // and produces rows of output, like a SELECT. (The contained query may be // a Scan corresponding to a non-Select top-level operation like UNION ALL // or WITH.) // // <output_column_list> gives the user-visible column names that should be // returned in the API or query tools. There may be duplicate names, and // multiple output columns may reference the same column from <query>. class ResolvedQueryStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_QUERY_STMT;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
// If true, the result of this query is a value table. Rather than // producing rows with named columns, it produces rows with a single // unnamed value type. output_column_list will have exactly one // column, with an empty name. See (broken link). bool is_value_table() const;
const ResolvedScan* query() const; };
// This is a query statement variation that supports generalized queries // using operators that might not produce exactly one query result. // Queries using these operators can produce multiple output tables, or zero // output tables, and can also have statement side-effects like DML actions. // // This is used for any query containing pipe syntax operators like FORK // (that splits the query into multiple output tables) or terminal operators // like CREATE TABLE (that consume the output without returning a table). // See (broken link). // // This node can only occur if: // * FEATURE_PIPES is enabled, // * Some pipe operator that produces generalized output is enabled, // * One of those operators occurs in the query, and // * ResolvedGeneralizedQueryStmt is in SupportedStatementKinds in // LanguageOptions. // // `output_schema` is nullable, and will be null if the outer `query` // doesn't return a table. // // Additional output tables or statement side-effects can be found // while traversing `query`, looking at ResolvedGeneralizedQuerySubpipeline // nodes. class ResolvedGeneralizedQueryStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_GENERALIZED_QUERY_STMT;
const ResolvedOutputSchema* output_schema() const;
const ResolvedScan* query() const; };
// This statement: // CREATE DATABASE <name> [OPTIONS (...)] // <name_path> is a vector giving the identifier path in the database name. // <option_list> specifies the options of the database. class ResolvedCreateDatabaseStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_DATABASE_STMT;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// Common superclass for CREATE statements with standard modifiers like // CREATE [OR REPLACE] [TEMP|TEMPORARY|PUBLIC|PRIVATE] <object type> // [IF NOT EXISTS] <name> ... // // <name_path> is a vector giving the identifier path in the table name. // <create_scope> is the relevant scope, i.e., DEFAULT, TEMP, PUBLIC, // or PRIVATE. PUBLIC/PRIVATE are only valid in module // resolution context, see (broken link) // for details. // <create_mode> indicates if this was CREATE, CREATE OR REPLACE, or // CREATE IF NOT EXISTS. class ResolvedCreateStatement : public ResolvedStatement { typedef ResolvedCreateStatementEnums::CreateScope CreateScope; typedef ResolvedCreateStatementEnums::CreateMode CreateMode; typedef ResolvedCreateStatementEnums::SqlSecurity SqlSecurity; typedef ResolvedCreateStatementEnums::DeterminismLevel DeterminismLevel; static const CreateScope CREATE_DEFAULT_SCOPE = ResolvedCreateStatementEnums::CREATE_DEFAULT_SCOPE; static const CreateScope CREATE_PRIVATE = ResolvedCreateStatementEnums::CREATE_PRIVATE; static const CreateScope CREATE_PUBLIC = ResolvedCreateStatementEnums::CREATE_PUBLIC; static const CreateScope CREATE_TEMP = ResolvedCreateStatementEnums::CREATE_TEMP; static const CreateMode CREATE_DEFAULT = ResolvedCreateStatementEnums::CREATE_DEFAULT; static const CreateMode CREATE_OR_REPLACE = ResolvedCreateStatementEnums::CREATE_OR_REPLACE; static const CreateMode CREATE_IF_NOT_EXISTS = ResolvedCreateStatementEnums::CREATE_IF_NOT_EXISTS; static const SqlSecurity SQL_SECURITY_UNSPECIFIED = ResolvedCreateStatementEnums::SQL_SECURITY_UNSPECIFIED; static const SqlSecurity SQL_SECURITY_DEFINER = ResolvedCreateStatementEnums::SQL_SECURITY_DEFINER; static const SqlSecurity SQL_SECURITY_INVOKER = ResolvedCreateStatementEnums::SQL_SECURITY_INVOKER; static const DeterminismLevel DETERMINISM_UNSPECIFIED = ResolvedCreateStatementEnums::DETERMINISM_UNSPECIFIED; static const DeterminismLevel DETERMINISM_DETERMINISTIC = ResolvedCreateStatementEnums::DETERMINISM_DETERMINISTIC; static const DeterminismLevel DETERMINISM_NOT_DETERMINISTIC = ResolvedCreateStatementEnums::DETERMINISM_NOT_DETERMINISTIC; static const DeterminismLevel DETERMINISM_IMMUTABLE = ResolvedCreateStatementEnums::DETERMINISM_IMMUTABLE; static const DeterminismLevel DETERMINISM_STABLE = ResolvedCreateStatementEnums::DETERMINISM_STABLE; static const DeterminismLevel DETERMINISM_VOLATILE = ResolvedCreateStatementEnums::DETERMINISM_VOLATILE;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
ResolvedCreateStatement::CreateScope create_scope() const;
ResolvedCreateStatement::CreateMode create_mode() const; };
// Represents one of indexed items in CREATE INDEX statement, with the // ordering direction specified. // // `option_list` represents the per item options for the index. This is // used in both the case where ALL COLUMNS is used and the case where // specific items are specified. The list of options for a specific item // must not be empty in the case of ALL COLUMNS. class ResolvedIndexItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_INDEX_ITEM;
const ResolvedColumnRef* column_ref() const;
bool descending() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This is used in CREATE INDEX STMT to represent the unnest operation // performed on the base table. The produced element columns or array offset // columns (optional) can appear in other ResolvedUnnestItem or index keys. // // <array_expr> is the expression of the array field, e.g., t.array_field. // <element_column> is the new column produced by this unnest item that // stores the array element value for each row. // <array_offset_column> is optional. If present, it defines the column // produced by this unnest item that stores the array // offset (0-based) for the corresponding // <element_column>. class ResolvedUnnestItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_UNNEST_ITEM;
const ResolvedExpr* array_expr() const;
const ResolvedColumn& element_column() const;
const ResolvedColumnHolder* array_offset_column() const; };
// This statement: // CREATE [OR REPLACE] [UNIQUE] [SEARCH | VECTOR] INDEX [IF NOT EXISTS] // <index_name_path> ON <table_name_path> // [UNNEST(path_expression) [[AS] alias] [WITH OFFSET [[AS] alias]], ...] // (path_expression [ASC|DESC], ...) // [STORING (Expression, ...)] // [PARTITION BY partition_expression, ...] // [OPTIONS (name=value, ...)]; // // <table_name_path> is the name of table being indexed. // <table_scan> is a TableScan on the table being indexed. // <is_unique> specifies if the index has unique entries. // <is_search> specifies if the index is for search. It is mutually exclusive // with is_vector. // <is_vector> specifies if the index is for vector search. It is mutually // exclusive with is_search. // <index_all_columns> specifies if indexing all the columns of the table. // When this field is true, index_item_list must be // empty and is_search must be true. // <index_item_list> has the columns being indexed, specified as references // to 'computed_columns_list' entries or the columns of // 'table_scan'. // <storing_expression_list> has the expressions in the storing clause. // <partition_by_list> has the expressions in the partition by clause. // <option_list> has engine-specific directives for how and where to // materialize this index. // <computed_columns_list> has computed columns derived from the columns of // 'table_scan' or 'unnest_expressions_list'. For // example, the extracted field (e.g., x.y.z). // <unnest_expressions_list> has unnest expressions derived from // 'table_scan' or previous unnest expressions in // the list. So the list order is significant. class ResolvedCreateIndexStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_INDEX_STMT;
const std::vector<std::string>& table_name_path() const; int table_name_path_size() const; std::string table_name_path(int i) const;
const ResolvedTableScan* table_scan() const;
bool is_unique() const;
bool is_search() const;
bool is_vector() const;
bool index_all_columns() const;
const std::vector<std::unique_ptr<const ResolvedIndexItem>>& index_item_list() const; int index_item_list_size() const; const ResolvedIndexItem* index_item_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& storing_expression_list() const; int storing_expression_list_size() const; const ResolvedExpr* storing_expression_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& computed_columns_list() const; int computed_columns_list_size() const; const ResolvedComputedColumn* computed_columns_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedUnnestItem>>& unnest_expressions_list() const; int unnest_expressions_list_size() const; const ResolvedUnnestItem* unnest_expressions_list(int i) const; };
// A base for statements that create schemas, such as:
// CREATE [OR REPLACE] SCHEMA [IF NOT EXISTS] <name>
// [DEFAULT COLLATE <collation>]
// [OPTIONS (name=value, ...)]
//
// CREATE [OR REPLACE] [TEMP|TEMPORARY|PUBLIC|PRIVATE] EXTERNAL SCHEMA
// [IF NOT EXISTS] <name> [WITH CONNECTION] <connection>
// OPTIONS (name=value, ...)
//
// <option_list> contains engine-specific options associated with the schema
class ResolvedCreateSchemaStmtBase : public ResolvedCreateStatement {
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const;
int option_list_size() const;
const ResolvedOption* option_list(int i) const;
};
// This statement: // CREATE [OR REPLACE] SCHEMA [IF NOT EXISTS] <name> // [DEFAULT COLLATE <collation>] // [OPTIONS (name=value, ...)] // <collation_name> specifies the default collation specification for future // tables created in the dataset. If a table is created in this dataset // without specifying table-level default collation, it inherits the // dataset default collation. A change to this field affects only tables // created afterwards, not the existing tables. Only string literals // are allowed for this field. // // Note: If a table being created in this schema does not specify table // default collation, the engine should copy the dataset default collation // to the table as the table default collation. class ResolvedCreateSchemaStmt : public ResolvedCreateSchemaStmtBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_SCHEMA_STMT;
const ResolvedExpr* collation_name() const; };
// This statement: // CREATE [OR REPLACE] [TEMP|TEMPORARY|PUBLIC|PRIVATE] EXTERNAL SCHEMA // [IF NOT EXISTS] <name> [WITH CONNECTION] <connection> // OPTIONS (name=value, ...) // // <connection> encapsulates engine-specific metadata used to connect // to an external data source // // Note: external schemas are pointers to schemas defined in an external // system. CREATE EXTERNAL SCHEMA does not actually build a new schema. class ResolvedCreateExternalSchemaStmt : public ResolvedCreateSchemaStmtBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_EXTERNAL_SCHEMA_STMT;
const ResolvedConnection* connection() const; };
// This statement: // CREATE [TEMP] TABLE <name> [(column type, ...) | LIKE <name_path>] // [DEFAULT COLLATE <collation>] [PARTITION BY expr, ...] // [CLUSTER BY expr, ...] [OPTIONS (...)] // // <option_list> has engine-specific directives for how and where to // materialize this table. // <column_definition_list> has the names and types of the columns in the // created table. If <is_value_table> is true, it // must contain exactly one column, with a generated // name such as "$struct". // <pseudo_column_list> is a list of some pseudo-columns expected to be // present on the created table (provided by // AnalyzerOptions::SetDdlPseudoColumns*). These can be // referenced in expressions in <partition_by_list> and // <cluster_by_list>. // <primary_key> specifies the PRIMARY KEY constraint on the table, it is // nullptr when no PRIMARY KEY is specified. // <foreign_key_list> specifies the FOREIGN KEY constraints on the table. // <check_constraint_list> specifies the ABSL_CHECK constraints on the table. // <partition_by_list> specifies the partitioning expressions for the table. // <cluster_by_list> specifies the clustering expressions for the table. // TODO: Return error when the PARTITION BY / CLUSTER BY // expression resolves to have collation specified. // <is_value_table> specifies whether the table is a value table. // See (broken link). // <like_table> identifies the table in the LIKE <name_path>. // By default, all fields (column names, types, constraints, // keys, clustering etc.) will be inherited from the source // table. But if explicitly set, the explicit settings will // take precedence. // <collation_name> specifies the default collation specification to apply to // newly added STRING fields in this table. A change of this field affects // only the STRING columns and the STRING fields in STRUCTs added // afterwards, not existing columns. Only string literals are allowed for // this field. // // Note: During table creation or alteration, if a STRING field is added to // this table without explicit collation specified, the engine should copy // the table default collation to the STRING field. class ResolvedCreateTableStmtBase : public ResolvedCreateStatement { const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& column_definition_list() const; int column_definition_list_size() const; const ResolvedColumnDefinition* column_definition_list(int i) const;
const std::vector<ResolvedColumn>& pseudo_column_list() const; int pseudo_column_list_size() const; ResolvedColumn pseudo_column_list(int i) const;
const ResolvedPrimaryKey* primary_key() const;
const std::vector<std::unique_ptr<const ResolvedForeignKey>>& foreign_key_list() const; int foreign_key_list_size() const; const ResolvedForeignKey* foreign_key_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedCheckConstraint>>& check_constraint_list() const; int check_constraint_list_size() const; const ResolvedCheckConstraint* check_constraint_list(int i) const;
bool is_value_table() const;
const Table* like_table() const;
const ResolvedExpr* collation_name() const;
const ResolvedConnection* connection() const; };
// This statement: // CREATE [TEMP] TABLE <name> // [(column schema, ...) | LIKE <name_path> | // {CLONE|COPY} <name_path> // [FOR SYSTEM_TIME AS OF <time_expr>] // [WHERE <where_clause>]] // [DEFAULT COLLATE <collation_name>] // [PARTITION BY expr, ...] [CLUSTER BY expr, ...] // [WITH CONNECTION connection_name] // [OPTIONS (...)] // // One of <clone_from> or <copy_from> can be present for CLONE or COPY. // <clone_from> specifies the data source to clone from (cheap, typically // O(1) operation); while <copy_from> is intended for a full copy. // // ResolvedTableScan will represent the source table, with an optional // for_system_time_expr. // // The ResolvedTableScan may be wrapped inside a ResolvedFilterScan if the // source table has a where clause. No other Scan types are allowed here. // // If the OPTIONS clause is explicitly specified, the option values are // intended to be used for the created or replaced table. // If any OPTION is unspecified, the corresponding option from the source // table will be used instead. // // The 'clone_from.column_list' field may be set, but should be ignored. // // clone_from and copy_from cannot be value tables. class ResolvedCreateTableStmt : public ResolvedCreateTableStmtBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_TABLE_STMT;
const ResolvedScan* clone_from() const;
const ResolvedScan* copy_from() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& cluster_by_list() const; int cluster_by_list_size() const; const ResolvedExpr* cluster_by_list(int i) const; };
// This statement: // CREATE [TEMP] TABLE <name> [(column schema, ...) | LIKE <name_path>] // [DEFAULT COLLATE <collation_name>] [PARTITION BY expr, ...] // [CLUSTER BY expr, ...] // [WITH CONNECTION connection_name] // [OPTIONS (...)] // AS SELECT ... // // The <output_column_list> matches 1:1 with the <column_definition_list> in // ResolvedCreateTableStmtBase, and maps ResolvedColumns produced by <query> // into specific columns of the created table. The output column names and // types must match the column definition names and types. If the table is // a value table, <output_column_list> must have exactly one column, with a // generated name such as "$struct". // // <output_column_list> does not contain all table schema information that // <column_definition_list> does. For example, NOT NULL annotations, column // OPTIONS, and primary keys are only available in <column_definition_list>. // Consumers are encouraged to read from <column_definition_list> rather // than than <output_column_list> to determine the table schema, if possible. // // <query> is the query to run. class ResolvedCreateTableAsSelectStmt : public ResolvedCreateTableStmtBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_TABLE_AS_SELECT_STMT;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& cluster_by_list() const; int cluster_by_list_size() const; const ResolvedExpr* cluster_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
const ResolvedScan* query() const; };
// Resolves a create model aliased query: // identifier AS <query> // // <alias> is the string representation of identifier. // <query> is the ResolvedScan of the subquery. // <output_column_list> matches 1:1 with the <query>'s column_list and // identifies the names and types of the columns output from the query. class ResolvedCreateModelAliasedQuery : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_MODEL_ALIASED_QUERY;
const std::string& alias() const;
const ResolvedScan* query() const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const; };
// This statement: // CREATE [TEMP] MODEL <name> [INPUT(...) OUTPUT(...)] [TRANSFORM(...)] // [REMOTE [WITH CONNECTION ...]] [OPTIONS (...)] // [AS <query> | (<identifier> AS (<query>) [, ...])] // // At most one of <query> and <aliased_query_list> can be set. <query> is // used when there is a single query as input. <aliased_query_list> is used // for the syntax with multiple queries with identifiers. For below, let // <has_query> be true if either of these are present. // // Models can be evaluated either locally or remotely. Orthogonally, they can // be either trained using SQL or come from external source. Depending on // these properties, different clauses are expected to be present. // // * Local models <is_remote> = FALSE // * Trained: <has_query> // * External: !<has_query> // * Remote models <is_remote> = TRUE // * Trained: <has_query> // * External: !<has_query> // // <option_list> has engine-specific directives for how to train this model. // <query> is the AS SELECT statement. It can be only set when all of // <input_column_definition_list>, <output_column_definition_list> and // <aliased_query_list> are empty. // TODO: consider rename to <query_output_column_list>. // <output_column_list> matches 1:1 with the <query>'s column_list and // identifies the names and types of the columns output from the select // statement. Set only when <query> is present. // <input_column_definition_list> contains names and types of model's input // columns. Cannot be set if <has_query> is true. Might be absent when // <is_remote> is true, meaning schema is read from the remote model // itself. // <output_column_definition_list> contains names and types of model's output // columns. Cannot be set if <has_query> is true. Might be absent when // <is_remote> is true, meaning schema is read from the remote model // itself. // <is_remote> is true if this is a remote model. // <connection> is the identifier path of the connection object. It can be // only set when <is_remote> is true. // <transform_list> is the list of ResolvedComputedColumn in TRANSFORM // clause. It can be only set when <query> is present. // <transform_input_column_list> introduces new ResolvedColumns that have the // same names and types of the columns in the <output_column_list>. The // transform expressions resolve against these ResolvedColumns. It's only // set when <transform_list> is non-empty. // <transform_output_column_list> matches 1:1 with <transform_list> output. // It records the names of the output columns from TRANSFORM clause. // <transform_analytic_function_group_list> is the list of // AnalyticFunctionGroup for analytic functions inside TRANSFORM clause. // It records the input expression of the analytic functions. It can // see all the columns from <transform_input_column_list>. The only valid // group is for the full, unbounded window generated from empty OVER() // clause. // For example, CREATE MODEL statement // "create model Z // transform (max(c) over() as d) // options () // as select 1 c, 2 b;" // will generate transform_analytic_function_group_list: // +-transform_analytic_function_group_list= // +-AnalyticFunctionGroup // +-analytic_function_list= // +-d#5 := // +-AnalyticFunctionCall(ZetaSQL:max(INT64) -> INT64) // +-ColumnRef(type=INT64, column=Z.c#3) // +-window_frame= // +-WindowFrame(frame_unit=ROWS) // +-start_expr= // | +-WindowFrameExpr(boundary_type=UNBOUNDED PRECEDING) // +-end_expr= // +-WindowFrameExpr(boundary_type=UNBOUNDED FOLLOWING) // <aliased_query_list> is the aliased query list. It can only be set when // <is_remote> is false and <query> is null. It cannot coexist with any // transform related resolved nodes. class ResolvedCreateModelStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_MODEL_STMT;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
const ResolvedScan* query() const;
const std::vector<std::unique_ptr<const ResolvedCreateModelAliasedQuery>>& aliased_query_list() const; int aliased_query_list_size() const; const ResolvedCreateModelAliasedQuery* aliased_query_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& transform_input_column_list() const; int transform_input_column_list_size() const; const ResolvedColumnDefinition* transform_input_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& transform_list() const; int transform_list_size() const; const ResolvedComputedColumn* transform_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& transform_output_column_list() const; int transform_output_column_list_size() const; const ResolvedOutputColumn* transform_output_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedAnalyticFunctionGroup>>& transform_analytic_function_group_list() const; int transform_analytic_function_group_list_size() const; const ResolvedAnalyticFunctionGroup* transform_analytic_function_group_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& input_column_definition_list() const; int input_column_definition_list_size() const; const ResolvedColumnDefinition* input_column_definition_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& output_column_definition_list() const; int output_column_definition_list_size() const; const ResolvedColumnDefinition* output_column_definition_list(int i) const;
bool is_remote() const;
const ResolvedConnection* connection() const; };
// Common superclass for CREATE view/materialized view: // CREATE [TEMP|MATERIALIZED] [RECURSIVE] VIEW <name> [(...)] // [OPTIONS (...)] // AS SELECT ... // // <option_list> has engine-specific directives for options attached to // this view. // <output_column_list> has the names and types of the columns in the // created view, and maps from <query>'s column_list // to these output columns. If <has_explicit_columns> is // true, names will be explicitly provided. // <has_explicit_columns> If this is set, the statement includes an explicit // column name list. These column names should still be applied even if the // query changes or is re-resolved in the future. The view becomes invalid // if the query produces a different number of columns. // <query> is the query to run. // <sql> is the view query text. // <sql_security> is the declared security mode for the function. Values // include 'INVOKER', 'DEFINER'. // <recursive> specifies whether or not the view is created with the // RECURSIVE keyword. // <column_definition_list> matches 1:1 with the <output_column_list> and // provides explicit definition for each output column. Output column names // and types must match column definition names and types. If the table is // a value table, <column_definition_list> must have exactly one column, // with a generated name such as "$struct". // // Currently <column_definition_list> contains the same schema information // (column names and types) as <output_column_list>, but also contains the // column OPTIONS. Therefore, consumers are encouraged to read from // <column_definition_list> rather than from <output_column_list> to // determine the schema, if possible. // // Note that <query> and <sql> are both marked as IGNORABLE because // an engine could look at either one (but might not look at both). // An engine must look at one (and cannot ignore both) to be // semantically valid, but there is currently no way to enforce that. // // The view must produce named columns with unique names. class ResolvedCreateViewBase : public ResolvedCreateStatement { const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
bool has_explicit_columns() const;
const ResolvedScan* query() const;
const std::string& sql() const;
ResolvedCreateStatement::SqlSecurity sql_security() const;
// If true, this view produces a value table. Rather than producing // rows with named columns, it produces rows with a single unnamed // value type. output_column_list will have exactly one column, with // an empty name. See (broken link). bool is_value_table() const;
// True if the view uses the RECURSIVE keyword. <query> // can be a ResolvedRecursiveScan only if this is true. bool recursive() const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& column_definition_list() const; int column_definition_list_size() const; const ResolvedColumnDefinition* column_definition_list(int i) const; };
// This statement: // CREATE [TEMP] VIEW <name> [(...)] [OPTIONS (...)] AS SELECT ... class ResolvedCreateViewStmt : public ResolvedCreateViewBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_VIEW_STMT;
};
// This statement: // WITH PARTITION COLUMNS [(column schema, ...)] class ResolvedWithPartitionColumns : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WITH_PARTITION_COLUMNS;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& column_definition_list() const; int column_definition_list_size() const; const ResolvedColumnDefinition* column_definition_list(int i) const; };
// This statement: // CREATE SNAPSHOT TABLE [IF NOT EXISTS] <name> [OPTIONS (...)] // CLONE <name> // [FOR SYSTEM_TIME AS OF <time_expr>] // // <clone_from> the source data to clone data from. // ResolvedTableScan will represent the source table, with an // optional for_system_time_expr. // The ResolvedTableScan may be wrapped inside a // ResolvedFilterScan if the source table has a where clause. // No other Scan types are allowed here. // By default, all fields (column names, types, constraints, // partition, clustering, options etc.) will be inherited from // the source table. If table options are explicitly set, the // explicit options will take precedence. // The 'clone_from.column_list' field may be set, but should be // ignored. class ResolvedCreateSnapshotTableStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_SNAPSHOT_TABLE_STMT;
const ResolvedScan* clone_from() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: // CREATE [TEMP] EXTERNAL TABLE <name> [(column type, ...)] // [DEFAULT COLLATE <collation_name>] // [WITH PARTITION COLUMN [(column type, ...)]] // [WITH CONNECTION connection_name] // OPTIONS (...) class ResolvedCreateExternalTableStmt : public ResolvedCreateTableStmtBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_EXTERNAL_TABLE_STMT;
const ResolvedWithPartitionColumns* with_partition_columns() const; };
// This statement: // EXPORT MODEL <model_name_path> [WITH CONNECTION <connection>] // <option_list> // which is used to export a model to a specific location. // <connection> is the connection that the model is written to. // <option_list> identifies user specified options to use when exporting the // model. class ResolvedExportModelStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_EXPORT_MODEL_STMT;
const std::vector<std::string>& model_name_path() const; int model_name_path_size() const; std::string model_name_path(int i) const;
const ResolvedConnection* connection() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: // EXPORT DATA [WITH CONNECTION] <connection> (<option_list>) AS SELECT ... // or this pipe operator (without a query, in ResolvedPipeExportDataScan): // |> EXPORT DATA [WITH CONNECTION] <connection> (<option_list>) // // This is used to run export a query result somewhere without giving the // result a table name. // // <connection> connection reference for accessing destination source. // <option_list> has engine-specific directives for how and where to // materialize the query result. // <output_column_list> has the names and types of the columns produced by // the query, and maps from <query>'s column_list // to these output columns. The engine may ignore // the column names depending on the output format. // <query> is the query to run (when this node is used as a statement). // When this node is used as part of ResolvedPipeExportDataScan, // <query> is not present. The input table is the pipe input table. // // The query must produce named columns with unique names. class ResolvedExportDataStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_EXPORT_DATA_STMT;
const ResolvedConnection* connection() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
// If true, the result of this query is a value table. Rather than // producing rows with named columns, it produces rows with a single // unnamed value type. output_column_list will have exactly one // column, with an empty name. See (broken link). bool is_value_table() const;
//
query
is present when this node is used as a statement. //query
is not present when used in ResolvedPipeExportDataScan. const ResolvedScan* query() const; };
// This statement: // EXPORT <schema_object_kind> METADATA FROM <name_path> // [WITH CONNECTION <connection>] [OPTIONS(<option_list>)] // // <schema_object_kind> is a string identifier for the object for which the // metadata should be exported. Currently, only 'TABLE' object is supported. // <name_path> is a vector giving the identifier path for the object for // which the metadata should be exported. // <connection> connection reference for accessing destination source. // <option_list> identifies user specified options to use when exporting // object's metadata. class ResolvedExportMetadataStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_EXPORT_METADATA_STMT;
const std::string& schema_object_kind() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const ResolvedConnection* connection() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: DEFINE TABLE name (...); // // <name_path> is a vector giving the identifier path in the table name. // <option_list> has engine-specific options of how the table is defined. // // DEFINE TABLE normally has the same effect as CREATE TEMP EXTERNAL TABLE. class ResolvedDefineTableStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DEFINE_TABLE_STMT;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: DESCRIBE [<object_type>] <name> [FROM <from_name_path>]; // // <object_type> is an optional string identifier, // e.g., "INDEX", "FUNCTION", "TYPE", etc. // <name_path> is a vector giving the identifier path for the object to be // described. // <from_name_path> is an optional vector giving the identifier path of a // containing object, e.g. a table. class ResolvedDescribeStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DESCRIBE_STMT;
const std::string& object_type() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::string>& from_name_path() const; int from_name_path_size() const; std::string from_name_path(int i) const; };
// This statement: SHOW <identifier> [FROM <name_path>] [LIKE <like_expr>]; // // <identifier> is a string that determines the type of objects to be shown, // e.g., TABLES, COLUMNS, INDEXES, STATUS, // <name_path> is an optional path to an object from which <identifier> // objects will be shown, e.g., if <identifier> = INDEXES and // <name> = table_name, the indexes of "table_name" will be // shown, // <like_expr> is an optional ResolvedLiteral of type string that if present // restricts the objects shown to have a name like this string. class ResolvedShowStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_SHOW_STMT;
const std::string& identifier() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const ResolvedLiteral* like_expr() const; };
// This statement: BEGIN [TRANSACTION] [ <transaction_mode> [, ...] ] // // Where transaction_mode is one of: // READ ONLY // READ WRITE // <isolation_level> // // <isolation_level> is a string vector storing the identifiers after // ISOLATION LEVEL. The strings inside vector could be one of the // SQL standard isolation levels: // // READ UNCOMMITTED // READ COMMITTED // READ REPEATABLE // SERIALIZABLE // // or could be arbitrary strings. ZetaSQL does not validate that // the string is valid. class ResolvedBeginStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_BEGIN_STMT;
typedef ResolvedBeginStmtEnums::ReadWriteMode ReadWriteMode; static const ReadWriteMode MODE_UNSPECIFIED = ResolvedBeginStmtEnums::MODE_UNSPECIFIED; static const ReadWriteMode MODE_READ_ONLY = ResolvedBeginStmtEnums::MODE_READ_ONLY; static const ReadWriteMode MODE_READ_WRITE = ResolvedBeginStmtEnums::MODE_READ_WRITE;
ResolvedBeginStmt::ReadWriteMode read_write_mode() const;
const std::vector<std::string>& isolation_level_list() const; int isolation_level_list_size() const; std::string isolation_level_list(int i) const; };
// This statement: SET TRANSACTION <transaction_mode> [, ...] // // Where transaction_mode is one of: // READ ONLY // READ WRITE // <isolation_level> // // <isolation_level> is a string vector storing the identifiers after // ISOLATION LEVEL. The strings inside vector could be one of the // SQL standard isolation levels: // // READ UNCOMMITTED // READ COMMITTED // READ REPEATABLE // SERIALIZABLE // // or could be arbitrary strings. ZetaSQL does not validate that // the string is valid. class ResolvedSetTransactionStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_SET_TRANSACTION_STMT;
typedef ResolvedBeginStmt::ReadWriteMode ReadWriteMode;
ResolvedBeginStmt::ReadWriteMode read_write_mode() const;
const std::vector<std::string>& isolation_level_list() const; int isolation_level_list_size() const; std::string isolation_level_list(int i) const; };
// This statement: COMMIT [TRANSACTION]; class ResolvedCommitStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_COMMIT_STMT;
};
// This statement: ROLLBACK [TRANSACTION]; class ResolvedRollbackStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ROLLBACK_STMT;
};
// This statement: START BATCH [<batch_type>]; // // <batch_type> is an optional string identifier that identifies the type of // the batch. (e.g. "DML" or "DDL) class ResolvedStartBatchStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_START_BATCH_STMT;
const std::string& batch_type() const; };
// This statement: RUN BATCH; class ResolvedRunBatchStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_RUN_BATCH_STMT;
};
// This statement: ABORT BATCH; class ResolvedAbortBatchStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ABORT_BATCH_STMT;
};
// This statement: DROP <object_type> [IF EXISTS] <name_path> [<drop_mode>]; // // <object_type> is an string identifier, // e.g., "TABLE", "VIEW", "INDEX", "FUNCTION", "TYPE", etc. // <name_path> is a vector giving the identifier path for the object to be // dropped. // <is_if_exists> silently ignore the "name_path does not exist" error. // <drop_mode> specifies drop mode RESTRICT/CASCASE, if any. class ResolvedDropStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_STMT;
typedef ResolvedDropStmtEnums::DropMode DropMode; static const DropMode DROP_MODE_UNSPECIFIED = ResolvedDropStmtEnums::DROP_MODE_UNSPECIFIED; static const DropMode RESTRICT = ResolvedDropStmtEnums::RESTRICT; static const DropMode CASCADE = ResolvedDropStmtEnums::CASCADE;
const std::string& object_type() const;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
ResolvedDropStmt::DropMode drop_mode() const; };
// This statement: DROP MATERIALIZED VIEW [IF EXISTS] <name_path>; // // <name_path> is a vector giving the identifier path for the object to be // dropped. // <is_if_exists> silently ignore the "name_path does not exist" error. class ResolvedDropMaterializedViewStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_MATERIALIZED_VIEW_STMT;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const; };
// This statement: DROP SNAPSHOT TABLE [IF EXISTS] <name_path>; // // <name_path> is a vector giving the identifier path for the object to be // dropped. // <is_if_exists> silently ignore the "name_path does not exist" error. class ResolvedDropSnapshotTableStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_SNAPSHOT_TABLE_STMT;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const; };
// Scan the previous iteration of the recursive alias currently being // defined, from inside the recursive subquery which defines it. Such nodes // can exist only in the recursive term of a ResolvedRecursiveScan node. // The column_list produced here will match 1:1 with the column_list produced // by the referenced subquery and will be given a new unique name to each // column produced for this scan. class ResolvedRecursiveRefScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_RECURSIVE_REF_SCAN;
};
// This represents a recursion depth modifier to recursive CTE: // WITH DEPTH [ AS <recursion_depth_column> ] // [ BETWEEN <lower_bound> AND <upper_bound> ] // // <lower_bound> and <upper_bound> represents the range of iterations (both // side included) whose results are part of CTE's final output. // // lower_bound and upper_bound are two integer literals or // query parameters. Query parameter values must be checked at run-time by // ZetaSQL compliant backend systems. // - both lower/upper_bound must be non-negative; // - lower_bound is by default zero if unspecified; // - upper_bound is by default infinity if unspecified; // - lower_bound must be smaller or equal than upper_bound; // // <recursion_depth_column> is the column that represents the // recursion depth semantics: the iteration number that outputs this row; // it is part of ResolvedRecursiveScan's column list when specified, but // there is no corresponding column in the inputs of Recursive CTE. // // See (broken link):explicit-recursion-depth for details. class ResolvedRecursionDepthModifier : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_RECURSION_DEPTH_MODIFIER;
const ResolvedExpr* lower_bound() const;
const ResolvedExpr* upper_bound() const;
const ResolvedColumnHolder* recursion_depth_column() const; };
// A recursive query inside a WITH RECURSIVE or RECURSIVE VIEW. A // ResolvedRecursiveScan may appear in a resolved tree only as a top-level // input scan of a ResolvedWithEntry or ResolvedCreateViewBase. // // Recursive queries must satisfy the form: // <non-recursive-query> UNION [ALL|DISTINCT] <recursive-query> // // where self-references to table being defined are allowed only in the // <recursive-query> section. // // <column_list> is a set of new ResolvedColumns created by this scan. // Each input ResolvedSetOperationItem has an <output_column_list> which // matches 1:1 with <column_list> and specifies how the input <scan>'s // columns map into the final <column_list>. // // At runtime, a recursive scan is evaluated using an iterative process: // // Step 1 (iteration 0): Evaluate the non-recursive term. If UNION DISTINCT // is specified, discard duplicates. // // Step 2 (iteration k): // Repeat until step 2 produces an empty result: // Evaluate the recursive term, binding the recursive table to the // new rows produced by previous step (iteration k-1). // If UNION DISTINCT is specified, discard duplicate rows, as well as any // rows which match any previously-produced result. // // Step 3: // The final content of the recursive table is the UNION ALL of all results // produced [lower_bound, upper_bound] iterations specified in the // recursion depth modifier. (which are already DISTINCT because of step 2, // if the query had UNION DISTINCT). The final content is augmented by the // column specified in the recursion depth modifier (if specified) which // represents the iteration number that the row is output. // If UNION DISTINCT is specified, the depth column represents the first // iteration that produces a given row. // The depth column will be part of the output column list. // // When recursion_depth_modifier is unspecified, the lower bound is // effectively zero, the upper bound is infinite. // // ResolvedRecursiveScan only supports a recursive WITH entry which // directly references itself; ZetaSQL does not support mutual recursion // between multiple with-clause elements. // // See (broken link) for details. class ResolvedRecursiveScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_RECURSIVE_SCAN;
typedef ResolvedRecursiveScanEnums::RecursiveSetOperationType RecursiveSetOperationType; static const RecursiveSetOperationType UNION_ALL = ResolvedRecursiveScanEnums::UNION_ALL; static const RecursiveSetOperationType UNION_DISTINCT = ResolvedRecursiveScanEnums::UNION_DISTINCT;
ResolvedRecursiveScan::RecursiveSetOperationType op_type() const;
const ResolvedSetOperationItem* non_recursive_term() const;
const ResolvedSetOperationItem* recursive_term() const;
const ResolvedRecursionDepthModifier* recursion_depth_modifier() const; };
// This represents a SQL WITH query (or subquery) like // WITH [RECURSIVE] <with_query_name1> AS (<with_subquery1>), // <with_query_name2> AS (<with_subquery2>) // <query>; // // WITH entries are sorted in dependency order so that an entry can only // reference entries earlier in <with_entry_list>, plus itself if the // RECURSIVE keyword is used. If the RECURSIVE keyword is not used, this will // be the same order as in the original query, since an entry which // references itself or any entry later in the list is not allowed. // // If a WITH subquery is referenced multiple times, the full query should // behave as if the subquery runs only once and its result is reused. // // There will be one ResolvedWithEntry here for each subquery in the SQL // WITH statement, in the same order as in the query. // // Inside the resolved <query>, or any <with_entry_list> occurring after // its definition, a <with_query_name> used as a table scan will be // represented using a ResolvedWithRefScan. // // The <with_query_name> aliases are always unique within a query, and should // be used to connect the ResolvedWithRefScan to the original query // definition. The subqueries are not inlined and duplicated into the tree. // // In ZetaSQL 1.0, WITH is allowed only on the outermost query and not in // subqueries, so the ResolvedWithScan node can only occur as the outermost // scan in a statement (e.g. a QueryStmt or CreateTableAsSelectStmt). // // In ZetaSQL 1.1 (language option FEATURE_V_1_1_WITH_ON_SUBQUERY), WITH // is allowed on subqueries. Then, ResolvedWithScan can occur anywhere in // the tree. The alias introduced by a ResolvedWithEntry is visible only // in subsequent ResolvedWithEntry queries and in <query>. The aliases used // must be globally unique in the resolved AST however, so consumers do not // need to implement any scoping for these names. Because the aliases are // unique, it is legal to collect all ResolvedWithEntries in the tree and // treat them as if they were a single WITH clause at the outermost level. // // In ZetaSQL 1.3 (language option FEATURE_V_1_3_WITH_RECURSIVE), WITH // RECURSIVE is supported, which allows any <with_subquery> to reference // any <with_query_name>, regardless of order, including WITH entries which // reference themself. Circular dependency chains of WITH entries are allowed // only for direct self-references, and only when the corresponding // <with_subquery> takes the form "<non-recursive-term> UNION [ALL|DISTINCT] // <recursive-term>", with all references to the current <with_query_name> // confined to the recursive term. // // The subqueries inside ResolvedWithEntries cannot be correlated. // // If a WITH subquery is defined but never referenced, it will still be // resolved and still show up here. Query engines may choose not to run it. class ResolvedWithScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_WITH_SCAN;
const std::vector<std::unique_ptr<const ResolvedWithEntry>>& with_entry_list() const; int with_entry_list_size() const; const ResolvedWithEntry* with_entry_list(int i) const;
const ResolvedScan* query() const;
// True if the WITH clause uses the recursive keyword. bool recursive() const; };
// This represents one aliased subquery introduced in a WITH clause. // // The <with_query_name>s must be globally unique in the full resolved AST. // The <with_subquery> cannot be correlated and cannot reference any // columns from outside. It may reference other WITH subqueries. // // See ResolvedWithScan for full details. class ResolvedWithEntry : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WITH_ENTRY;
const std::string& with_query_name() const;
const ResolvedScan* with_subquery() const; };
// This represents one SQL hint or option key/value pair. // The SQL syntax @{ key1=value1, key2=value2, some_db.key3=value3 } // will expand to three ResolvedOptions. Keyword hints (e.g. LOOKUP JOIN) // are interpreted as shorthand, and will be expanded to a ResolvedOption // attached to the appropriate node before any explicit long-form hints. // // ResolvedOptions are attached to the ResolvedScan corresponding to the // operator that the SQL hint was associated with. // See (broken link) for more detail. // Hint semantics are implementation defined. // // Each hint or option is resolved as a [<qualifier>.]<name>:=<value> pair. // <qualifier> will be empty if no qualifier was present. // <name> is always non-empty. // <value> can be a ResolvedLiteral or a ResolvedParameter, // a cast of a ResolvedParameter (for typed hints only), // or a general expression (on constant inputs). // <assignment_op> is an enum that indicates the assignment operation for // array type options. // // If AllowedHintsAndOptions was set in AnalyzerOptions, and this hint or // option was included there and had an expected type, the type of <value> // will match that expected type. For assignment_op that's not the default // value, also checks whether the expected type is Array and whether // allow_alter_array is true. Unknown hints and options(not listed in // AllowedHintsAndOptions) are not stripped and will still show up here. // // If non-empty, <qualifier> should be interpreted as a target system name, // and a database system should ignore any hints targeted to different // systems. // // <qualifier> is set only for hints, and will always be empty in options // lists. // // <assignment_op> will always be DEFAULT_ASSIGN (i.e. "=") for hints, and // defaults to the same value for options. Can be set to // ADD_ASSIGN ("+=") and SUB_ASSIGN ("-=") for options with // Array type. // // The SQL syntax allows using an identifier as a hint value. // Such values are stored here as ResolvedLiterals with string type. class ResolvedOption : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_OPTION;
typedef ResolvedOptionEnums::AssignmentOp AssignmentOp; static const AssignmentOp DEFAULT_ASSIGN = ResolvedOptionEnums::DEFAULT_ASSIGN; static const AssignmentOp ADD_ASSIGN = ResolvedOptionEnums::ADD_ASSIGN; static const AssignmentOp SUB_ASSIGN = ResolvedOptionEnums::SUB_ASSIGN;
const std::string& qualifier() const;
const std::string& name() const;
const ResolvedExpr* value() const;
ResolvedOption::AssignmentOp assignment_op() const; };
// Window partitioning specification for an analytic function call. // // PARTITION BY keys in <partition_by_list>. // // <collation_list> is either empty to indicate that all the elements in // <partition_by_list> have the default collation, or <collation_list> has // the same number of elements as <partition_by_list>. Each element is the // collation for the element in <partition_by_list> with the same index, or // can be empty to indicate default collation or when the type is not // collatable. <collation_list> is only set when // FEATURE_V_1_3_COLLATION_SUPPORT is enabled. // See (broken link). class ResolvedWindowPartitioning : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WINDOW_PARTITIONING;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedColumnRef* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const;
const std::vector<ResolvedCollation>& collation_list() const; int collation_list_size() const; ResolvedCollation collation_list(int i) const; };
// Window ordering specification for an analytic function call. // // ORDER BY items in <order_by_list>. There should be exactly one ORDER // BY item if this is a window ORDER BY for a RANGE-based window. class ResolvedWindowOrdering : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WINDOW_ORDERING;
const std::vector<std::unique_ptr<const ResolvedOrderByItem>>& order_by_item_list() const; int order_by_item_list_size() const; const ResolvedOrderByItem* order_by_item_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& hint_list() const; int hint_list_size() const; const ResolvedOption* hint_list(int i) const; };
// Window framing specification for an analytic function call. // // ROW-based window frames compute the frame based on physical offsets // from the current row. // RANGE-based window frames compute the frame based on a logical // range of rows around the current row based on the current row's // ORDER BY key value. // // <start_expr> and <end_expr> cannot be NULL. If the window frame // is one-sided in the input query, the resolver will generate an // implicit ending boundary. class ResolvedWindowFrame : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WINDOW_FRAME;
typedef ResolvedWindowFrameEnums::FrameUnit FrameUnit; static const FrameUnit ROWS = ResolvedWindowFrameEnums::ROWS; static const FrameUnit RANGE = ResolvedWindowFrameEnums::RANGE;
std::string GetFrameUnitString() const; static std::string FrameUnitToString(FrameUnit frame_unit);
ResolvedWindowFrame::FrameUnit frame_unit() const;
const ResolvedWindowFrameExpr* start_expr() const;
const ResolvedWindowFrameExpr* end_expr() const; };
// This represents a group of analytic function calls that shares PARTITION // BY and ORDER BY. // // <partition_by> can be NULL. <order_by> may be NULL depending on the // functions in <analytic_function_list> and the window frame unit. See // (broken link) for more details. // // All expressions in <analytic_function_list> have a // ResolvedAnalyticFunctionCall with a function in mode // Function::AGGREGATE or Function::ANALYTIC. class ResolvedAnalyticFunctionGroup : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ANALYTIC_FUNCTION_GROUP;
const ResolvedWindowPartitioning* partition_by() const;
const ResolvedWindowOrdering* order_by() const;
const std::vector<std::unique_ptr<const ResolvedComputedColumnBase>>& analytic_function_list() const; int analytic_function_list_size() const; const ResolvedComputedColumnBase* analytic_function_list(int i) const; };
// Window frame boundary expression that determines the first/last row of // the moving window for each tuple. // // <expression> cannot be NULL if the type is OFFSET_PRECEDING // or OFFSET_FOLLOWING. It must be a constant expression. If this is a // boundary for a ROW-based window, it must be integer type. Otherwise, // it must be numeric type and must match exactly the type of the window // ordering expression. See (broken link) for more // details. class ResolvedWindowFrameExpr : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_WINDOW_FRAME_EXPR;
typedef ResolvedWindowFrameExprEnums::BoundaryType BoundaryType; static const BoundaryType UNBOUNDED_PRECEDING = ResolvedWindowFrameExprEnums::UNBOUNDED_PRECEDING; static const BoundaryType OFFSET_PRECEDING = ResolvedWindowFrameExprEnums::OFFSET_PRECEDING; static const BoundaryType CURRENT_ROW = ResolvedWindowFrameExprEnums::CURRENT_ROW; static const BoundaryType OFFSET_FOLLOWING = ResolvedWindowFrameExprEnums::OFFSET_FOLLOWING; static const BoundaryType UNBOUNDED_FOLLOWING = ResolvedWindowFrameExprEnums::UNBOUNDED_FOLLOWING;
std::string GetBoundaryTypeString() const; static std::string BoundaryTypeToString(BoundaryType boundary_type);
ResolvedWindowFrameExpr::BoundaryType boundary_type() const;
const ResolvedExpr* expression() const; };
// This represents a value inside an INSERT or UPDATE statement. // // The <value> is either an expression or a DMLDefault. // // For proto fields, NULL values mean the field should be cleared. class ResolvedDMLValue : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_DMLVALUE;
const ResolvedExpr* value() const; };
// This is used to represent the value DEFAULT that shows up (in place of a // value expression) in INSERT and UPDATE statements. // For columns, engines should substitute the engine-defined default value // for that column, or give an error. // For proto fields, this always means to clear the field. // This will never show up inside expressions other than ResolvedDMLValue. class ResolvedDMLDefault : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_DMLDEFAULT;
};
// This represents the ASSERT statement: // ASSERT <expression> [AS <description>]; // // <expression> is any expression that returns a bool. // <description> is an optional string literal used to give a more // descriptive error message in case the ASSERT fails. class ResolvedAssertStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ASSERT_STMT;
const ResolvedExpr* expression() const;
const std::string& description() const; };
// This represents the ASSERT ROWS MODIFIED clause on a DML statement. // The value must be a literal or (possibly casted) parameter int64. // // The statement should fail if the number of rows updated does not // exactly match this number. class ResolvedAssertRowsModified : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ASSERT_ROWS_MODIFIED;
const ResolvedExpr* rows() const; };
// This represents the ON CONFLICT clause on an INSERT statement. It // specifies the alternate action to be taken if the insert row causes // unique constraint violations. // // <conflict_action> is the action to take if the insert row causes unique // constraint violations. Either NOTHING to ignore the insert row or UPDATE // to update the original table row with the constraint values. // // <conflict_target_column_list> is the list of columns to infer a unique // constraint - primary key or UNIQUE columns - for which the uniqueness // should be arbitrated. ZetaSQL only resolves them into valid column // references. It is the engine's responsibility to validate and infer // a unique constraint. See "Conflict target" section in // (broken link), http://shortn/_4GrUbFPEKm // // <unique_constraint_name> is the name of the UNIQUE constraint instead of // specifying the columns in conflict target. ZetaSQL only resolves it as // a valid identifier. It is the engine's responsibility to infer a UNIQUE // constraint. See "Conflict target" section in // (broken link). http://shortn/_4GrUbFPEKm // // <insert_row_scan> is a ResolvedTableScan on the target table. It returns // the new rows that were constructed to be inserted where the insert failed // with a conflict, using the underlying Table's columns. // The included columns are the columns from insert row referenced // in the update SET RHS expression and/or the update WHERE clause using // the `excluded` alias. It can also include generated columns or columns not // in the INSERT column list. // This is applicable only for conflict action UPDATE. It's null if the // conflict action is NOTHING. // // <update_item_list> is the list of update items if the conflict action is // UPDATE. They are refer columns in both the insert row and original table // row. // // <update_where_expression> is used to conditionally update the table row if // the conflict action is UPDATE. class ResolvedOnConflictClause : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ON_CONFLICT_CLAUSE;
typedef ResolvedOnConflictClauseEnums::ConflictAction ConflictAction; static const ConflictAction NOTHING = ResolvedOnConflictClauseEnums::NOTHING; static const ConflictAction UPDATE = ResolvedOnConflictClauseEnums::UPDATE;
std::string GetConflictActionString() const; static std::string ConflictActionToString(ConflictAction action);
ResolvedOnConflictClause::ConflictAction conflict_action() const;
// IGNORABLE_DEFAULT because this is an optional field for NOTHING // conflict action. It is also empty if unique constraint name // is specified. const std::vector<ResolvedColumn>& conflict_target_column_list() const; int conflict_target_column_list_size() const; ResolvedColumn conflict_target_column_list(int i) const;
// IGNORABLE_DEFAULT because this is an optional field for NOTHING // conflict action. It is also empty if conflict target is specified. const std::string& unique_constraint_name() const;
// IGNORABLE_DEFAULT because this is set for UPDATE conflict action // only and if update_item_list and/or update_where_expression // reference columns from the insert row using
excluded
alias. const ResolvedTableScan* insert_row_scan() const;// IGNORABLE_DEFAULT because this is set for UPDATE conflict action // only. const std::vector<std::unique_ptr<const ResolvedUpdateItem>>& update_item_list() const; int update_item_list_size() const; const ResolvedUpdateItem* update_item_list(int i) const;
// IGNORABLE_DEFAULT because this is set for UPDATE conflict action // only. const ResolvedExpr* update_where_expression() const; };
// This represents one row in the VALUES clause of an INSERT. class ResolvedInsertRow : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_INSERT_ROW;
const std::vector<std::unique_ptr<const ResolvedDMLValue>>& value_list() const; int value_list_size() const; const ResolvedDMLValue* value_list(int i) const; };
// This represents an INSERT statement, or a nested INSERT inside an // UPDATE statement. // // For top-level INSERT statements, <table_scan> gives the table to // scan and creates ResolvedColumns for its columns. Those columns can be // referenced in <insert_column_list>. // // For nested INSERTS, there is no <table_scan> or <insert_column_list>. // There is implicitly a single column to insert, and its type is the // element type of the array being updated in the ResolvedUpdateItem // containing this statement. // // For nested INSERTs, alternate modes are not supported and <insert_mode> // will always be set to OR_ERROR. // // The rows to insert come from <row_list> or the result of <query>. // Exactly one of these must be present. // // If <row_list> is present, the columns in the row_list match // positionally with <insert_column_list>. // // If <query> is present, <query_output_column_list> must also be present. // <query_output_column_list> is the list of output columns produced by // <query> that correspond positionally with the target <insert_column_list> // on the output table. For nested INSERTs with no <insert_column_list>, // <query_output_column_list> must have exactly one column. // // <query_parameter_list> is set for nested INSERTs where <query> is set and // references non-target values (columns or field values) from the table. It // is only set when FEATURE_V_1_2_CORRELATED_REFS_IN_NESTED_DML is enabled. // // If <returning> is present, the INSERT statement will return newly inserted // rows. <returning> can only occur on top-level statements. // // The returning clause has a <output_column_list> to represent the data // sent back to clients. It can only access columns from the <table_scan>. // // <topologically_sorted_generated_column_id_list> is set for queries to // tables having generated columns. It provides the resolved column ids of // the generated columns in topological order, which the computed generated // column expressions can be computed in. // // <generated_expr_list> has generated expressions for the corresponding // generated column in the topologically_sorted_generated_column_id_list. // Hence, these lists have the same size. // // <column_access_list> indicates for each column in <table_scan.column_list> // whether it was read and/or written. The query engine may also require // read or write permissions across all columns, including unreferenced // columns, depending on the operation. // // <on_conflict_clause> specifies the alternate action if the insert row // causes unique constraint violations. It handles violations in both primary // key and UNIQUE constraints. Alternate actions are (1) to do nothing // (ignore the insert row), or (2) update the original table row using the // specified SET clauses and the optional WHERE clause. class ResolvedInsertStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_INSERT_STMT;
typedef ResolvedInsertStmtEnums::InsertMode InsertMode; static const InsertMode OR_ERROR = ResolvedInsertStmtEnums::OR_ERROR; static const InsertMode OR_IGNORE = ResolvedInsertStmtEnums::OR_IGNORE; static const InsertMode OR_REPLACE = ResolvedInsertStmtEnums::OR_REPLACE; static const InsertMode OR_UPDATE = ResolvedInsertStmtEnums::OR_UPDATE;
std::string GetInsertModeString() const; static std::string InsertModeToString(InsertMode boundary_type);
const ResolvedTableScan* table_scan() const;
// Behavior on duplicate rows (normally defined to mean duplicate // primary keys). ResolvedInsertStmt::InsertMode insert_mode() const;
const ResolvedAssertRowsModified* assert_rows_modified() const;
const ResolvedReturningClause* returning() const;
const std::vector<ResolvedColumn>& insert_column_list() const; int insert_column_list_size() const; ResolvedColumn insert_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnRef>>& query_parameter_list() const; int query_parameter_list_size() const; const ResolvedColumnRef* query_parameter_list(int i) const;
const ResolvedScan* query() const;
const std::vector<ResolvedColumn>& query_output_column_list() const; int query_output_column_list_size() const; ResolvedColumn query_output_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedInsertRow>>& row_list() const; int row_list_size() const; const ResolvedInsertRow* row_list(int i) const;
const std::vector<ResolvedStatement::ObjectAccess>& column_access_list() const; int column_access_list_size() const; ResolvedStatement::ObjectAccess column_access_list(int i) const;
const ResolvedOnConflictClause* on_conflict_clause() const;
// This returns a topologically sorted list of generated columns // resolved ids in the table accessed by insert statement. // For example for below table // CREATE TABLE T( // k1 INT64 NOT NULL, // data INT64, // gen1 INT64 AS data+1, // gen2 INT64 AS gen12, // gen3 INT64 AS data2 + gen1, // ) PRIMARY KEY(k1); // data------------------->gen1--------------------->gen2 // * *----------> * // * ------------------------------->gen3 // the vector would have corresponding indexes of one of these values // gen1 gen2 gen3 OR gen1 gen3 gen2. const std::vector<int>& topologically_sorted_generated_column_id_list() const; int topologically_sorted_generated_column_id_list_size() const; int topologically_sorted_generated_column_id_list(int i) const;
// This field returns the vector of generated column expressions // corresponding to the column ids in // topologically_sorted_generated_column_id_list. Both the lists have // the same size and 1-to-1 mapping for the column id with its // corresponding expression. This field is not directly accessed // from the catalog since these expressions are rewritten to replace // the ResolvedExpressionColumn for the referred columns in the // catalog to corresponding ResolvedColumnRef. const std::vector<std::unique_ptr<const ResolvedExpr>>& generated_column_expr_list() const; int generated_column_expr_list_size() const; const ResolvedExpr* generated_column_expr_list(int i) const; };
// This represents a DELETE statement or a nested DELETE inside an // UPDATE statement. // // For top-level DELETE statements, <table_scan> gives the table to // scan and creates ResolvedColumns for its columns. Those columns can // be referenced inside the <where_expr>. // // For nested DELETEs, there is no <table_scan>. The <where_expr> can // only reference: // (1) the element_column from the ResolvedUpdateItem containing this // statement, // (2) columns from the outer statements, and // (3) (optionally) <array_offset_column>, which represents the 0-based // offset of the array element being modified. // // <where_expr> is required. // // If <returning> is present, the DELETE statement will return deleted rows // back. It can only occur on top-level statements. // // This returning clause has a <output_column_list> to represent the data // sent back to clients. It can only access columns from the <table_scan>. // // <column_access_list> indicates for each column in <table_scan.column_list> // whether it was read and/or written. The query engine may also require // read or write permissions across all columns, including unreferenced // columns, depending on the operation. class ResolvedDeleteStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DELETE_STMT;
const ResolvedTableScan* table_scan() const;
const ResolvedAssertRowsModified* assert_rows_modified() const;
const ResolvedReturningClause* returning() const;
const std::vector<ResolvedStatement::ObjectAccess>& column_access_list() const; int column_access_list_size() const; ResolvedStatement::ObjectAccess column_access_list(int i) const;
const ResolvedColumnHolder* array_offset_column() const;
const ResolvedExpr* where_expr() const; };
// This represents one item inside the SET clause of an UPDATE. // // The entity being updated is specified by <target>. // // For a regular // SET {target} = {expression} | DEFAULT // clause (not including an array element update like SET a[OFFSET(0)] = 5), // <target> and <set_value> will be present, and all other fields will be // unset. // // For an array element update (e.g. SET a.b[<expr>].c = <value>), // - <target> is set to the array, // - <element_column> is a new ResolvedColumn that can be used inside the // update items to refer to the array element. // - <array_update_list> will have a node corresponding to the offset into // that array and the modification to that array element. // For example, for SET a.b[<expr>].c = <value>, we have // ResolvedUpdateItem // +-<target> = a.b // +-<element_column> = <x> // +-<array_update_list> // +-ResolvedUpdateArrayItem // +-<offset> = <expr> // +-<update_item> = ResolvedUpdateItem // +-<target> = <x>.c // +-<set_value> = <value> // // The engine is required to fail the update if there are two elements of // <array_update_list> corresponding to offset expressions that evaluate to // the same value. These are considered to be conflicting updates. // // Multiple updates to the same array are always represented as multiple // elements of <array_update_list> under a single ResolvedUpdateItem // corresponding to that array. <array_update_list> will only have one // element for modifications to an array-valued subfield of an array element. // E.g., for SET a[<expr1>].b[<expr2>] = 5, a[<expr3>].b[<expr4>] = 6, we // will have: // ResolvedUpdateItem // +-<target> = a // +-<element_column> = x // +-<array_update_list> // +-ResolvedUpdateArrayItem // +-<offset> = <expr1> // +-ResolvedUpdateItem for <x>.b[<expr2>] = 5 // +-ResolvedUpdateArrayItem // +-<offset> = <expr3> // +-ResolvedUpdateItem for <x>.b[<expr4>] = 6 // The engine must give a runtime error if <expr1> and <expr3> evaluate to // the same thing. Notably, it does not have to understand that the // two ResolvedUpdateItems corresponding to "b" refer to the same array iff // <expr1> and <expr3> evaluate to the same thing. // // TODO: Consider allowing the engine to execute an update like // SET a[<expr1>].b = 1, a[<expr2>].c = 2 even if <expr1> == <expr2> since // "b" and "c" do not overlap. Also consider allowing a more complex example // like SET a[<expr1>].b[<expr2>] = ..., // a[<expr3>].b[<expr4>].c[<expr5>] = ... even if <expr1> == <expr3>, as long // as <expr2> != <expr4> in that case. // // For nested DML, <target> and <element_column> will both be set, and one or // more of the nested statement lists will be non-empty. <target> must have // ARRAY type, and <element_column> introduces a ResolvedColumn representing // elements of that array. The nested statement lists will always be empty in // a ResolvedUpdateItem child of a ResolvedUpdateArrayItem node. // // See (broken link) for more detail. class ResolvedUpdateItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_UPDATE_ITEM;
// The target entity to be updated. // // This is an expression evaluated using the ResolvedColumns visible // inside this statement. This expression can contain only // ResolvedColumnRefs, ResolvedGetProtoField and // ResolvedGetStructField nodes. // // In a top-level UPDATE, the expression always starts with a // ResolvedColumnRef referencing a column from the statement's // TableScan. // // In a nested UPDATE, the expression always starts with a // ResolvedColumnRef referencing the element_column from the // ResolvedUpdateItem containing this scan. // // This node is also used to represent a modification of a single // array element (when it occurs as a child of a // ResolvedUpdateArrayItem node). In that case, the expression // starts with a ResolvedColumnRef referencing the <element_column> // from its grandparent ResolvedUpdateItem. (E.g., for "SET a[<expr>] // = 5", the grandparent ResolvedUpdateItem has <target> "a", the // parent ResolvedUpdateArrayItem has offset <expr>, and this node // has <set_value> 5 and target corresponding to the grandparent's // <element_column> field.) // // For either a nested UPDATE or an array modification, there may be // a path of field accesses after the initial ResolvedColumnRef, // represented by a chain of GetField nodes. // // NOTE: We use the same GetField nodes as we do for queries, but // they are not treated the same. Here, they express a path inside // an object that is being mutated, so they have reference semantics. const ResolvedExpr* target() const;
// Set the target entity to this value. The types must match. // This can contain the same columns that can appear in the // <where_expr> of the enclosing ResolvedUpdateStmt. // // This is mutually exclusive with all fields below, which are used // for nested updates only. const ResolvedDMLValue* set_value() const;
// The ResolvedColumn introduced to represent the elements of the // array being updated. This works similarly to // ArrayScan::element_column. // // <target> must have array type, and this column has the array's // element type. // // This column can be referenced inside the nested statements below. const ResolvedColumnHolder* element_column() const;
// Array element modifications to apply. Each item runs on the value // of <element_column> specified by ResolvedUpdateArrayItem.offset. // This field is always empty if the analyzer option // FEATURE_V_1_2_ARRAY_ELEMENTS_WITH_SET is disabled. // // The engine must fail if two elements in this list have offset // expressions that evaluate to the same value. // TODO: Consider generalizing this to allow // SET a[<expr1>].b = ..., a[<expr2>].c = ... const std::vector<std::unique_ptr<const ResolvedUpdateArrayItem>>& array_update_list() const; int array_update_list_size() const; const ResolvedUpdateArrayItem* array_update_list(int i) const;
// Nested DELETE statements to apply. Each delete runs on one value // of <element_column> and may choose to delete that array element. // // DELETEs are applied before INSERTs or UPDATEs. // // It is legal for the same input element to match multiple DELETEs. const std::vector<std::unique_ptr<const ResolvedDeleteStmt>>& delete_list() const; int delete_list_size() const; const ResolvedDeleteStmt* delete_list(int i) const;
// Nested UPDATE statements to apply. Each update runs on one value // of <element_column> and may choose to update that array element. // // UPDATEs are applied after DELETEs and before INSERTs. // // It is an error if any element is matched by multiple UPDATEs. const std::vector<std::unique_ptr<const ResolvedUpdateStmt>>& update_list() const; int update_list_size() const; const ResolvedUpdateStmt* update_list(int i) const;
// Nested INSERT statements to apply. Each insert will produce zero // or more values for <element_column>. // // INSERTs are applied after DELETEs and UPDATEs. // // For nested UPDATEs, insert_mode will always be the default, and // has no effect. const std::vector<std::unique_ptr<const ResolvedInsertStmt>>& insert_list() const; int insert_list_size() const; const ResolvedInsertStmt* insert_list(int i) const; };
// For an array element modification, this node represents the offset // expression and the modification, but not the array. E.g., for // SET a[<expr>] = 5, this node represents a modification of "= 5" to offset // <expr> of the array defined by the parent node. class ResolvedUpdateArrayItem : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_UPDATE_ARRAY_ITEM;
// The array offset to be modified. const ResolvedExpr* offset() const;
// The modification to perform to the array element. const ResolvedUpdateItem* update_item() const; };
// This represents an UPDATE statement, or a nested UPDATE inside an // UPDATE statement. // // For top-level UPDATE statements, <table_scan> gives the table to // scan and creates ResolvedColumns for its columns. Those columns can be // referenced in the <update_item_list>. The top-level UPDATE statement may // also have <from_scan>, the output of which is joined with // the <table_scan> using expressions in the <where_expr>. The columns // exposed in the <from_scan> are visible in the right side of the // expressions in the <update_item_list> and in the <where_expr>. // <array_offset_column> is never set for top-level UPDATE statements. // // Top-level UPDATE statements will also have <column_access_list> populated. // For each column, this vector indicates if the column was read and/or // written. The columns in this vector match those of // <table_scan.column_list>. If a column was not encountered when producing // the resolved AST, then the value at that index will be // ResolvedStatement::NONE. // // For nested UPDATEs, there is no <table_scan>. The <where_expr> can // only reference: // (1) the element_column from the ResolvedUpdateItem containing this // statement, // (2) columns from the outer statements, and // (3) (optionally) <array_offset_column>, which represents the 0-based // offset of the array element being modified. // The left hand sides of the expressions in <update_item_list> can only // reference (1). The right hand sides of those expressions can reference // (1), (2), and (3). // // The updates in <update_item_list> will be non-overlapping. // If there are multiple nested statements updating the same entity, // they will be combined into one ResolvedUpdateItem. // // See (broken link) for more detail on nested DML. // // If <returning> is present, the UPDATE statement will return updated rows. // <returning> can only occur on top-level statements. // // This returning clause has a <output_column_list> to represent the data // sent back to clients. It can only access columns from the <table_scan>. // The columns in <from_scan> are not allowed. // TODO: allow columns in <from_scan> to be referenced. // // <topologically_sorted_generated_column_id_list> is set for queries to // tables having generated columns. This field is similar to the INSERT case, // more details can be found in ResolvedInsertStmt. // // <generated_expr_list> has generated expressions for the corresponding // generated column in the topologically_sorted_generated_column_id_list. // Hence, these lists have the same size. This field is similar to the // INSERT case, more details can be found in ResolvedInsertStmt. class ResolvedUpdateStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_UPDATE_STMT;
const ResolvedTableScan* table_scan() const;
const std::vector<ResolvedStatement::ObjectAccess>& column_access_list() const; int column_access_list_size() const; ResolvedStatement::ObjectAccess column_access_list(int i) const;
const ResolvedAssertRowsModified* assert_rows_modified() const;
const ResolvedReturningClause* returning() const;
const ResolvedColumnHolder* array_offset_column() const;
const ResolvedExpr* where_expr() const;
const std::vector<std::unique_ptr<const ResolvedUpdateItem>>& update_item_list() const; int update_item_list_size() const; const ResolvedUpdateItem* update_item_list(int i) const;
const ResolvedScan* from_scan() const;
// TODO: refactor it with INSERT case. const std::vector<int>& topologically_sorted_generated_column_id_list() const; int topologically_sorted_generated_column_id_list_size() const; int topologically_sorted_generated_column_id_list(int i) const;
// TODO: refactor it with INSERT case. const std::vector<std::unique_ptr<const ResolvedExpr>>& generated_column_expr_list() const; int generated_column_expr_list_size() const; const ResolvedExpr* generated_column_expr_list(int i) const; };
// This is used by ResolvedMergeStmt to represent one WHEN ... THEN clause // within MERGE statement. // // There are three types of clauses, which are MATCHED, NOT_MATCHED_BY_SOURCE // and NOT_MATCHED_BY_TARGET. The <match_type> must have one of these values. // // The <match_expr> defines an optional expression to apply to the join // result of <table_scan> and <from_scan> of the parent ResolvedMergeStmt. // // Each ResolvedMergeWhen must define exactly one of three operations, // -- INSERT: <action_type> is ResolvedMergeWhen::INSERT. // Both <insert_column_list> and <insert_row> are non-empty. // The size of <insert_column_list> must be the same with the // value_list size of <insert_row>, and, the column data type // must match. // -- UPDATE: <action_type> is ResolvedMergeWhen::UPDATE. // <update_item_list> is non-empty. // -- DELETE: <action_type> is ResolvedMergeWhen::DELETE. // The INSERT, UPDATE and DELETE operations are mutually exclusive. // // When <match_type> is MATCHED, <action_type> must be UPDATE or DELETE. // When <match_type> is NOT_MATCHED_BY_TARGET, <action_type> must be INSERT. // When <match_type> is NOT_MATCHED_BY_SOURCE, <action_type> must be UPDATE // or DELETE. // // The column visibility within a ResolvedMergeWhen clause is defined as // following, // -- When <match_type> is MATCHED, // -- All columns from <table_scan> and <from_scan> are allowed in // <match_expr>. // -- If <action_type> is UPDATE, only columns from <table_scan> are // allowed on left side of expressions in <update_item_list>. // All columns from <table_scan> and <from_scan> are allowed on right // side of expressions in <update_item_list>. // -- When <match_type> is NOT_MATCHED_BY_TARGET, // -- Only columns from <from_scan> are allowed in <match_expr>. // -- Only columns from <table_scan> are allowed in // <insert_column_list>. // -- Only columns from <from_scan> are allowed in <insert_row>. // -- When <match_type> is NOT_MATCHED_BY_SOURCE, // -- Only columns from <table_scan> are allowed in <match_expr>. // -- If <action_type> is UPDATE, only columns from <table_scan> are // allowed in <update_item_list>. class ResolvedMergeWhen : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_MERGE_WHEN;
typedef ResolvedMergeWhenEnums::MatchType MatchType; typedef ResolvedMergeWhenEnums::ActionType ActionType; static const MatchType MATCHED = ResolvedMergeWhenEnums::MATCHED; static const MatchType NOT_MATCHED_BY_SOURCE = ResolvedMergeWhenEnums::NOT_MATCHED_BY_SOURCE; static const MatchType NOT_MATCHED_BY_TARGET = ResolvedMergeWhenEnums::NOT_MATCHED_BY_TARGET; static const ActionType INSERT = ResolvedMergeWhenEnums::INSERT; static const ActionType UPDATE = ResolvedMergeWhenEnums::UPDATE; static const ActionType DELETE = ResolvedMergeWhenEnums::DELETE;
ResolvedMergeWhen::MatchType match_type() const;
const ResolvedExpr* match_expr() const;
ResolvedMergeWhen::ActionType action_type() const;
const std::vector<ResolvedColumn>& insert_column_list() const; int insert_column_list_size() const; ResolvedColumn insert_column_list(int i) const;
const ResolvedInsertRow* insert_row() const;
const std::vector<std::unique_ptr<const ResolvedUpdateItem>>& update_item_list() const; int update_item_list_size() const; const ResolvedUpdateItem* update_item_list(int i) const; };
// This represents a MERGE statement. // // <table_scan> gives the target table to scan and creates ResolvedColumns // for its columns. // // <column_access_list> indicates for each column, whether it was read and/or // written. The columns in this vector match those of // <table_scan.column_list>. If a column was not encountered when producing // the resolved AST, then the value at that index will be // ResolvedStatement::NONE(0). // // The output of <from_scan> is joined with <table_scan> using the join // expression <merge_expr>. // // The order of elements in <when_clause_list> matters, as they are executed // sequentially. At most one of the <when_clause_list> clause will be applied // to each row from <table_scan>. // // <table_scan>, <from_scan>, <merge_expr> and <when_clause_list> are // required. <when_clause_list> must be non-empty. // // See (broken link) for more detail on MERGE statement. class ResolvedMergeStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_MERGE_STMT;
const ResolvedTableScan* table_scan() const;
const std::vector<ResolvedStatement::ObjectAccess>& column_access_list() const; int column_access_list_size() const; ResolvedStatement::ObjectAccess column_access_list(int i) const;
const ResolvedScan* from_scan() const;
const ResolvedExpr* merge_expr() const;
const std::vector<std::unique_ptr<const ResolvedMergeWhen>>& when_clause_list() const; int when_clause_list_size() const; const ResolvedMergeWhen* when_clause_list(int i) const; };
// This represents a TRUNCATE TABLE statement. // // Statement: // TRUNCATE TABLE <table_name> [WHERE <boolean_expression>] // // <table_scan> is a TableScan for the target table, which is used during // resolving and validation. Consumers can use either the table // object inside it or name_path to reference the table. // <where_expr> boolean expression that can reference columns in // ResolvedColumns (which the TableScan creates); the // <where_expr> should always correspond to entire partitions, // and is optional. class ResolvedTruncateStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_TRUNCATE_STMT;
const ResolvedTableScan* table_scan() const;
const ResolvedExpr* where_expr() const; };
// A reference to a unit of an object (e.g. a column or field of a table). // // <name_path> is a vector giving the identifier path of the object unit. class ResolvedObjectUnit : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_OBJECT_UNIT;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const; };
// A grantable privilege. // // <action_type> is the type of privilege action, e.g. SELECT, INSERT, UPDATE // or DELETE. // <unit_list> is an optional list of units of the object (e.g. columns of a // table, fields in a value table) that the privilege is scoped to. The // privilege is on the whole object if the list is empty. class ResolvedPrivilege : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_PRIVILEGE;
const std::string& action_type() const;
const std::vector<std::unique_ptr<const ResolvedObjectUnit>>& unit_list() const; int unit_list_size() const; const ResolvedObjectUnit* unit_list(int i) const; };
// Common superclass of GRANT/REVOKE statements. // // <privilege_list> is the list of privileges to be granted/revoked. ALL // PRIVILEGES should be granted/revoked if it is empty. // <object_type_list> is an optional list of string identifiers, e.g., TABLE, // VIEW, MATERIALIZED VIEW. // <name_path> is a vector of segments of the object identifier's pathname. // <grantee_list> (DEPRECATED) is the list of grantees (strings). // <grantee_expr_list> is the list of grantees, and may include parameters. // // Only one of <grantee_list> or <grantee_expr_list> will be populated, // depending on whether or not the FEATURE_PARAMETERS_IN_GRANTEE_LIST // is enabled. The <grantee_list> is deprecated, and will be removed // along with the corresponding FEATURE once all engines have migrated to // use the <grantee_expr_list>. Once <grantee_expr_list> is the only // one, then it should be marked as NOT_IGNORABLE. class ResolvedGrantOrRevokeStmt : public ResolvedStatement { ABSL_DEPRECATED("Use `object_type_list()` instead") inline const std::string& object_type() const { return object_type_list()[0]; }
const std::vector<std::unique_ptr<const ResolvedPrivilege>>& privilege_list() const; int privilege_list_size() const; const ResolvedPrivilege* privilege_list(int i) const;
const std::vector<std::string>& object_type_list() const; int object_type_list_size() const; std::string object_type_list(int i) const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::string>& grantee_list() const; int grantee_list_size() const; std::string grantee_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& grantee_expr_list() const; int grantee_expr_list_size() const; const ResolvedExpr* grantee_expr_list(int i) const; };
// A GRANT statement. It represents the action to grant a list of privileges // on a specific object to/from list of grantees. class ResolvedGrantStmt : public ResolvedGrantOrRevokeStmt { static const ResolvedNodeKind TYPE = RESOLVED_GRANT_STMT;
};
// A REVOKE statement. It represents the action to revoke a list of // privileges on a specific object to/from list of grantees. class ResolvedRevokeStmt : public ResolvedGrantOrRevokeStmt { static const ResolvedNodeKind TYPE = RESOLVED_REVOKE_STMT;
};
// Common super class for statements: // ALTER <object> [IF EXISTS] <name_path> <alter_action_list> // // <name_path> is a vector giving the identifier path in the table <name>. It // is optional if // FEATURE_ALLOW_MISSING_PATH_EXPRESSION_IN_ALTER_DDL is enabled. // <alter_action_list> is a vector of actions to be done to the object. // <is_if_exists> silently ignores the "name_path does not exist" error. class ResolvedAlterObjectStmt : public ResolvedStatement { const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedAlterAction>>& alter_action_list() const; int alter_action_list_size() const; const ResolvedAlterAction* alter_action_list(int i) const;
bool is_if_exists() const; };
// This statement: // ALTER DATABASE [IF EXISTS] <name_path> <alter_action_list> // // This statement could be used to change the database level options. class ResolvedAlterDatabaseStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_DATABASE_STMT;
};
// This statement: // ALTER MATERIALIZED VIEW [IF EXISTS] <name_path> <alter_action_list> class ResolvedAlterMaterializedViewStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_MATERIALIZED_VIEW_STMT;
};
// This statement: // ALTER APPROX VIEW [IF EXISTS] <name_path> <alter_action_list> class ResolvedAlterApproxViewStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_APPROX_VIEW_STMT;
};
// This statement: // ALTER SCHEMA [IF NOT EXISTS] <name_path> <alter_action_list>; class ResolvedAlterSchemaStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_SCHEMA_STMT;
};
// This statement: // ALTER EXTERNAL SCHEMA [IF EXISTS] <name_path> <alter_action_list>; class ResolvedAlterExternalSchemaStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_EXTERNAL_SCHEMA_STMT;
};
// This statement: // ALTER MODEL [IF EXISTS] <name_path> <alter_action_list> class ResolvedAlterModelStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_MODEL_STMT;
};
// This statement: // ALTER TABLE [IF EXISTS] <name_path> <alter_action_list> class ResolvedAlterTableStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_TABLE_STMT;
};
// This statement: // ALTER VIEW [IF EXISTS] <name_path> <alter_action_list> class ResolvedAlterViewStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_VIEW_STMT;
};
// A common super class for all actions in statement ALTER <object>
class ResolvedAlterAction : public ResolvedArgument {
};
// A super class for all ALTER COLUMN actions in the ALTER TABLE statement: // ALTER TABLE <table_name> ALTER COLUMN [IF EXISTS] <column> // // <is_if_exists> silently ignores the "column does not exist" error. // <column> is the name of the column. class ResolvedAlterColumnAction : public ResolvedAlterAction { bool is_if_exists() const;
const std::string& column() const; };
// SET OPTIONS action for ALTER <object> statement // // <option_list> has engine-specific directives that specify how to // alter the metadata for this object. class ResolvedSetOptionsAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_SET_OPTIONS_ACTION;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// Alter sub-entity action for ALTER <object> statement. // (broken link) // // ALTER <entity_type> [IF EXISTS] <name> <alter_action> // // <entity_type> engine-specific sub-entity type to be altered. // <name> the identifier for the sub-entity resource being altered. // <alter_action> action for the sub-entity resource, such as // SET OPTIONS or a further nested ALTER sub-entity action. // <is_if_exists> if set, skip the alter action if the resource does // not exist. class ResolvedAlterSubEntityAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_SUB_ENTITY_ACTION;
const std::string& entity_type() const;
const std::string& name() const;
const ResolvedAlterAction* alter_action() const;
bool is_if_exists() const; };
// Add sub-entity action for ALTER <object> statement. // (broken link) // // ADD <entity_type> [IF NOT EXISTS] <name> [OPTIONS(...)] // // <entity_type> engine-specific sub-entity type to be added. // <name> the identifier for the sub-entity resource being added. // <options_list> engine specific options_list for the sub-entity resource. // <is_if_not_exists> if set, skip the add action if the resource // already exists. class ResolvedAddSubEntityAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_ADD_SUB_ENTITY_ACTION;
const std::string& entity_type() const;
const std::string& name() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& options_list() const; int options_list_size() const; const ResolvedOption* options_list(int i) const;
bool is_if_not_exists() const; };
// Drop sub-entity action for ALTER <object> statement. // (broken link) // // DROP <entity_type> [IF EXISTS] <name> // // <entity_type> engine-specific sub-entity type to be dropped. // <name> the identifier for the sub-entity resource being dropped. // <is_if_exists> if set, skip the drop action if the resource does // not exist. class ResolvedDropSubEntityAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_DROP_SUB_ENTITY_ACTION;
const std::string& entity_type() const;
const std::string& name() const;
bool is_if_exists() const; };
// ADD COLUMN action for ALTER TABLE statement class ResolvedAddColumnAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_ADD_COLUMN_ACTION;
bool is_if_not_exists() const;
const ResolvedColumnDefinition* column_definition() const; };
// ADD CONSTRAINT for ALTER TABLE statement class ResolvedAddConstraintAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_ADD_CONSTRAINT_ACTION;
bool is_if_not_exists() const;
const ResolvedConstraint* constraint() const;
const Table* table() const; };
// DROP CONSTRAINT for ALTER TABLE statement class ResolvedDropConstraintAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_DROP_CONSTRAINT_ACTION;
bool is_if_exists() const;
const std::string& name() const; };
// DROP PRIMARY KEY [IF EXISTS] for ALTER TABLE statement class ResolvedDropPrimaryKeyAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_DROP_PRIMARY_KEY_ACTION;
bool is_if_exists() const; };
// This ALTER action: // ALTER COLUMN [IF EXISTS] <column> SET OPTIONS <options_list> // // <options_list> has engine-specific directives that specify how to // alter the metadata for a column. class ResolvedAlterColumnOptionsAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_OPTIONS_ACTION;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This ALTER action: // ALTER COLUMN [IF EXISTS] <column> DROP NOT NULL // // Removes the NOT NULL constraint from the given column. class ResolvedAlterColumnDropNotNullAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_DROP_NOT_NULL_ACTION;
};
// This ALTER action: // ALTER COLUMN [IF EXISTS] <column> DROP GENERATED // // Removes the generated value (either an expression or identity column) // from the given column. class ResolvedAlterColumnDropGeneratedAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_DROP_GENERATED_ACTION;
};
// ALTER COLUMN <column> SET DATA TYPE action for ALTER TABLE // statement. It supports updating the data type of the column as // well as updating type parameters and collation specifications of // the column (and on struct fields and array elements). class ResolvedAlterColumnSetDataTypeAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_SET_DATA_TYPE_ACTION;
// The new type for the column. const Type* updated_type() const;
// The new type parameters for the column, if the new type has // parameters. Note that unlike with CREATE TABLE, the child_list is // populated for ARRAY and STRUCT types. // TODO Use updated_annotations to pass type parameters. const TypeParameters& updated_type_parameters() const;
// The new annotations for the column including the new collation // specifications. Changing options using SET DATA TYPE action is not // allowed. const ResolvedColumnAnnotations* updated_annotations() const; };
// Alter column set default action: // ALTER COLUMN [IF EXISTS] <column> SET DEFAULT <default_value> // // <default_value> sets the new default value expression. It only impacts // future inserted rows, and has no impact on existing rows with the current // default value. This is a metadata only operation. // // Resolver validates that <default_value> expression can be coerced to the // column type when <column> exists. If <column> is not found and // <is_if_exists> is true, Resolver skips type match check. class ResolvedAlterColumnSetDefaultAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_SET_DEFAULT_ACTION;
const ResolvedColumnDefaultValue* default_value() const; };
// This ALTER action: // ALTER COLUMN [IF EXISTS] <column> DROP DEFAULT // // Removes the DEFAULT constraint from the given column. class ResolvedAlterColumnDropDefaultAction : public ResolvedAlterColumnAction { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_DROP_DEFAULT_ACTION;
};
// DROP COLUMN action for ALTER TABLE statement // // <name> is the name of the column to drop. class ResolvedDropColumnAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_DROP_COLUMN_ACTION;
bool is_if_exists() const;
const std::string& name() const; };
// RENAME COLUMN action for ALTER TABLE statement. // // <name> is the name of the column to rename. // <new_name> is the new name of the column. // // RENAME COLUMN actions cannot be part of the same alter_action_list as any // other type of action. // Chains of RENAME COLUMN will be interpreted as a sequence of mutations. // The order of actions matters. Each <name> refers to a column name that // exists after all preceding renames have been applied. class ResolvedRenameColumnAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_RENAME_COLUMN_ACTION;
bool is_if_exists() const;
const std::string& name() const;
const std::string& new_name() const; };
// SET AS action for generic ALTER <entity_type> statement. // Exactly one of <entity_body_json>, <entity_body_text> should be non-empty. // // <entity_body_json> is a JSON literal to be interpreted by engine. // <entity_body_text> is a text literal to be interpreted by engine. class ResolvedSetAsAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_SET_AS_ACTION;
const std::string& entity_body_json() const;
const std::string& entity_body_text() const; };
// SET DEFAULT COLLATE clause for generic ALTER <entity_type> statement. // // <collation_name> specifies the new default collation specification for a // table or schema. Modifying the default collation for a table or schema // does not affect any existing columns or tables - the new default // collation only affects new tables and/or columns if applicable. Only // string literals are allowed for this field. class ResolvedSetCollateClause : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_SET_COLLATE_CLAUSE;
const ResolvedExpr* collation_name() const; };
// This statement: // ALTER TABLE [IF EXISTS] <name> SET OPTIONS (...) // // NOTE: This is deprecated in favor of ResolvedAlterTableStmt. // // <name_path> is a vector giving the identifier path in the table <name>. // <option_list> has engine-specific directives that specify how to // alter the metadata for this table. // <is_if_exists> silently ignore the "name_path does not exist" error. class ResolvedAlterTableSetOptionsStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_TABLE_SET_OPTIONS_STMT;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
bool is_if_exists() const; };
// This statement: RENAME <object_type> <old_name_path> TO <new_name_path>; // // <object_type> is an string identifier, // e.g., "TABLE", "VIEW", "INDEX", "FUNCTION", "TYPE", etc. // <old_name_path> is a vector giving the identifier path for the object to // be renamed. // <new_name_path> is a vector giving the identifier path for the object to // be renamed to. class ResolvedRenameStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_RENAME_STMT;
const std::string& object_type() const;
const std::vector<std::string>& old_name_path() const; int old_name_path_size() const; std::string old_name_path(int i) const;
const std::vector<std::string>& new_name_path() const; int new_name_path_size() const; std::string new_name_path(int i) const; };
// This statement: // CREATE [OR REPLACE] PRIVILEGE RESTRICTION [IF NOT EXISTS] // ON <column_privilege_list> ON <object_type> <name_path> // [RESTRICT TO (<restrictee_list>)] // // <column_privilege_list> is the name of the column privileges on which // to apply the restrictions. // <object_type> is a string identifier, which is currently either TABLE or // VIEW, which tells the engine how to look up the name. // <restrictee_list> is a list of users and groups the privilege restrictions // should apply to. Each restrictee is either a string // literal or a parameter. class ResolvedCreatePrivilegeRestrictionStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_PRIVILEGE_RESTRICTION_STMT;
const std::vector<std::unique_ptr<const ResolvedPrivilege>>& column_privilege_list() const; int column_privilege_list_size() const; const ResolvedPrivilege* column_privilege_list(int i) const;
const std::string& object_type() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& restrictee_list() const; int restrictee_list_size() const; const ResolvedExpr* restrictee_list(int i) const; };
// This statement: CREATE [OR REPLACE] ROW ACCESS POLICY [IF NOT EXISTS] // [<name>] ON <target_name_path> // [GRANT TO (<grantee_list>)] // FILTER USING (<predicate>); // // <create_mode> indicates if this was CREATE, CREATE OR REPLACE, or // CREATE IF NOT EXISTS. // <name> is the name of the row access policy to be created or an empty // string. // <target_name_path> is a vector giving the identifier path of the target // table. // <table_scan> is a TableScan for the target table, which is used during // resolving and validation. Consumers can use either the table // object inside it or target_name_path to reference the table. // <grantee_list> (DEPRECATED) is the list of user principals the policy // should apply to. // <grantee_expr_list> is the list of user principals the policy should // apply to, and may include parameters. // <predicate> is a boolean expression that selects the rows that are being // made visible. // <predicate_str> is the string form of the predicate. // // Only one of <grantee_list> or <grantee_expr_list> will be populated, // depending on whether or not the FEATURE_PARAMETERS_IN_GRANTEE_LIST // is enabled. The <grantee_list> is deprecated, and will be removed // along with the corresponding FEATURE once all engines have migrated to // use the <grantee_expr_list>. Once <grantee_expr_list> is the only // one, then it should be marked as NOT_IGNORABLE. class ResolvedCreateRowAccessPolicyStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_ROW_ACCESS_POLICY_STMT;
typedef ResolvedCreateStatement::CreateMode CreateMode;
ResolvedCreateStatement::CreateMode create_mode() const;
const std::string& name() const;
const std::vector<std::string>& target_name_path() const; int target_name_path_size() const; std::string target_name_path(int i) const;
const std::vector<std::string>& grantee_list() const; int grantee_list_size() const; std::string grantee_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& grantee_expr_list() const; int grantee_expr_list_size() const; const ResolvedExpr* grantee_expr_list(int i) const;
const ResolvedTableScan* table_scan() const;
const ResolvedExpr* predicate() const;
const std::string& predicate_str() const; };
// This statement: // DROP PRIVILEGE RESTRICTION [IF EXISTS] // ON <column_privilege_list> ON <object_type> <name_path> // // <column_privilege_list> is the name of the column privileges on which // the restrictions have been applied. // <object_type> is a string identifier, which is currently either TABLE or // VIEW, which tells the engine how to look up the name. // <name_path> is the name of the table the restrictions are scoped to. class ResolvedDropPrivilegeRestrictionStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_PRIVILEGE_RESTRICTION_STMT;
const std::string& object_type() const;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedPrivilege>>& column_privilege_list() const; int column_privilege_list_size() const; const ResolvedPrivilege* column_privilege_list(int i) const; };
// This statement: // DROP ROW ACCESS POLICY <name> ON <target_name_path>; or // DROP ALL ROW [ACCESS] POLICIES ON <target_name_path>; // // <is_drop_all> indicates that all policies should be dropped. // <is_if_exists> silently ignore the "policy <name> does not exist" error. // This is not allowed if is_drop_all is true. // <name> is the name of the row policy to be dropped or an empty string. // <target_name_path> is a vector giving the identifier path of the target // table. class ResolvedDropRowAccessPolicyStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_ROW_ACCESS_POLICY_STMT;
bool is_drop_all() const;
bool is_if_exists() const;
const std::string& name() const;
const std::vector<std::string>& target_name_path() const; int target_name_path_size() const; std::string target_name_path(int i) const; };
// DROP SEARCH|VECTOR INDEX [IF EXISTS] <name> [ON <table_name_path>]; // Note: DROP INDEX without SEARCH or VECTOR is currently resolved to a // generic ResolvedDropStmt. The index_type currently would never be // INDEX_DEFAULT. // // <name> is the name of the search index to be dropped. // <table_name_path> is a vector giving the identifier path of the target // table. class ResolvedDropIndexStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_INDEX_STMT;
typedef ResolvedDropIndexStmtEnums::IndexType IndexType; static const IndexType INDEX_DEFAULT = ResolvedDropIndexStmtEnums::INDEX_DEFAULT; static const IndexType INDEX_SEARCH = ResolvedDropIndexStmtEnums::INDEX_SEARCH; static const IndexType INDEX_VECTOR = ResolvedDropIndexStmtEnums::INDEX_VECTOR;
std::string GetIndexTypeString() const; static std::string IndexTypeToString(IndexType index_type);
bool is_if_exists() const;
const std::string& name() const;
const std::vector<std::string>& table_name_path() const; int table_name_path_size() const; std::string table_name_path(int i) const;
ResolvedDropIndexStmt::IndexType index_type() const; };
// GRANT TO action for ALTER ROW ACCESS POLICY statement // // <grantee_expr_list> is the list of grantees, and may include parameters. class ResolvedGrantToAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_GRANT_TO_ACTION;
const std::vector<std::unique_ptr<const ResolvedExpr>>& grantee_expr_list() const; int grantee_expr_list_size() const; const ResolvedExpr* grantee_expr_list(int i) const; };
// This action for ALTER PRIVILEGE RESTRICTION statement: // RESTRICT TO <restrictee_list> // // <restrictee_list> is a list of users and groups the privilege restrictions // should apply to. Each restrictee is either a string // literal or a parameter. class ResolvedRestrictToAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_RESTRICT_TO_ACTION;
const std::vector<std::unique_ptr<const ResolvedExpr>>& restrictee_list() const; int restrictee_list_size() const; const ResolvedExpr* restrictee_list(int i) const; };
// This action for ALTER PRIVILEGE RESTRICTION statement: // ADD [IF NOT EXISTS] <restrictee_list> // // <restrictee_list> is a list of users and groups the privilege restrictions // should apply to. Each restrictee is either a string // literal or a parameter. class ResolvedAddToRestricteeListAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_ADD_TO_RESTRICTEE_LIST_ACTION;
bool is_if_not_exists() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& restrictee_list() const; int restrictee_list_size() const; const ResolvedExpr* restrictee_list(int i) const; };
// This action for ALTER PRIVILEGE RESTRICTION statement: // REMOVE [IF EXISTS] <restrictee_list> // // <restrictee_list> is a list of users and groups the privilege restrictions // should apply to. Each restrictee is either a string // literal or a parameter. class ResolvedRemoveFromRestricteeListAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_REMOVE_FROM_RESTRICTEE_LIST_ACTION;
bool is_if_exists() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& restrictee_list() const; int restrictee_list_size() const; const ResolvedExpr* restrictee_list(int i) const; };
// FILTER USING action for ALTER ROW ACCESS POLICY statement // // <predicate> is a boolean expression that selects the rows that are being // made visible. // <predicate_str> is the string form of the predicate. class ResolvedFilterUsingAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_FILTER_USING_ACTION;
const ResolvedExpr* predicate() const;
const std::string& predicate_str() const; };
// REVOKE FROM action for ALTER ROW ACCESS POLICY statement // // <revokee_expr_list> is the list of revokees, and may include parameters. // <is_revoke_from_all> is a boolean indicating whether it was a REVOKE FROM // ALL statement. class ResolvedRevokeFromAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_REVOKE_FROM_ACTION;
const std::vector<std::unique_ptr<const ResolvedExpr>>& revokee_expr_list() const; int revokee_expr_list_size() const; const ResolvedExpr* revokee_expr_list(int i) const;
bool is_revoke_from_all() const; };
// RENAME TO action for ALTER ROW ACCESS POLICY statement // and ALTER TABLE statement // // <new_path> is the new name of the row access policy, // or the new path of the table. class ResolvedRenameToAction : public ResolvedAlterAction { static const ResolvedNodeKind TYPE = RESOLVED_RENAME_TO_ACTION;
const std::vector<std::string>& new_path() const; int new_path_size() const; std::string new_path(int i) const; };
// This statement: // ALTER PRIVILEGE RESTRICTION [IF EXISTS] // ON <column_privilege_list> ON <object_type> <name_path> // <alter_action_list> // // <column_privilege_list> is the name of the column privileges on which // the restrictions have been applied. // <object_type> is a string identifier, which is currently either TABLE or // VIEW, which tells the engine how to look up the name. class ResolvedAlterPrivilegeRestrictionStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_PRIVILEGE_RESTRICTION_STMT;
const std::vector<std::unique_ptr<const ResolvedPrivilege>>& column_privilege_list() const; int column_privilege_list_size() const; const ResolvedPrivilege* column_privilege_list(int i) const;
const std::string& object_type() const; };
// This statement: // ALTER ROW ACCESS POLICY [IF EXISTS] // <name> ON <name_path> // <alter_action_list> // // <name> is the name of the row access policy to be altered, scoped to the // table in the base <name_path>. // <table_scan> is a TableScan for the target table, which is used during // resolving and validation. Consumers can use either the table // object inside it or base <name_path> to reference the table. class ResolvedAlterRowAccessPolicyStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_ROW_ACCESS_POLICY_STMT;
const std::string& name() const;
const ResolvedTableScan* table_scan() const; };
// This statement: // ALTER ALL ROW ACCESS POLICIES ON <name_path> <alter_action_list> // // <name_path> is a vector giving the identifier path in the table name. // <alter_action_list> is a vector of actions to be done to the object. It // must have exactly one REVOKE FROM action with either // a non-empty grantee list or 'all'. // <table_scan> is a TableScan for the target table, which is used during // resolving and validation. Consumers can use either the table // object inside it or base <name_path> to reference the table. class ResolvedAlterAllRowAccessPoliciesStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_ALL_ROW_ACCESS_POLICIES_STMT;
const ResolvedTableScan* table_scan() const; };
// This statement creates a user-defined named constant: // CREATE [OR REPLACE] [TEMP | TEMPORARY | PUBLIC | PRIVATE] CONSTANT // [IF NOT EXISTS] <name_path> = <expression> // // <name_path> is the identifier path of the named constants. // <expr> is the expression that determines the type and the value of the // named constant. Note that <expr> need not be constant. Its value // is bound to the named constant which is then treated as // immutable. <expr> can be evaluated at the time this statement is // processed or later (lazy evaluation during query execution). class ResolvedCreateConstantStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_CONSTANT_STMT;
const ResolvedExpr* expr() const; };
// This statement creates a user-defined function: // CREATE [TEMP] FUNCTION [IF NOT EXISTS] <name_path> (<arg_list>) // [RETURNS <return_type>] [SQL SECURITY <sql_security>] // [<determinism_level>] // [[LANGUAGE <language>] [AS <code> | AS ( <function_expression> )] // | REMOTE [WITH CONNECTION <connection>]] // [OPTIONS (<option_list>)] // // <name_path> is the identifier path of the function. // <has_explicit_return_type> is true iff RETURNS clause is present. // <return_type> is the return type for the function, which can be any // valid ZetaSQL type, including ARRAY or STRUCT. It is inferred // from <function_expression> if not explicitly set. // TODO: Deprecate and remove this. The return type is // already specified by the <signature>. // <argument_name_list> The names of the function arguments. // <signature> is the FunctionSignature of the created function, with all // options. This can be used to create a Function to load into a // Catalog for future queries. // <is_aggregate> is true if this is an aggregate function. All arguments // are assumed to be aggregate input arguments that may vary for // every row. // <language> is the programming language used by the function. This field // is set to 'SQL' for SQL functions and 'REMOTE' for remote // functions and otherwise to the language name specified in the // LANGUAGE clause. This field is set to 'REMOTE' iff <is_remote> is // set to true. // <code> is a string literal that contains the function definition. Some // engines may allow this argument to be omitted for certain types // of external functions. This will always be set for SQL functions. // <aggregate_expression_list> is a list of SQL aggregate functions to // compute prior to computing the final <function_expression>. // See below. // <function_expression> is the resolved SQL expression invoked for the // function. This will be unset for external language functions. For // non-template SQL functions, this is a resolved representation of // the expression in <code>. // <option_list> has engine-specific directives for modifying functions. // <sql_security> is the declared security mode for the function. Values // include 'INVOKER', 'DEFINER'. // <determinism_level> is the declared determinism level of the function. // Values are 'DETERMINISTIC', 'NOT DETERMINISTIC', 'IMMUTABLE', // 'STABLE', 'VOLATILE'. // <is_remote> is true if this is an remote function. It is true iff its // <language> is set to 'REMOTE'. // <connection> is the identifier path of the connection object. It can be // only set when <is_remote> is true. // // Note that <function_expression> and <code> are both marked as IGNORABLE // because an engine could look at either one (but might not look at both). // An engine must look at one (and cannot ignore both, unless the function is // remote) to be semantically valid, but there is currently no way to enforce // that. // // For aggregate functions, <is_aggregate> will be true. // Aggregate functions will only occur if LanguageOptions has // FEATURE_CREATE_AGGREGATE_FUNCTION enabled. // // Arguments to aggregate functions must have // <FunctionSignatureArgumentTypeOptions::is_not_aggregate> true or false. // Non-aggregate arguments must be passed constant values only. // // For SQL aggregate functions, there will be both an // <aggregate_expression_list>, with aggregate expressions to compute first, // and then a final <function_expression> to compute on the results // of the aggregates. Each aggregate expression is a // ResolvedAggregateFunctionCall, and may reference any input arguments. // Each ResolvedComputedColumn in <aggregate_expression_list> gives the // aggregate expression a column id. The final <function_expression> can // reference these created aggregate columns, and any input arguments // with <argument_kind>=NOT_AGGREGATE. // // For example, with // CREATE TEMP FUNCTION my_avg(x) = (SUM(x) / COUNT(x)); // we would have an <aggregate_expression_list> with // agg1#1 := SUM(ResolvedArgumentRef(x)) // agg2#2 := COUNT(ResolvedArgumentRef(x)) // and a <function_expression> // ResolvedColumnRef(agg1#1) / ResolvedColumnRef(agg2#2) // // For example, with // CREATE FUNCTION scaled_avg(x,y NOT AGGREGATE) = (SUM(x) / COUNT(x) * y); // we would have an <aggregate_expression_list> with // agg1#1 := SUM(ResolvedArgumentRef(x)) // agg2#2 := COUNT(ResolvedArgumentRef(x)) // and a <function_expression> // ResolvedColumnRef(agg1#1) / ResolvedColumnRef(agg2#2) * ResolvedArgumentRef(y) // // When resolving a query that calls an aggregate UDF, the query will // have a ResolvedAggregateScan that invokes the UDF function. The engine // should remove the UDF aggregate function from the <aggregate_list>, and // instead compute the additional aggregates from the // UDF's <aggregate_expression_list>, and then add an additional Project // to compute the final <function_expression>, which should produce the // value for the original ResolvedAggregateScan's computed column for the // UDF. Some rewrites of the ResolvedColumn references inside the UDF will // be required. TODO If using ResolvedColumns makes this renaming // too complicated, we could switch to use ResolvedArgumentRefs, or // something new. class ResolvedCreateFunctionStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_FUNCTION_STMT;
// Converts the function's determinism level into a volatility. // Functions with unspecified/non deterministic/volatile // specifiers are considered volatile, functions with deterministic // and immutable specifiers are considered immutable and functions // with the stable specifier are considered stable. FunctionEnums::Volatility volatility() const;
bool has_explicit_return_type() const;
const Type* return_type() const;
const std::vector<std::string>& argument_name_list() const; int argument_name_list_size() const; std::string argument_name_list(int i) const;
const FunctionSignature& signature() const;
bool is_aggregate() const;
const std::string& language() const;
const std::string& code() const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& aggregate_expression_list() const; int aggregate_expression_list_size() const; const ResolvedComputedColumn* aggregate_expression_list(int i) const;
const ResolvedExpr* function_expression() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
ResolvedCreateStatement::SqlSecurity sql_security() const;
ResolvedCreateStatement::DeterminismLevel determinism_level() const;
bool is_remote() const;
const ResolvedConnection* connection() const; };
// This represents an argument definition, e.g. in a function's argument // list. // // <name> is the name of the argument; optional for DROP FUNCTION statements. // <type> is the type of the argument. // <argument_kind> indicates what kind of argument this is, including scalar // vs aggregate. NOT_AGGREGATE means this is a non-aggregate // argument in an aggregate function, which can only passed constant // values only. // // NOTE: Statements that create functions now include a FunctionSignature // directly, and an argument_name_list if applicable. These completely // describe the function signature, so the ResolvedArgumentDef list can // be considered unnecessary and deprecated. // TODO We could remove this node in the future. class ResolvedArgumentDef : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ARGUMENT_DEF;
typedef ResolvedArgumentDefEnums::ArgumentKind ArgumentKind; static const ArgumentKind SCALAR = ResolvedArgumentDefEnums::SCALAR; static const ArgumentKind AGGREGATE = ResolvedArgumentDefEnums::AGGREGATE; static const ArgumentKind NOT_AGGREGATE = ResolvedArgumentDefEnums::NOT_AGGREGATE;
const std::string& name() const;
const Type* type() const;
ResolvedArgumentDef::ArgumentKind argument_kind() const; };
// This represents an argument reference, e.g. in a function's body. // <name> is the name of the argument. // <argument_kind> is the ArgumentKind from the ResolvedArgumentDef. // For scalar functions, this is always SCALAR. // For aggregate functions, it can be AGGREGATE or NOT_AGGREGATE. // If NOT_AGGREGATE, then this is a non-aggregate argument // to an aggregate function, which has one constant value // for the entire function call (over all rows in all groups). // (This is copied from the ResolvedArgumentDef for convenience.) class ResolvedArgumentRef : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_ARGUMENT_REF;
typedef ResolvedArgumentDefEnums::ArgumentKind ArgumentKind; static const ArgumentKind SCALAR = ResolvedArgumentDefEnums::SCALAR; static const ArgumentKind AGGREGATE = ResolvedArgumentDefEnums::AGGREGATE; static const ArgumentKind NOT_AGGREGATE = ResolvedArgumentDefEnums::NOT_AGGREGATE;
const std::string& name() const;
ResolvedArgumentDef::ArgumentKind argument_kind() const; };
// This statement creates a user-defined table-valued function: // CREATE [TEMP] TABLE FUNCTION [IF NOT EXISTS] // <name_path> (<argument_name_list>) // [RETURNS <return_type>] // [OPTIONS (<option_list>)] // [LANGUAGE <language>] // [AS <code> | AS ( <query> )] // // <argument_name_list> contains the names of the function arguments. // <signature> is the FunctionSignature of the created function, with all // options. This can be used to create a Function to load into a // Catalog for future queries. // <option_list> has engine-specific directives for modifying functions. // <language> is the programming language used by the function. This field // is set to 'SQL' for SQL functions, to the language name specified // in the LANGUAGE clause if present, and to 'UNDECLARED' if both // the LANGUAGE clause and query are not present. // <code> is an optional string literal that contains the function // definition. Some engines may allow this argument to be omitted // for certain types of external functions. This will always be set // for SQL functions. // <query> is the SQL query invoked for the function. This will be unset // for external language functions. For non-templated SQL functions, // this is a resolved representation of the query in <code>. // <output_column_list> is the list of resolved output // columns returned by the table-valued function. // <is_value_table> If true, this function returns a value table. // Rather than producing rows with named columns, it produces // rows with a single unnamed value type. <output_column_list> will // have exactly one anonymous column (with no name). // See (broken link). // <sql_security> is the declared security mode for the function. Values // include 'INVOKER', 'DEFINER'. // <has_explicit_return_schema> is true iff RETURNS clause is present. // // ---------------------- // Table-Valued Functions // ---------------------- // // This is a statement to create a new table-valued function. Each // table-valued function returns an entire table as output instead of a // single scalar value. Table-valued functions can only be created if // LanguageOptions has FEATURE_CREATE_TABLE_FUNCTION enabled. // // For SQL table-valued functions that include a defined SQL body, the // <query> is non-NULL and contains the resolved SQL body. // In this case, <output_column_list> contains a list of the // output columns of the SQL body. The <query> uses // ResolvedArgumentRefs to refer to scalar arguments and // ResolvedRelationArgumentScans to refer to relation arguments. // // The table-valued function may include RETURNS TABLE<...> to explicitly // specify a schema for the output table returned by the function. If the // function declaration includes a SQL body, then the names and types of the // output columns of the corresponding <query> will have been // coerced to exactly match 1:1 with the names and types of the columns // specified in the RETURNS TABLE<...> section. // // When resolving a query that calls a table-valued function, the query will // have a ResolvedTVFScan that invokes the function. // // Value tables: If the function declaration includes a value-table // parameter, this is written as an argument of type "TABLE" where the table // contains a single anonymous column with a type but no name. In this case, // calls to the function may pass a (regular or value) table with a single // (named or unnamed) column for any of these parameters, and ZetaSQL // accepts these arguments as long as the column type matches. // // Similarly, if the CREATE TABLE FUNCTION statement includes a "RETURNS // TABLE" section with a single column with no name, then this defines a // value-table return type. The function then returns a value table as long // as the SQL body returns a single column whose type matches (independent of // whether the SQL body result is a value table or not, and whether the // returned column is named or unnamed). // // -------------------------------- // Templated Table-Valued Functions // -------------------------------- // // ZetaSQL supports table-valued function declarations with parameters of // type ANY TABLE. This type indicates that any schema is valid for tables // passed for this parameter. In this case: // // * the IsTemplated() method of the <signature> field returns true, // * the <output_column_list> field is empty, // * the <is_value_table> field is set to a default value of false (since // ZetaSQL cannot analyze the function body in the presence of templated // parameters, it is not possible to detect this property yet), // // TODO: Update this description once ZetaSQL supports more types // of templated function parameters. Currently only ANY TABLE is supported. class ResolvedCreateTableFunctionStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_TABLE_FUNCTION_STMT;
const std::vector<std::string>& argument_name_list() const; int argument_name_list_size() const; std::string argument_name_list(int i) const;
const FunctionSignature& signature() const;
bool has_explicit_return_schema() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::string& language() const;
const std::string& code() const;
const ResolvedScan* query() const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
bool is_value_table() const;
ResolvedCreateStatement::SqlSecurity sql_security() const; };
// This represents a relation argument reference in a table-valued function's // body. The 'column_list' of this ResolvedScan includes column names from // the relation argument in the table-valued function signature. class ResolvedRelationArgumentScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_RELATION_ARGUMENT_SCAN;
// This is the name of the relation argument for the table-valued // function. It is used to match this relation argument reference in // a TVF SQL function body with one of possibly several relation // arguments in the TVF call. const std::string& name() const;
// If true, the result of this query is a value table. Rather than // producing rows with named columns, it produces rows with a single // unnamed value type. See (broken link). bool is_value_table() const; };
// This statement: [ (<arg_list>) ]; // // <arg_list> is an optional list of parameters. If given, each parameter // may consist of a type, or a name and a type. // // NOTE: This can be considered deprecated in favor of the FunctionSignature // stored directly in the statement. // // NOTE: ResolvedArgumentList is not related to the ResolvedArgument class, // which just exists to organize node classes. class ResolvedArgumentList : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_ARGUMENT_LIST;
const std::vector<std::unique_ptr<const ResolvedArgumentDef>>& arg_list() const; int arg_list_size() const; const ResolvedArgumentDef* arg_list(int i) const; };
// This wrapper is used for an optional FunctionSignature. class ResolvedFunctionSignatureHolder : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_FUNCTION_SIGNATURE_HOLDER;
const FunctionSignature& signature() const; };
// This statement: DROP FUNCTION [IF EXISTS] <name_path> // [ (<arguments>) ]; // // <is_if_exists> silently ignore the "name_path does not exist" error. // <name_path> is the identifier path of the function to be dropped. // <arguments> is an optional list of parameters. If given, each parameter // may consist of a type, or a name and a type. The name is // disregarded, and is allowed to permit copy-paste from CREATE // FUNCTION statements. // <signature> is the signature of the dropped function. Argument names and // argument options are ignored because only the types matter // for matching signatures in DROP FUNCTION. The return type // in this signature will always be <void>, since return type // is ignored when matching signatures for DROP. // TODO <arguments> could be deprecated in favor of this. class ResolvedDropFunctionStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_FUNCTION_STMT;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
// NOTE: arguments for DROP FUNCTION statements are matched only on // type; names for any arguments in ResolvedArgumentList will be set // to the empty string irrespective of whether or not argument names // were given in the DROP FUNCTION statement. const ResolvedArgumentList* arguments() const;
// NOTE: arguments for DROP FUNCTION statements are matched only on // type; names are irrelevant, so no argument names are saved to use // with this signature. Additionally, the return type will always be // <void>, since return types are ignored for DROP FUNCTION. const ResolvedFunctionSignatureHolder* signature() const; };
// This statement: DROP TABLE FUNCTION [IF EXISTS] <name_path>; // // <is_if_exists> silently ignore the "name_path does not exist" error. // <name_path> is the identifier path of the function to be dropped. class ResolvedDropTableFunctionStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_DROP_TABLE_FUNCTION_STMT;
bool is_if_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const; };
// This statement: CALL <procedure>; // // <procedure> Procedure to call. // <signature> Resolved FunctionSignature for this procedure. // <argument_list> Procedure arguments. class ResolvedCallStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_CALL_STMT;
const Procedure* procedure() const;
const FunctionSignature& signature() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& argument_list() const; int argument_list_size() const; const ResolvedExpr* argument_list(int i) const; };
// This statement: IMPORT <import_kind> // [<name_path> [AS|INTO <alias_path>] // |<file_path>] // [<option_list>]; // // <import_kind> The type of the object, currently supports MODULE and PROTO. // <name_path> The identifier path of the object to import, e.g., foo.bar, // used in IMPORT MODULE statement. // <file_path> The file path of the object to import, e.g., "file.proto", // used in IMPORT PROTO statement. // <alias_path> The AS alias path for the object. // <into_alias_path> The INTO alias path for the object. // <option_list> Engine-specific directives for the import. // // Either <name_path> or <file_path> will be populated but not both. // <name_path> will be populated for IMPORT MODULE. // <file_path> will be populated for IMPORT PROTO. // // At most one of <alias_path> or <into_alias_path> will be populated. // <alias_path> may be populated for IMPORT MODULE. // <into_alias_path> may be populated for IMPORT PROTO. // // IMPORT MODULE and IMPORT PROTO both support options. // // See (broken link) for more detail on IMPORT MODULE. // See (broken link) for more detail on IMPORT PROTO. class ResolvedImportStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_IMPORT_STMT;
typedef ResolvedImportStmtEnums::ImportKind ImportKind; static const ImportKind MODULE = ResolvedImportStmtEnums::MODULE; static const ImportKind PROTO = ResolvedImportStmtEnums::PROTO; static const ImportKind ImportKind__switch_must_have_a_default = ResolvedImportStmtEnums::ImportKind__switch_must_have_a_default;
std::string GetImportKindString() const; static std::string ImportKindToString(ImportKind kind);
ResolvedImportStmt::ImportKind import_kind() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::string& file_path() const;
const std::vector<std::string>& alias_path() const; int alias_path_size() const; std::string alias_path(int i) const;
const std::vector<std::string>& into_alias_path() const; int into_alias_path_size() const; std::string into_alias_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: MODULE <name_path> [<option_list>]; // // <name_path> is the identifier path of the module. // <option_list> Engine-specific directives for the module statement. // // See (broken link) for more detail on MODULEs. class ResolvedModuleStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_MODULE_STMT;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This represents a HAVING MAX or HAVING MIN modifier in an aggregate // expression. If an aggregate has arguments (x HAVING {MAX/MIN} y), // the aggregate will be computed over only the x values in the rows with the // maximal/minimal values of y. // // <kind> the MAX/MIN kind of this HAVING // <having_expr> the HAVING expression (y in the above example) class ResolvedAggregateHavingModifier : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_AGGREGATE_HAVING_MODIFIER;
typedef ResolvedAggregateHavingModifierEnums::HavingModifierKind HavingModifierKind; static const HavingModifierKind INVALID = ResolvedAggregateHavingModifierEnums::INVALID; static const HavingModifierKind MAX = ResolvedAggregateHavingModifierEnums::MAX; static const HavingModifierKind MIN = ResolvedAggregateHavingModifierEnums::MIN;
std::string GetHavingModifierKindString() const; static std::string HavingModifierKindToString(HavingModifierKind kind);
ResolvedAggregateHavingModifier::HavingModifierKind kind() const;
const ResolvedExpr* having_expr() const; };
// This statement: // CREATE MATERIALIZED VIEW <name> [(...)] [PARTITION BY expr, ...] // [CLUSTER BY expr, ...] [OPTIONS (...)] // {AS SELECT ... | AS REPLICA OF ...} // // <partition_by_list> specifies the partitioning expressions for the // materialized view. // <cluster_by_list> specifies the clustering expressions for the // materialized view. class ResolvedCreateMaterializedViewStmt : public ResolvedCreateViewBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_MATERIALIZED_VIEW_STMT;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& cluster_by_list() const; int cluster_by_list_size() const; const ResolvedExpr* cluster_by_list(int i) const;
const ResolvedScan* replica_source() const; };
// This statement creates an APPROX VIEW: // CREATE APPROX VIEW <name> [(...)] [OPTIONS (...)] AS SELECT ... // // An APPROX VIEW provides approximate results from the view query, as // opposed to a regular view which returns exact results from its view query. // APPROX VIEW is a generic operator whose behavior is implementation-defined // based on the OPTIONS and query engines. // // See (broken link) for more details on APPROX VIEW. class ResolvedCreateApproxViewStmt : public ResolvedCreateViewBase { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_APPROX_VIEW_STMT;
};
// This statement creates a user-defined procedure: // CREATE [OR REPLACE] [TEMP] PROCEDURE [IF NOT EXISTS] <name_path> // (<arg_list>) [EXTERNAL SECURITY <external_security>] // [WITH CONNECTION <connection>] [OPTIONS (<option_list>)] // [BEGIN <procedure_body> END | LANGUAGE <language> [AS <code>]]; // // <name_path> is the identifier path of the procedure. // <argument_name_list> The names of the function arguments. // <signature> is the FunctionSignature of the created procedure, with all // options. This can be used to create a procedure to load into a // Catalog for future queries. // <external_security> is the external security mode for the created // procedure. Values include 'INVOKER', 'DEFINER'. // <connection> is the identifier path of the connection object. // <option_list> has engine-specific directives for modifying procedures. // <procedure_body> is a string literal that contains the SQL procedure // body. It includes everything from the BEGIN keyword to the END // keyword, inclusive. This will always be set for SQL procedures // and unset for external language procedures. // // The resolver will perform some basic validation on the procedure // body, for example, verifying that DECLARE statements are in the // proper position, and that variables are not declared more than // once, but any validation that requires the catalog (including // generating resolved tree nodes for individual statements) is // deferred until the procedure is actually called. This deferral // makes it possible to define a procedure which references a table // or routine that does not yet exist, so long as the entity is // created before the procedure is called. // <language> is the programming language used by the procedure. This field // is set to the language name specified in the LANGUAGE clause. // Exactly one of <procedure_body> and <language> must be set. // <code> is a string literal that contains the external language procedure // definition. It is allowed only if <language> is set. class ResolvedCreateProcedureStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_PROCEDURE_STMT;
const std::vector<std::string>& argument_name_list() const; int argument_name_list_size() const; std::string argument_name_list(int i) const;
const FunctionSignature& signature() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::string& procedure_body() const;
const ResolvedConnection* connection() const;
const std::string& language() const;
const std::string& code() const;
ResolvedCreateStatement::SqlSecurity external_security() const; };
// An argument for an EXECUTE IMMEDIATE's USING clause. // // <name> an optional name for this expression // <expression> the expression's value class ResolvedExecuteImmediateArgument : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_EXECUTE_IMMEDIATE_ARGUMENT;
const std::string& name() const;
const ResolvedExpr* expression() const; };
// An EXECUTE IMMEDIATE statement // EXECUTE IMMEDIATE <sql> [<into_clause>] [<using_clause>] // // <sql> a string expression indicating a SQL statement to be dynamically // executed // <into_identifier_list> the identifiers whose values should be set. // Identifiers should not be repeated in the list. // <using_argument_list> a list of arguments to supply for dynamic SQL. // The arguments should either be all named or all unnamed, and // arguments should not be repeated in the list. class ResolvedExecuteImmediateStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_EXECUTE_IMMEDIATE_STMT;
const ResolvedExpr* sql() const;
const std::vector<std::string>& into_identifier_list() const; int into_identifier_list_size() const; std::string into_identifier_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExecuteImmediateArgument>>& using_argument_list() const; int using_argument_list_size() const; const ResolvedExecuteImmediateArgument* using_argument_list(int i) const; };
// An assignment of a value to another value. class ResolvedAssignmentStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ASSIGNMENT_STMT;
// Target of the assignment. Currently, this will be // either ResolvedSystemVariable, or a chain of ResolveGetField // operations around it. const ResolvedExpr* target() const;
// Value to assign into the target. This will always be // the same type as the target. const ResolvedExpr* expr() const; };
// (broken link) // This statement: // CREATE [OR REPLACE] <entity_type> [IF NOT EXISTS] <path_expression> // [OPTIONS <option_list>] // [AS <entity_body_json>]; // // At most one of <entity_body_json>, <entity_body_text> can be non-empty. // // <entity_type> engine-specific entity type to be created. // <entity_body_json> is a JSON literal to be interpreted by engine. // <entity_body_text> is a text literal to be interpreted by engine. // <option_list> has engine-specific directives for how to // create this entity. class ResolvedCreateEntityStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_ENTITY_STMT;
const std::string& entity_type() const;
const std::string& entity_body_json() const;
const std::string& entity_body_text() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// (broken link) // This statement: // ALTER <entity_type> [IF EXISTS] <path_expression> // <generic_alter_action>, ... // // <entity_type> engine-specific entity type to be altered. class ResolvedAlterEntityStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_ENTITY_STMT;
const std::string& entity_type() const; };
// Represents a column produced by aggregating a particular pivot // expression over a subset of the input for which the FOR expression // matches a particular pivot value. This aggregation is further // broken up by the enclosing ResolvedPivotScan's groupby columns, // with each distinct value of the groupby columns producing a // separate row in the output. // // In any pivot column, 'c', // 'c' is produced by aggregating pivot expression // <pivot_expr_list[c.pivot_expr_index]> // over input rows such that // <for_expr> IS NOT DISTINCT FROM // <pivot_value_list[c.pivot_value_index]> class ResolvedPivotColumn : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_PIVOT_COLUMN;
// The output column used to represent the result of the pivot. const ResolvedColumn& column() const;
// Specifies the index of the pivot expression // within the enclosing ResolvedPivotScan's <pivot_expr_list> used to // determine the result of the column. int pivot_expr_index() const;
// Specifies the index of the pivot value within // the enclosing ResolvedPivotScan's <pivot_value_list> used to // determine the subset of input rows the pivot expression should be // evaluated over. int pivot_value_index() const; };
// A scan produced by the following SQL fragment: // <input_scan> PIVOT(... FOR ... IN (...)) // // The column list of this scan consists of a subset of columns from // <group_by_column_list> and <pivot_column_list>. // // Details: (broken link) class ResolvedPivotScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_PIVOT_SCAN;
// Input to the PIVOT clause const ResolvedScan* input_scan() const;
// The columns from <input_scan> to group by. // The output will have one row for each distinct combination of // values for all grouping columns. (There will be one output row if // this list is empty.) // // Each element is a ResolvedComputedColumn. The expression is always // a ResolvedColumnRef that references a column from <input_scan>. const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& group_by_list() const; int group_by_list_size() const; const ResolvedComputedColumn* group_by_list(int i) const;
// Pivot expressions which aggregate over the subset of <input_scan> // where <for_expr> matches each value in <pivot_value_list>, plus // all columns in <group_by_list>. const std::vector<std::unique_ptr<const ResolvedExpr>>& pivot_expr_list() const; int pivot_expr_list_size() const; const ResolvedExpr* pivot_expr_list(int i) const;
// Expression following the FOR keyword, to be evaluated over each row // in <input_scan>. This value is compared with each value in // <pivot_value_list> to determine which columns the aggregation // results of <pivot_expr_list> should go to. const ResolvedExpr* for_expr() const;
// A list of pivot values within the IN list, to be compared against // the result of <for_expr> for each row in the input table. Each // pivot value generates a distinct column in the output for each // pivot expression, representing the result of the corresponding // pivot expression over the subset of input where <for_expr> matches // this pivot value. // // All pivot values in this list must have the same type as // <for_expr> and must be constant. const std::vector<std::unique_ptr<const ResolvedExpr>>& pivot_value_list() const; int pivot_value_list_size() const; const ResolvedExpr* pivot_value_list(int i) const;
// List of columns created to store the output pivot columns. // Each is computed using one of pivot_expr_list and one of // pivot_value_list. const std::vector<std::unique_ptr<const ResolvedPivotColumn>>& pivot_column_list() const; int pivot_column_list_size() const; const ResolvedPivotColumn* pivot_column_list(int i) const; };
// Represents the returning clause on a DML statement. class ResolvedReturningClause : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_RETURNING_CLAUSE;
// Specifies the columns in the returned output row with column // names. It can reference columns from the target table scan // <table_scan> from INSERT/DELETE/UPDATE statements. Also this list // can have columns computed in the <expr_list> or an <action_column> // as the last column. const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
// Represents the WITH ACTION column in <output_column_list> as a // string type column. There are four valid values for this action // column: "INSERT", "REPLACE", "UPDATE", and "DELETE". const ResolvedColumnHolder* action_column() const;
// Represents the computed expressions so they can be referenced in // <output_column_list>. Worth noting, it can't see <action_column> // and can only access columns from the DML statement target table. const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& expr_list() const; int expr_list_size() const; const ResolvedComputedColumn* expr_list(int i) const; };
// A column group in the UNPIVOT IN clause. // // Example: // 'a' in 'UNPIVOT(x FOR z IN (a , b , c))' // or '(a , b)' in 'UNPIVOT((x , y) FOR z IN ((a , b), (c , d))' class ResolvedUnpivotArg : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_UNPIVOT_ARG;
// A list of columns referencing an output column of the <input_scan> // of ResolvedUnpivotScan. The size of this vector is // the same as <value_column_list>. const std::vector<std::unique_ptr<const ResolvedColumnRef>>& column_list() const; int column_list_size() const; const ResolvedColumnRef* column_list(int i) const; };
// A scan produced by the following SQL fragment: // <input_scan> UNPIVOT(<value_column_list> // FOR <label_column> // IN (<unpivot_arg_list>)) // // size of (<unpivot_arg_list>[i], i.e. column groups inside // <unpivot_arg_list>) // = size of (<value_column_list>) // = Let's say num_value_columns // // size of (<unpivot_arg_list>) // = size of (<label_list>) // = Let's say num_args // // Here is how output rows are generated -- // for each input row : // for arg_index = 0 .. (num_args - 1) : // output a row with the original columns from <input_scan> // // plus // arg = <unpivot_arg_list>[arg_index] // for value_column_index = 0 .. (num_value_columns - 1) : // output_value_column = <value_column_list>[value_column_index] // input_arg_column = arg [value_column_index] // output_value_column = input_arg_column // // plus // <label_column> = <label_list>[arg_index] // // // Hence the total number of rows generated in the output = // input rows * size of <unpivot_arg_list> // // For all column groups inside <unpivot_arg_list>, datatype of // columns at the same position in the vector must be equivalent, and // also equivalent to the datatype of the column at the same position in // <value_column_list>. // I.e. in the above pseudocode, datatypes must be equivalent for // output_value_column and input_arg_column. // Datatype of <label_column> must be the same as datatype of // <label_list> and can be string or int64. // // Details: (broken link) class ResolvedUnpivotScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_UNPIVOT_SCAN;
const ResolvedScan* input_scan() const;
// This is a list of one or more new columns added by UNPIVOT. // These new column(s) store the value of input columns that are in // the UNPIVOT IN clause. const std::vector<ResolvedColumn>& value_column_list() const; int value_column_list_size() const; ResolvedColumn value_column_list(int i) const;
// This is a new column added in the output for storing labels for // input columns groups that are present in the IN clause. Its // values are taken from <label_list>. const ResolvedColumn& label_column() const;
// String or integer literal for each column group in // <unpivot_arg_list>. const std::vector<std::unique_ptr<const ResolvedLiteral>>& label_list() const; int label_list_size() const; const ResolvedLiteral* label_list(int i) const;
// The list of groups of columns in the UNPIVOT IN list. Each group // contains references to the output columns of <input_scan> of the // ResolvedUnpivotScan. The values of these columns are stored in the // new <value_column_list> and the column group labels/names // in the <label_column>. const std::vector<std::unique_ptr<const ResolvedUnpivotArg>>& unpivot_arg_list() const; int unpivot_arg_list_size() const; const ResolvedUnpivotArg* unpivot_arg_list(int i) const;
// The columns from <input_scan> that are not unpivoted in UNPIVOT // IN clause. Columns in <projected_input_column_list> and // <unpivot_arg_list> are mutually exclusive and their union is the // complete set of columns in the unpivot input-source. // // The expression of each ResolvedComputedColumn is a // ResolvedColumnRef that references a column from <input_scan>. const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& projected_input_column_list() const; int projected_input_column_list_size() const; const ResolvedComputedColumn* projected_input_column_list(int i) const;
// Whether we need to include the rows from output where ALL columns // from <value_column_list> are null. bool include_nulls() const; };
// A scan for row pattern recognition (the MATCH_RECOGNIZE clause). // See (broken link) for details. class ResolvedMatchRecognizeScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_SCAN;
typedef ResolvedMatchRecognizeScanEnums::AfterMatchSkipMode AfterMatchSkipMode; static const AfterMatchSkipMode AFTER_MATCH_SKIP_MODE_UNSPECIFIED = ResolvedMatchRecognizeScanEnums::AFTER_MATCH_SKIP_MODE_UNSPECIFIED; static const AfterMatchSkipMode END_OF_MATCH = ResolvedMatchRecognizeScanEnums::END_OF_MATCH; static const AfterMatchSkipMode NEXT_ROW = ResolvedMatchRecognizeScanEnums::NEXT_ROW;
const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
// Partitioning columns for this pattern matching operation. // Pattern matching occurs on individual partitions, just like // windowing functions. // // If this list is empty, the whole input table is a single // partition. // // Partitioning columns are always part of the scan's output columns, // along with the measures. const ResolvedWindowPartitioning* partition_by() const;
// The ordering list can never be empty. // Collation & hints supported, just like in window specification. // However, ordinals are not allowed. const ResolvedWindowOrdering* order_by() const;
// The pattern variable definitions. This list is never empty, and // variable names must be unique (ignoring case). const std::vector<std::unique_ptr<const ResolvedMatchRecognizeVariableDefinition>>& pattern_variable_definition_list() const; int pattern_variable_definition_list_size() const; const ResolvedMatchRecognizeVariableDefinition* pattern_variable_definition_list(int i) const;
// The pattern expression to use when matching rows. All row pattern // variables referenced in this expression must be defined in // pattern_variable_definition_list. const ResolvedMatchRecognizePatternExpr* pattern() const;
// Represents the AFTER MATCH SKIP clause. Can never be // 'UNSPECIFIED'. // See (broken link) for details. ResolvedMatchRecognizeScan::AfterMatchSkipMode after_match_skip_mode() const;
// The outputs as defined in the MEASURES clause. const std::vector<std::unique_ptr<const ResolvedMeasureGroup>>& measure_group_list() const; int measure_group_list_size() const; const ResolvedMeasureGroup* measure_group_list(int i) const; };
// Must be contained directly in a ResolvedMatchRecognizeScan. Groups all // aggregations ranging over the same pattern variable in the MEASURES clause // a MATCH_RECOGNIZE. This is a similar concept to // ResolvedAnalyticFunctionGroup. // // For example, for this MEASURES clause: // MEASURES max(A.x) - min(b.x - b.y), sum(c.x) - avg(x) - min(A.z) // There will be 4 groups: // 1. (A, [max(A.x), min(A.z)]) // 2. (b, [min(b.x - b.y)]) // 3. (c, sum(c.x)) // 4. [avg(x)] universal group. // // The last group is the universal group. It ranges over all rows in the // match. There can only be one such group in the ResolvedMatchRecognizeScan. class ResolvedMeasureGroup : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_MEASURE_GROUP;
// Nullptr for the universal group, or name of the referenced pattern // variable, in which case this must match the name exactly as listed // in the
pattern_variable_definition_list
of the enclosing // ResolvedMatchRecognizeScan. const ResolvedMatchRecognizePatternVariableRef* pattern_variable_ref() const;
// Aggregations that are part of this group, all ranging over rows // assigned to the designated pattern variable. If this is the // universal group, the aggregations range over all rows in the // match. // This list is never empty. const std::vector<std::unique_ptr<const ResolvedComputedColumnBase>>& aggregate_list() const; int aggregate_list_size() const; const ResolvedComputedColumnBase* aggregate_list(int i) const; };
// Represents a row pattern variable definition. // This node can only be used under ResolvedMatchRecognizeScan. class ResolvedMatchRecognizeVariableDefinition : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_VARIABLE_DEFINITION;
// The name of the pattern variable. The name cannot be // empty and must be unique (case-insensitively) within this // ResolvedMatchRecognizeScan, but every place this name is // referenced elsewhere (e.g. variable ref), it will be identical, // including case. const std::string& name() const;
// Predicate for this pattern variable. This is a BOOL expression to // compute whether or not a given row can be qualified for this // pattern variable. const ResolvedExpr* predicate() const; };
// Abstract class for row pattern expression.
class ResolvedMatchRecognizePatternExpr : public ResolvedArgument {
};
// Represents an empty pattern. // * An empty pattern consumes zero rows and always matches successfully. // * An empty pattern on zero input rows will not produce a match, since // matches are just searched for at each distinct start row. class ResolvedMatchRecognizePatternEmpty : public ResolvedMatchRecognizePatternExpr { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_PATTERN_EMPTY;
};
// Represents a start or end anchor (^ or $, respectively.) // * A START anchor requires the match to be at the start of the partition. // * An END anchor requires the match to be at the end of the partition. // * Just like the empty pattern, anchors consume zero rows and do not // produce matches on zero input rows. class ResolvedMatchRecognizePatternAnchor : public ResolvedMatchRecognizePatternExpr { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_PATTERN_ANCHOR;
typedef ResolvedMatchRecognizePatternAnchorEnums::Mode Mode; static const Mode MODE_UNSPECIFIED = ResolvedMatchRecognizePatternAnchorEnums::MODE_UNSPECIFIED; static const Mode START = ResolvedMatchRecognizePatternAnchorEnums::START; static const Mode END = ResolvedMatchRecognizePatternAnchorEnums::END;
ResolvedMatchRecognizePatternAnchor::Mode mode() const; };
// A reference to a row pattern variable. class ResolvedMatchRecognizePatternVariableRef : public ResolvedMatchRecognizePatternExpr { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_PATTERN_VARIABLE_REF;
// Name of the referenced pattern variable. This must match the // the name exactly as listed in the //
pattern_variable_definition_list
of the enclosing // ResolvedMatchRecognizeScan. const std::string& name() const; };
// An N-ary operation over row pattern sub-expressions. class ResolvedMatchRecognizePatternOperation : public ResolvedMatchRecognizePatternExpr { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_PATTERN_OPERATION;
typedef ResolvedMatchRecognizePatternOperationEnums::MatchRecognizePatternOperationType MatchRecognizePatternOperationType; static const MatchRecognizePatternOperationType OPERATION_TYPE_UNSPECIFIED = ResolvedMatchRecognizePatternOperationEnums::OPERATION_TYPE_UNSPECIFIED; static const MatchRecognizePatternOperationType CONCAT = ResolvedMatchRecognizePatternOperationEnums::CONCAT; static const MatchRecognizePatternOperationType ALTERNATE = ResolvedMatchRecognizePatternOperationEnums::ALTERNATE;
ResolvedMatchRecognizePatternOperation::MatchRecognizePatternOperationType op_type() const;
const std::vector<std::unique_ptr<const ResolvedMatchRecognizePatternExpr>>& operand_list() const; int operand_list_size() const; const ResolvedMatchRecognizePatternExpr* operand_list(int i) const; };
// Quantification on a row pattern expression, e.g. A+, A?, A{n, m}, ..etc. // Regardless of the original syntax used, e.g. a symbol or fixed- or custom- // bounded, e.g. A+, A{3} or A{1,2}?, the quantifier is represented by the // lower and upper bounds, and a boolean indicating whether the quantifier is // reluctant or not. // // The upper and lower bounds are represented as ResolvedExprs, but currently // must be literals or parameters. Their type is INT64. // // It is a runtime error if the upper bound is present and is smaller than // the lower bound. // Any pattern expression can be quantified, including already-quantified // pattern expressions, For example, the pattern expression // ( (A|B){2} ) {2,4} // specifies either 2, 3 or 4 *pairs* of rows, each matches A or B. class ResolvedMatchRecognizePatternQuantification : public ResolvedMatchRecognizePatternExpr { static const ResolvedNodeKind TYPE = RESOLVED_MATCH_RECOGNIZE_PATTERN_QUANTIFICATION;
// The sub-pattern to be repeated according to this quantifier. // Cannot be nullptr. const ResolvedMatchRecognizePatternExpr* operand() const;
// Lower bound of the quantification. Cannot be nullptr. const ResolvedExpr* lower_bound() const;
// The upper bound of the quantification. Can be nullptr, in which // case it means there is no upper bound (i.e., unlimited). const ResolvedExpr* upper_bound() const;
// If true, this quantifier is reluctant. If false, it is greedy. bool is_reluctant() const; };
// CLONE DATA INTO <table_name> FROM ... // // <target_table> the table to clone data into. Cannot be value table. // <clone_from> The source table(s) to clone data from. // For a single table, the scan is TableScan, with an optional // for_system_time_expr; // If WHERE clause is present, the Scan is wrapped inside // ResolvedFilterScan; // When multiple sources are present, they are UNION'ed together // in a ResolvedSetOperationScan. // // Constraints: // The target_table must not be the same as any source table, // and two sources cannot refer to the same table. // All source tables and target table must have equal number // of columns, with positionally identical column names and // types. // Cannot be value table. class ResolvedCloneDataStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_CLONE_DATA_STMT;
const ResolvedTableScan* target_table() const;
const ResolvedScan* clone_from() const; };
// Identifies the <table> and <column_index_list> (which can be empty) that // are targets of the ANALYZE statement. // // <column_index_list> This list identifies the ordinals of columns to be // analyzed in the <table>'s column list. class ResolvedTableAndColumnInfo : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_TABLE_AND_COLUMN_INFO;
const Table* table() const;
const std::vector<int>& column_index_list() const; int column_index_list_size() const; int column_index_list(int i) const; };
// This represents the ANALYZE statement: // ANALYZE [OPTIONS (<option_list>)] [<table_and_column_index_list> [, ...]]; // // <option_list> is a list of options for ANALYZE. // // <table_and_column_info_list> identifies a list of tables along with their // related columns that are the target of ANALYZE. class ResolvedAnalyzeStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_ANALYZE_STMT;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedTableAndColumnInfo>>& table_and_column_index_list() const; int table_and_column_index_list_size() const; const ResolvedTableAndColumnInfo* table_and_column_index_list(int i) const; };
// Indicates that the LOAD DATA statement will load to or overwrite the // selected partitions: // [OVERWRITE] PARTITIONS (<filter>) class ResolvedAuxLoadDataPartitionFilter : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_AUX_LOAD_DATA_PARTITION_FILTER;
// Expression to find the partitions to load. // Scan rows from source file, and fail the query if filter // evaluates some rows to false. // <filter> is always of type bool. // When this expression produces NULL, the query should fail. const ResolvedExpr* filter() const;
// Indicates whether the load data will append to or overwrite the // selected partition. bool is_overwrite() const; };
// LOAD DATA {OVERWRITE|INTO} [{TEMP|TEMPORARY} TABLE] <table_name> // [[OVERWRITE] PARTITIONS(...)] ... // FROM FILES ... // This statement loads an external file to a new or existing table. // See (broken link). // // <insertion_mode> either OVERWRITE or APPEND (INTO) the destination table. // <is_temp_table> True if the destination table should be a temporary table. // Otherwise, the destination table should be a persistent table. // <name_path> the table to load data into. // <output_column_list> the list of visible columns of the destination table. // If <column_definition_list> is explicitly specified: // <output_column_list> = // <column_definition_list> + <with_partition_columns> // Or if the table already exists: // <output_column_list> = <name_path>.columns // Last, if the table doesn't exist and <column_definition_list> isn't // explicitly specified: // <output_column_list> = detected-columns + <with_partition_columns> // <column_definition_list> If not empty, the explicit columns of the // destination table. Must be coerciable from the source file's fields. // // When the destination table doesn't already exist, it will be created // with these columns (plus the additional columns from WITH PARTITION // COLUMNS subclause); otherwise, the destination table's schema must // match the explicit columns by both name and type. // <pseudo_column_list> is a list of pseudo-columns expected to be present on // the created table (provided by AnalyzerOptions::SetDdlPseudoColumns*). // These can be referenced in expressions in <partition_by_list> and // <cluster_by_list>. // <primary_key> specifies the PRIMARY KEY constraint on the table. It is // nullptr when no PRIMARY KEY is specified. // If specified, and the table already exists, the primary_key is // required to be the same as that of the existing. // <foreign_key_list> specifies the FOREIGN KEY constraints on the table. // If specified, and the table already exists, the foreign keys are // required to be the same as that of the existing. // <check_constraint_list> specifies the ABSL_CHECK constraints on the table. // If specified, and the table already exists, the constraints are // required to be the same as that of the existing. // <partition_by_list> The list of columns to partition the destination // table. Similar to <column_definition_list>, it must match the // destination table's partitioning spec if it already exists. // <cluster_by_list> The list of columns to cluster the destination // table. Similar to <column_definition_list>, it must match the // destination table's partitioning spec if it already exists. // <partition_filter> specifies the destination partition selections and // whether load to or overwrite the selected partitions. // <option_list> the options list describing the destination table. // If the destination doesn't already exist, it will be created with // these options; otherwise it must match the existing destination // table's options. // <with_partition_columns> The columns decoded from partitioned source // files. If the destination table doesn't already exist, these columns // will be implicitly added to the destination table's schema; otherwise // the destination table must already have these columns // (matching by both names and types). // // The hive partition columns from the source file do not automatically // partition the destination table. To apply the partition, the // <partition_by_list> must be specified. // <connection> optional connection reference for accessing files. // <from_files_option_list> the options list describing the source file(s). class ResolvedAuxLoadDataStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_AUX_LOAD_DATA_STMT;
typedef ResolvedAuxLoadDataStmtEnums::InsertionMode InsertionMode; static const InsertionMode NONE = ResolvedAuxLoadDataStmtEnums::NONE; static const InsertionMode APPEND = ResolvedAuxLoadDataStmtEnums::APPEND; static const InsertionMode OVERWRITE = ResolvedAuxLoadDataStmtEnums::OVERWRITE;
ResolvedAuxLoadDataStmt::InsertionMode insertion_mode() const;
bool is_temp_table() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const ResolvedAuxLoadDataPartitionFilter* partition_filter() const;
const std::vector<std::unique_ptr<const ResolvedOutputColumn>>& output_column_list() const; int output_column_list_size() const; const ResolvedOutputColumn* output_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedColumnDefinition>>& column_definition_list() const; int column_definition_list_size() const; const ResolvedColumnDefinition* column_definition_list(int i) const;
const std::vector<ResolvedColumn>& pseudo_column_list() const; int pseudo_column_list_size() const; ResolvedColumn pseudo_column_list(int i) const;
const ResolvedPrimaryKey* primary_key() const;
const std::vector<std::unique_ptr<const ResolvedForeignKey>>& foreign_key_list() const; int foreign_key_list_size() const; const ResolvedForeignKey* foreign_key_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedCheckConstraint>>& check_constraint_list() const; int check_constraint_list_size() const; const ResolvedCheckConstraint* check_constraint_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& partition_by_list() const; int partition_by_list_size() const; const ResolvedExpr* partition_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& cluster_by_list() const; int cluster_by_list_size() const; const ResolvedExpr* cluster_by_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const;
const ResolvedWithPartitionColumns* with_partition_columns() const;
const ResolvedConnection* connection() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& from_files_option_list() const; int from_files_option_list_size() const; const ResolvedOption* from_files_option_list(int i) const; };
// This statement: // CREATE [OR REPLACE] PROPERTY GRAPH [IF NOT EXISTS] <name_path> // [OPTIONS (<option_list>)] // NODE TABLES(<node_table_list>) // [EDGE TABLES(<edge_table_list>)] // // <option_list> is a placeholder for engine-specific directives. // <node_table_list> has the list of node table definitions. // <edge_table_list> has the list of edge table definitions. class ResolvedCreatePropertyGraphStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_PROPERTY_GRAPH_STMT;
const std::vector<std::unique_ptr<const ResolvedGraphElementTable>>& node_table_list() const; int node_table_list_size() const; const ResolvedGraphElementTable* node_table_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedGraphElementTable>>& edge_table_list() const; int edge_table_list_size() const; const ResolvedGraphElementTable* edge_table_list(int i) const;
// All labels defined in this property graph. const std::vector<std::unique_ptr<const ResolvedGraphElementLabel>>& label_list() const; int label_list_size() const; const ResolvedGraphElementLabel* label_list(int i) const;
// All property declarations exposed by labels in this property // graph. const std::vector<std::unique_ptr<const ResolvedGraphPropertyDeclaration>>& property_declaration_list() const; int property_declaration_list_size() const; const ResolvedGraphPropertyDeclaration* property_declaration_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// GraphElementTable definition: // <name> [AS <alias>] // [KEY(<key_list>)] // [<source_node_reference>] // [<dest_node_reference>] // [<label_name_list>] // [<property_definition_list] // // <alias> identifier of the element table in the property graph. // <key_list> has a set of references to ResolvedColumn from input_scan that // can uniquely identify rows in the element table. // <source_node_reference> describes how rows in edge table connect to // rows in the referenced source node table. // <dest_node_reference> describes how rows in edge table connect to // rows in the referenced destination node table by same value columns. // <label_name_list> is a list of label names. // <property_definition_list> is a list of property definitions exposed by // labels. class ResolvedGraphElementTable : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_ELEMENT_TABLE;
const std::string& alias() const;
// ResolvedScan of the underlying table, view etc for column // references in key_list and source/dest_node_reference. const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& key_list() const; int key_list_size() const; const ResolvedExpr* key_list(int i) const;
const ResolvedGraphNodeTableReference* source_node_reference() const;
const ResolvedGraphNodeTableReference* dest_node_reference() const;
const std::vector<std::string>& label_name_list() const; int label_name_list_size() const; std::string label_name_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedGraphPropertyDefinition>>& property_definition_list() const; int property_definition_list_size() const; const ResolvedGraphPropertyDefinition* property_definition_list(int i) const; };
// GraphNodeTableReference definition: // SOURCE|DESTINATION KEY(<edge_table_column_list>) REFERENCES // <node_table_identifier>(<node_table_column_list>) // // <node_table_identifier> must be a defined node table's alias. // <edge_table_column_list> contains columns from the edge table referencing // corresponding node table columns at the same ordinal position in // <node_table_column_list>. class ResolvedGraphNodeTableReference : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_NODE_TABLE_REFERENCE;
const std::string& node_table_identifier() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& edge_table_column_list() const; int edge_table_column_list_size() const; const ResolvedExpr* edge_table_column_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& node_table_column_list() const; int node_table_column_list_size() const; const ResolvedExpr* node_table_column_list(int i) const; };
// <name> is the name of the label. // <property_declaration_name_list> is a list of property declarations // exposed by the label. class ResolvedGraphElementLabel : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_ELEMENT_LABEL;
const std::string& name() const;
const std::vector<std::string>& property_declaration_name_list() const; int property_declaration_name_list_size() const; std::string property_declaration_name_list(int i) const; };
// Represents a property name and type exposed by a GraphElementLabel. class ResolvedGraphPropertyDeclaration : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PROPERTY_DECLARATION;
const std::string& name() const;
const Type* type() const; };
// Represents a property exposed by a GraphElementLabel on a specific // GraphElementTable. // <expr> [ AS <property_declaration_name> ] // // <expr> is the property definition, a ResolvedExpression to identify a // column. // <sql> is the original sql string of the property definition. // <property_declaration_name> refers to a property declaration. class ResolvedGraphPropertyDefinition : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PROPERTY_DEFINITION;
const ResolvedExpr* expr() const;
const std::string& sql() const;
const std::string& property_declaration_name() const; };
// Base scan class for graph scans
class ResolvedGraphScanBase : public ResolvedScan {
};
// A reference scan that can be used as input by a scan op // to its previous scan op within the same parent GraphLinearScan. class ResolvedGraphRefScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_REF_SCAN;
};
// GraphLinearScan consists of multiple child scans executed in // order and outputs the last scan class ResolvedGraphLinearScan : public ResolvedGraphScanBase { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_LINEAR_SCAN;
const std::vector<std::unique_ptr<const ResolvedScan>>& scan_list() const; int scan_list_size() const; const ResolvedScan* scan_list(int i) const; };
// A scan produced by <graph table> as described in // (broken link):graph-table-syntax, or gql enabled <graph table>, // as described in (broken link):gql-graph-table. // // It produces columns of non-graph SQL type, either defined by // <shape_expr_list> or from <input_scan> directly. // When FEATURE_V_1_4_SQL_GRAPH_EXPOSE_GRAPH_ELEMENT is enabled it may // produce columns of graph element type. // // If <shape_expr_list> is not empty, it defines the output columns of // ResolvedGraphTableScan, it can only access columns produced from // <input_scan>. class ResolvedGraphTableScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_TABLE_SCAN;
const PropertyGraph* property_graph() const;
const ResolvedGraphScanBase* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& shape_expr_list() const; int shape_expr_list_size() const; const ResolvedComputedColumn* shape_expr_list(int i) const; };
// A scan produced by a <graph pattern> in <graph table>. It represents the // cross product of input ResolvedGraphPathScans, each represents a matching // sequences of graph elements (i.e. paths) in the property graph. // // The <column_list> will contain columns from the <column_list>s of the // input path scans. // // <filter_expr> contains expressions resolved from // graph pattern where clause, and possible equalities for joining path scans // on multiply-declared variables. It further filters the set of matched // paths. // // When <input_scan> exists, the natural join semantics mentioned in // (broken link):gql-linear-comp would be applied to the <graph pattern> scan and // this <input_scan>. // // When <optional> is true and <input_scan> exists, LEFT OUTER JOIN semantics // mentioned in (broken link):optional-match would be applied to <input_scan> and // scan produced from <graph pattern>. class ResolvedGraphScan : public ResolvedGraphScanBase { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_SCAN;
// path pattern list contained in the graph pattern const std::vector<std::unique_ptr<const ResolvedGraphPathScan>>& input_scan_list() const; int input_scan_list_size() const; const ResolvedGraphPathScan* input_scan_list(int i) const;
const ResolvedExpr* filter_expr() const;
// current tabular result in the graph query to be joined with. // See (broken link):gql-linear-comp for more details. This can only be a // ResolvedGraphRefScan after resolution, and would become a // ProjectScan / other GraphScan when linear query is rewritten into // a nested tree structure. const ResolvedScan* input_scan() const;
// this is the result of an OPTIONAL MATCH. See // (broken link):optional-match for more details. Corresponds to a left // outer join. bool optional() const; };
// A graph path pattern quantifier is used to represent the repetition of // a path pattern. class ResolvedGraphPathPatternQuantifier : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PATH_PATTERN_QUANTIFIER;
const ResolvedExpr* lower_bound() const;
const ResolvedExpr* upper_bound() const; };
// A graph path pattern search prefix, which restricts the result from a // graph pattern match by grouping the resulting paths by their // endpoints (the first and last vertices) and makes a selection of // paths from each group. class ResolvedGraphPathSearchPrefix : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PATH_SEARCH_PREFIX;
typedef ResolvedGraphPathSearchPrefixEnums::PathSearchPrefixType PathSearchPrefixType; static const PathSearchPrefixType PATH_SEARCH_PREFIX_TYPE_UNSPECIFIED = ResolvedGraphPathSearchPrefixEnums::PATH_SEARCH_PREFIX_TYPE_UNSPECIFIED; static const PathSearchPrefixType ANY = ResolvedGraphPathSearchPrefixEnums::ANY; static const PathSearchPrefixType SHORTEST = ResolvedGraphPathSearchPrefixEnums::SHORTEST;
ResolvedGraphPathSearchPrefix::PathSearchPrefixType type() const; };
// Common base class for path scan and element scan.
// This is needed to support parenthesized path pattern.
class ResolvedGraphPathScanBase : public ResolvedScan {
};
// A base scan produced by a <element pattern>. // Outputs a stream of single-columned rows where <filter_expr> evaluates // to true and <label_expr> is satisfied. Column is of // GraphElementType(kind=Node|Edge). // Element tables matching the label expression and the element kind // are accessible in <target_element_table_list>. class ResolvedGraphElementScan : public ResolvedGraphPathScanBase { const ResolvedExpr* filter_expr() const;
// This is a logical combination of individual labels belonging // to a property graph using conjunctions (&), disjunctions (|), // negations (!), and grouping parentheses. During query evaluation, // relevant graph element tables are retrieved that satisfy // <label_expr>. const ResolvedGraphLabelExpr* label_expr() const;
// This is a vector of element tables of kind Node or Edge that // were found to satisfy <labelexpr> during resolution. const std::vector<const GraphElementTable*>& target_element_table_list() const; int target_element_table_list_size() const; const GraphElementTable* target_element_table_list(int i) const; };
// A ResolvedGraphElementScan produced by <node pattern>, whose the single // output column is of GraphElementType(kind=Node). class ResolvedGraphNodeScan : public ResolvedGraphElementScan { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_NODE_SCAN;
};
// A ResolvedGraphElementScan produced by <edge pattern>, whose the single // output column is of GraphElementType(kind=Edge). // // The edge scan also specifies the orientation requirement: only edges // matches the orientation should be returned. class ResolvedGraphEdgeScan : public ResolvedGraphElementScan { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_EDGE_SCAN;
typedef ResolvedGraphEdgeScanEnums::EdgeOrientation EdgeOrientation; static const EdgeOrientation ANY = ResolvedGraphEdgeScanEnums::ANY; static const EdgeOrientation LEFT = ResolvedGraphEdgeScanEnums::LEFT; static const EdgeOrientation RIGHT = ResolvedGraphEdgeScanEnums::RIGHT;
ResolvedGraphEdgeScan::EdgeOrientation orientation() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& lhs_hint_list() const; int lhs_hint_list_size() const; const ResolvedOption* lhs_hint_list(int i) const;
const std::vector<std::unique_ptr<const ResolvedOption>>& rhs_hint_list() const; int rhs_hint_list_size() const; const ResolvedOption* rhs_hint_list(int i) const; };
// Get property <property_name> from the graph element in <expr>. <expr> must // be of GraphElementType. class ResolvedGraphGetElementProperty : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_GET_ELEMENT_PROPERTY;
const ResolvedExpr* expr() const;
const GraphPropertyDeclaration* property() const; };
// A label is an element of a graph that declares what properties
// are exposed by some node/edge table.
// A label expression is an arbitrarily complex expression of labels with the
// operators &, |, and ! as well as grouping parentheses.
class ResolvedGraphLabelExpr : public ResolvedArgument {
};
// This represents a logical operation performed on a set of individual // labels, where <op> specifies the type of operation (&, |, !) and // <operand_list> contains the operands of type ResolvedGraphLabelExpr. Note // that & and | are N-ary instead of binary to flatten the expressions // and avoid deep stacks. Note that ! is unary and therefore expects // that <operand_list> has 1 element. class ResolvedGraphLabelNaryExpr : public ResolvedGraphLabelExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_LABEL_NARY_EXPR;
typedef ResolvedGraphLabelNaryExprEnums::GraphLogicalOpType GraphLogicalOpType; static const GraphLogicalOpType OPERATION_TYPE_UNSPECIFIED = ResolvedGraphLabelNaryExprEnums::OPERATION_TYPE_UNSPECIFIED; static const GraphLogicalOpType NOT = ResolvedGraphLabelNaryExprEnums::NOT; static const GraphLogicalOpType AND = ResolvedGraphLabelNaryExprEnums::AND; static const GraphLogicalOpType OR = ResolvedGraphLabelNaryExprEnums::OR;
std::string GetGraphLogicalOpTypeString() const; static std::string GraphLogicalOpTypeToString(GraphLogicalOpType logical_op_type);
ResolvedGraphLabelNaryExpr::GraphLogicalOpType op() const;
const std::vector<std::unique_ptr<const ResolvedGraphLabelExpr>>& operand_list() const; int operand_list_size() const; const ResolvedGraphLabelExpr* operand_list(int i) const; };
// This represents a single resolved graph label. A label is an element // belonging to a property graph that has a unique name identifier and // references a set of property declarations. An element table with // a given label exposes all the properties declared by that label. class ResolvedGraphLabel : public ResolvedGraphLabelExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_LABEL;
// Points to a label in the catalog const GraphElementLabel* label() const; };
// This represents the wildcard label % that matches any label in the graph. class ResolvedGraphWildCardLabel : public ResolvedGraphLabelExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_WILD_CARD_LABEL;
};
// Represents the identifier of a graph element within a graph. // See (broken link):graph-element-identifiers for more details. // // <element_table>: the ElementTable that produced this graph element; // <key_list>: references to the key columns of the <element_table>; // <source/dest_node_identifier>: identifiers of source/destination node // of an edge: must be set if the element is an edge; must be null if // the element is a node. class ResolvedGraphElementIdentifier : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_ELEMENT_IDENTIFIER;
const GraphElementTable* element_table() const;
const std::vector<std::unique_ptr<const ResolvedExpr>>& key_list() const; int key_list_size() const; const ResolvedExpr* key_list(int i) const;
const ResolvedGraphElementIdentifier* source_node_identifier() const;
const ResolvedGraphElementIdentifier* dest_node_identifier() const; };
// Represents a graph element property of a graph element. // // <declaration> refers to the property declaration catalog object; // <expr> is the value expression for the <declaration>. class ResolvedGraphElementProperty : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_ELEMENT_PROPERTY;
const GraphPropertyDeclaration* declaration() const;
const ResolvedExpr* expr() const; };
// Constructs a graph element. <type> is always a GraphElementType. // // <identifier> uniquely identifies a graph element in the graph; // <property_list> contains a list of properties and their definitions; // <label_list> contains a list of label catalog objects that are exposed // by the graph element. class ResolvedGraphMakeElement : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_MAKE_ELEMENT;
const ResolvedGraphElementIdentifier* identifier() const;
const std::vector<std::unique_ptr<const ResolvedGraphElementProperty>>& property_list() const; int property_list_size() const; const ResolvedGraphElementProperty* property_list(int i) const;
const std::vector<const GraphElementLabel*>& label_list() const; int label_list_size() const; const GraphElementLabel* label_list(int i) const; };
// Computes an aggregate over the elements of an array. // // For each element in <array>, produce an input row for the aggregate // as follows: // - Let <element_column> be the array element. // - Compute the expressions in <pre_aggregate_computed_column_list>, // which may refer to <element_column> and <array>. // Then evaluate <aggregate> over these rows. It may reference these // new columns, or any other columns in scope for this node. // // The aggregate input rows use the original <array>'s order unless // <aggregate> has an ORDER BY modifier. // // <element_column> and the columns in // <pre_aggregate_computed_column_list> are not visible outside this node. // // <array> can be any ResolvedExpr. Today it's always a ResolvedColumnRef // because the only user is graph's horizontal aggregation and that is // baked into the SQLBuilder implementation. class ResolvedArrayAggregate : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_ARRAY_AGGREGATE;
const ResolvedExpr* array() const;
const ResolvedColumn& element_column() const;
const std::vector<std::unique_ptr<const ResolvedComputedColumn>>& pre_aggregate_computed_column_list() const; int pre_aggregate_computed_column_list_size() const; const ResolvedComputedColumn* pre_aggregate_computed_column_list(int i) const;
const ResolvedAggregateFunctionCall* aggregate() const; };
// ResolvedGraphMakeArrayVariable populates the newly created <array> // column with the values that <element> takes across iterations of the // quantified path. For example, the resolved path `((a) - (b)){3}` will // contain two ResolvedGraphMakeArrayVariables, one creating the // array-typed column with the three values that `a` takes along the // quantified path; same for `b`. // // The type of <array> must be an array with element type <scalar>. class ResolvedGraphMakeArrayVariable : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_MAKE_ARRAY_VARIABLE;
const ResolvedColumn& element() const;
const ResolvedColumn& array() const; };
// Path mode specifies ways to restrict the nodes and edges on a particular // path. It currently provides the ability to prevent duplicate edges with // TRAIL, duplicate nodes with ACYCLIC, and duplicate nodes except possibly // the head and the tail of the path with SIMPLE. class ResolvedGraphPathMode : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PATH_MODE;
typedef ResolvedGraphPathModeEnums::PathMode PathMode; static const PathMode PATH_MODE_UNSPECIFIED = ResolvedGraphPathModeEnums::PATH_MODE_UNSPECIFIED; static const PathMode WALK = ResolvedGraphPathModeEnums::WALK; static const PathMode TRAIL = ResolvedGraphPathModeEnums::TRAIL; static const PathMode SIMPLE = ResolvedGraphPathModeEnums::SIMPLE; static const PathMode ACYCLIC = ResolvedGraphPathModeEnums::ACYCLIC;
ResolvedGraphPathMode::PathMode path_mode() const; };
// ResolvedGraphPathScan represents a scan of matching sequences of // sub-paths or graph elements (i.e. paths) from the graph. // // ResolvedGraphPathScan matches paths that: for the sequence of elements // along the path: // 1) node/edge output from successive node pattern and edge pattern // satisfy edge pattern's orientation constraint: // the matching node must be the source or the destination of the // matching edge; // 2) <filter_expr> evaluates true for the matching graph elements. // 3) <path_hint_list> denotes a hint on a traversal between the // previous path to this path, so the first path in a graph pattern // will not contain a 'path hint'. Note that this is different from // the parent ResolvedScan node's 'hint_list' which belongs to the // scan itself. // // // <head> and <tail> are the first and last graph node of the path // respectively. // // Consecutive paths match when the <tail> of the first path is the same // as the <head> of the second path. // // A path is either quantified or not. If quantified: // 1) <quantifier> and <group_variable_list> must be present. // 2) <group_variable_list> is a list of (<element>, <array>) columns. // For each <element> column, this scan will populate the // corresponding <array> column with an array of all the values // that <scalar> column took across the iterations of the // quantified path in iteration order. Every <element> column comes // from <input_scan_list>. <column_list> contains the <head>, // <tail>, and all of the <array> columns from <group_variable_list> // // // If the path is not quantified: // 1) <quantifier> and <group_variable_list> must not be present. // 2) The <column_list> will contain columns from the <column_list>s of // the input scans, which represents elements in the path. // // If <path> is present, it must be a path-typed column that can be // constructed from the paths and graph elements in <input_scan_list>. // This scan will populate <path> with the nodes and edges that are // matched along the path. If <path> is set on a ResolvedGraphPathScan it // must be set on all descendant ResolvedGraphPathScans. <path> must be a // new column. class ResolvedGraphPathScan : public ResolvedGraphPathScanBase { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_PATH_SCAN;
const std::vector<std::unique_ptr<const ResolvedGraphPathScanBase>>& input_scan_list() const; int input_scan_list_size() const; const ResolvedGraphPathScanBase* input_scan_list(int i) const;
const ResolvedExpr* filter_expr() const;
const ResolvedColumnHolder* path() const;
const ResolvedColumn& head() const;
const ResolvedColumn& tail() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& path_hint_list() const; int path_hint_list_size() const; const ResolvedOption* path_hint_list(int i) const;
// const ResolvedGraphPathPatternQuantifier* quantifier() const;
const std::vector<std::unique_ptr<const ResolvedGraphMakeArrayVariable>>& group_variable_list() const; int group_variable_list_size() const; const ResolvedGraphMakeArrayVariable* group_variable_list(int i) const;
const ResolvedGraphPathMode* path_mode() const;
const ResolvedGraphPathSearchPrefix* search_prefix() const; };
// Represents IS LABELED predicate for graph elements, a boolean expression // that evaluates to true if the graph element satisfies the given // label expression. // <expr> represents the LHS which should always be a column reference of // GraphElementType. // <label_expr> represents the RHS which should always be a // ResolvedGraphLabelExpr. // <is_not> is true if the predicate is negated. class ResolvedGraphIsLabeledPredicate : public ResolvedExpr { static const ResolvedNodeKind TYPE = RESOLVED_GRAPH_IS_LABELED_PREDICATE;
bool is_not() const;
const ResolvedExpr* expr() const;
const ResolvedGraphLabelExpr* label_expr() const; };
// This statement: // UNDROP <schema_object_kind> [IF NOT EXISTS] <name_path> // FOR SYSTEM_TIME AS OF [<for_system_time_expr>] // [OPTIONS (name=value, ...)]; // // <schema_object_kind> is a string identifier for the entity to be // undroped. Currently, only 'SCHEMA' object is supported. // // <name_path> is a vector giving the identifier path for the object to // be undropped. // // <is_if_not_exists> if set, skip the undrop if the resource already // exists. // // <for_system_time_expr> specifies point in time from which entity is to // be undropped. // // <option_list> contains engine-specific options associated with the schema. class ResolvedUndropStmt : public ResolvedStatement { static const ResolvedNodeKind TYPE = RESOLVED_UNDROP_STMT;
const std::string& schema_object_kind() const;
bool is_if_not_exists() const;
const std::vector<std::string>& name_path() const; int name_path_size() const; std::string name_path(int i) const;
const ResolvedExpr* for_system_time_expr() const;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This argument represents the identity column clause for a generated // column: // GENERATED AS IDENTITY ( // [ START WITH <signed_numeric_literal> ] // [ INCREMENT BY <signed_numeric_literal> ] // [ MAXVALUE <signed_numeric_literal>] // [ MINVALUE <signed_numeric_literal>] // [ CYCLE | NO CYCLE] // ) // If attributes are not specified, the resolver fills in the fields using // default values. // Note: Only integer-typed columns can be identity columns. // // `start_with_value` is the start/first value generated for the column. // // `increment_by_value` is the minimum difference between two successive // generated values. // - Can be negative or positive but not 0. // // `max_value` is the maximum value that can be generated in the column. // // `min_value` is the minimum value that can be generated in the column. // // `cycling_enabled`: If true, the generated identity value will cycle around // after overflow, when `min_value` or `max_value` is exceeded. // // See (broken link). class ResolvedIdentityColumnInfo : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_IDENTITY_COLUMN_INFO;
const Value& start_with_value() const;
const Value& increment_by_value() const;
const Value& max_value() const;
const Value& min_value() const;
bool cycling_enabled() const; };
// This represents the pipe STATIC_DESCRIBE operator, which is controlled by // FEATURE_PIPE_STATIC_DESCRIBE. // // This scan is a no-op, that just stores the describe_text produced to show // the intermediate schema where this operator occurred. // // This describe_text is displayed in resolved AST DebugStrings (which is // used internally in analyzer tests), and is also meant to be displayed // through some engine-specific side-channel at query prepare time. class ResolvedStaticDescribeScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_STATIC_DESCRIBE_SCAN;
const ResolvedScan* input_scan() const;
const std::string& describe_text() const; };
// This represents the pipe ASSERT operator, which is controlled by // FEATURE_PIPE_ASSERT. // // `condition` is a boolean expression. // `message` is a string expression. // // `condition` is computed for each row. If it does not return true, // the assertion fails. Then `message` is evaluated and used as part // of the error message, following something like "Assert failed: ". class ResolvedAssertScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_ASSERT_SCAN;
const ResolvedScan* input_scan() const;
const ResolvedExpr* condition() const;
const ResolvedExpr* message() const; };
// This represents the pipe ABSL_LOG operator, which is controlled by // FEATURE_PIPE_LOG. // // Execute `subpipeline` over `input_scan` and send its output to an // implementation-defined log. // // `output_schema` describes the visible schema of the output to send to // the log. (This is not the output of the ResolvedLogScan in the query.) // // In the main query flow, ResolvedLogScan is a no-op and just returns // the result from `input_scan` unchanged. class ResolvedLogScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_LOG_SCAN;
const ResolvedScan* input_scan() const;
const ResolvedSubpipeline* subpipeline() const;
const ResolvedOutputSchema* output_schema() const; };
// This represents the pipe IF operator, which is controlled by // FEATURE_PIPE_IF. See (broken link). // // `if_case_list` must have at least one element with a `condition`. // If there's an ELSE case, if will be last and will have no `condition`. // // `selected_case` indicates the chosen case and must be a valid index into // `if_case_list`. `selected_case` is -1 if no case is selected and there's // no ELSE case. // // The constant `condition` for `selected_case` must evaluate to true unless // it's the ELSE case. All preceding `condition` expressions must evaluate // to non-true values. (Later `condition` expressions could return errors.) // // The selected case includes a valid resolved `subpipeline` that takes // `input_scan` as its input table. // // Execution semantics: // Only the selected case runs. The condition expressions have already been // evaluated statically at analysis time so are not evaluated at runtime. // If `selected_case` is -1, this scan is a no-op. // // The subpipeline for the selected case runs over `input_scan`. // Its output is this node's output. // This node's `column_list` must be a subset of the subpipeline's final // column list. // // `if_case_list` is ignorable because if `selected_case` is -1, it's // not necessary to look at any cases. class ResolvedPipeIfScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_PIPE_IF_SCAN;
// Get the ResolvedScan for the case that was selected. // When no case is selected (and there's no ELSE), this will be
input_scan
. const ResolvedScan* GetSelectedCaseScan() const;const ResolvedScan* input_scan() const;
int selected_case() const;
const std::vector<std::unique_ptr<const ResolvedPipeIfCase>>& if_case_list() const; int if_case_list_size() const; const ResolvedPipeIfCase* if_case_list(int i) const; };
// This represents one case in a ResolvedPipeIf. // // `condition` and `subpipeline_sql` must be present for all cases except // the last case (if it's an ELSE case). // `condition` must be present except on the ELSE case. // `subpipeline_sql` must be present for all cases. // // Where `condition` is present, it must be a valid boolean constant // expression. // // `subpipeline_sql` gives the SQL for the subpipeline, including the // wrapping parentheses. This is required even for the selected case // because the SQLBuilder currently relies on it. // // `subpipeline_sql` for non-selected cases doesn't have to be resolvable // but should be parsable. // // `subpipeline` must be present for the selected case, and can optionally // be present for other cases (only when the SQL is valid). // // `condition` is ignorable because conditions are evaluated at analysis time // and the case to run has already been chosen. // // `subpipeline` is ignorable because it doesn't need to be consumed in the // non-selected cases. class ResolvedPipeIfCase : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_PIPE_IF_CASE;
bool IsElse() const { return condition() == nullptr; }
const ResolvedExpr* condition() const;
const std::string& subpipeline_sql() const;
const ResolvedSubpipeline* subpipeline() const; };
// This represents the pipe FORK operator, which is controlled by // FEATURE_PIPE_FORK. See (broken link). // // This only occurs inside ResolvedGeneralizedQueryStmts, so that statement // must be enabled in SupportedStatementKinds. class ResolvedPipeForkScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_PIPE_FORK_SCAN;
const ResolvedScan* input_scan() const;
const std::vector<std::unique_ptr<const ResolvedGeneralizedQuerySubpipeline>>& subpipeline_list() const; int subpipeline_list_size() const; const ResolvedGeneralizedQuerySubpipeline* subpipeline_list(int i) const; };
// This represents the pipe EXPORT DATA operator, which is controlled by // FEATURE_PIPE_EXPORT_DATA. See (broken link). // // This only occurs inside ResolvedGeneralizedQueryStmts, so that statement // must be enabled in SupportedStatementKinds. class ResolvedPipeExportDataScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_PIPE_EXPORT_DATA_SCAN;
const ResolvedScan* input_scan() const;
const ResolvedExportDataStmt* export_data_stmt() const; };
// This represents a subpipeline. // These occur inside various pipe operators, expressing a subpipeline of // pipe operators to apply on some input table. // See (broken link). // // The operator that contains this ResolvedSubpipeline defines how it's // being used and what table is passed in. Most commonly, this is used // inside pipe operator scans, and is passed the `input_scan` of the // containing ResolvedScan. When some other intermediate table is passed to // the subpipeline, that will be documented in the containing node. // // Inside `scan`, there must be exactly one instance of // ResolvedSubpipelineInputScan as a leaf scan receiving the subpipeline's // input table. That scan's column_list includes a subset of columns // available from the input table provided to this ResolvedSubpipeline. // // ResolvedSubpipeline is like the final subquery in a ResolvedWithScan. // The ResolvedSubpipelineInputScan is like the ResolvedWithRefScan. // The node containing this ResolvedSubpipeline is like the ResolvedWithScan // and has to define the CTE-like table that will be referenced. class ResolvedSubpipeline : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_SUBPIPELINE;
const ResolvedScan* scan() const; };
// This is the scan inside a ResolvedSubpipeline representing the initial // input table passed into the subpipeline. This works like a CTE in WITH. // // The node containing the ResolvedSubpipeline (which is like a // ResolvedWithScan) specifies what table this is. Often it's a table that // just gets a copy of the node's `input_scan`, to pass through to the // subpipeline. // // The ResolvedSubpipelineInputScan is like a ResolvedWithRefScan, doing the // scan of that specified table inside the subpupline query. // // The `column_list` columns are a subset of columns available on that // input table. class ResolvedSubpipelineInputScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_SUBPIPELINE_INPUT_SCAN;
};
// This represents a subpipeline that is part of a ResolvedGeneralizedQueryStmt // and could produce an output table or a statement side-effect. // This node can only occur inside a ResolvedGeneralizedQueryStmt. // // These subpipelines occur inside operators like FORK that create // generalized query shapes. See (broken link). // // `output_schema` is present if this subpipeline produces a final output // table to be returned as part of the ResolvedGeneralizedQueryStmt, and // provides the schema of that table. class ResolvedGeneralizedQuerySubpipeline : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_GENERALIZED_QUERY_SUBPIPELINE;
const ResolvedSubpipeline* subpipeline() const;
const ResolvedOutputSchema* output_schema() const; };
// ResolvedBarrierScan marks an optimization barrier during query planning. // It wraps an `input_scan` and ensures `input_scan` is evaluated as if // `input_scan` stands alone; plan transformations that may cause // different observable side effects may not cross the optimization barrier. // // The output rows of a ResolvedBarrierScan are the same as those of the // `input_scan`, propagating the `is_ordered` property of `input_scan`. // // The following optimizations are allowed: // * Prune an unused column of a ResolvedBarrierScan. // * Prune the whole ResolvedBarrierScan. // // This node does not have a corresponding syntax. class ResolvedBarrierScan : public ResolvedScan { static const ResolvedNodeKind TYPE = RESOLVED_BARRIER_SCAN;
const ResolvedScan* input_scan() const; };
// This statement: // CREATE [OR REPLACE] [TEMP] CONNECTION // [IF NOT EXISTS] <name> [OPTIONS (name=value, ...)] // // builds a new connection based on the inputs provided via the // the OPTIONS field. // // <name> is the name of the fully qualified connection. // <option_list> is the list of options for the connection. class ResolvedCreateConnectionStmt : public ResolvedCreateStatement { static const ResolvedNodeKind TYPE = RESOLVED_CREATE_CONNECTION_STMT;
const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };
// This statement: // ALTER CONNECTION [IF EXISTS] <name_path> SET OPTIONS(...) class ResolvedAlterConnectionStmt : public ResolvedAlterObjectStmt { static const ResolvedNodeKind TYPE = RESOLVED_ALTER_CONNECTION_STMT;
};
// ResolvedLockMode optionally indicates whether locks should be // acquired on the data accessed during a ResolvedTableScan. // // `strength` specifies the strength of the locks to be acquired. class ResolvedLockMode : public ResolvedArgument { static const ResolvedNodeKind TYPE = RESOLVED_LOCK_MODE;
typedef ResolvedLockModeEnums::LockStrengthType LockStrengthType; static const LockStrengthType UPDATE = ResolvedLockModeEnums::UPDATE;
ResolvedLockMode::LockStrengthType strength() const; };