Skip to content

Latest commit

 

History

History
executable file
·
5594 lines (4727 loc) · 254 KB

resolved_ast.md

File metadata and controls

executable file
·
5594 lines (4727 loc) · 254 KB

ZetaSQL Resolved AST

The ZetaSQL Resolved AST

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.

C++

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.

Java

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.

Resolved AST Node Hierarchy


ResolvedNode
  ResolvedArgument
    ResolvedAggregateHavingModifier
    ResolvedAlterAction
      ResolvedAddColumnAction
      ResolvedAddConstraintAction
      ResolvedAlterColumnOptionsAction
      ResolvedDropColumnAction
      ResolvedDropConstraintAction
      ResolvedFilterUsingAction
      ResolvedGrantToAction
      ResolvedRenameToAction
      ResolvedRevokeFromAction
      ResolvedSetAsAction
      ResolvedSetOptionsAction
    ResolvedAnalyticFunctionGroup
    ResolvedArgumentDef
    ResolvedArgumentList
    ResolvedAssertRowsModified
    ResolvedColumnAnnotations
    ResolvedColumnDefinition
    ResolvedColumnHolder
    ResolvedComputedColumn
    ResolvedConnection
    ResolvedConstraint
      ResolvedCheckConstraint
      ResolvedForeignKey
    ResolvedDMLValue
    ResolvedDescriptor
    ResolvedExecuteImmediateArgument
    ResolvedExtendedCast
    ResolvedExtendedCastElement
    ResolvedFilterFieldArg
    ResolvedFunctionArgument
    ResolvedFunctionSignatureHolder
    ResolvedGeneratedColumnInfo
    ResolvedGroupingSet
    ResolvedIndexItem
    ResolvedInlineLambda
    ResolvedInsertRow
    ResolvedMakeProtoField
    ResolvedMergeWhen
    ResolvedModel
    ResolvedOption
    ResolvedOrderByItem
    ResolvedOutputColumn
    ResolvedPivotColumn
    ResolvedPrimaryKey
    ResolvedPrivilege
    ResolvedReplaceFieldItem
    ResolvedReturningClause
    ResolvedSetOperationItem
    ResolvedUnnestItem
    ResolvedUnpivotArg
    ResolvedUpdateArrayItem
    ResolvedUpdateItem
    ResolvedWindowFrame
    ResolvedWindowFrameExpr
    ResolvedWindowOrdering
    ResolvedWindowPartitioning
    ResolvedWithEntry
    ResolvedWithPartitionColumns
  ResolvedExpr
    ResolvedArgumentRef
    ResolvedCast
    ResolvedColumnRef
    ResolvedConstant
    ResolvedDMLDefault
    ResolvedExpressionColumn
    ResolvedFilterField
    ResolvedFlatten
    ResolvedFlattenedArg
    ResolvedFunctionCallBase
      ResolvedFunctionCall
      ResolvedNonScalarFunctionCallBase
        ResolvedAggregateFunctionCall
        ResolvedAnalyticFunctionCall
    ResolvedGetJsonField
    ResolvedGetProtoField
    ResolvedGetStructField
    ResolvedLiteral
    ResolvedMakeProto
    ResolvedMakeStruct
    ResolvedParameter
    ResolvedReplaceField
    ResolvedSubqueryExpr
    ResolvedSystemVariable
  ResolvedScan
    ResolvedAggregateScanBase
      ResolvedAggregateScan
      ResolvedAnonymizedAggregateScan
    ResolvedAnalyticScan
    ResolvedArrayScan
    ResolvedFilterScan
    ResolvedJoinScan
    ResolvedLimitOffsetScan
    ResolvedOrderByScan
    ResolvedPivotScan
    ResolvedProjectScan
    ResolvedRecursiveRefScan
    ResolvedRecursiveScan
    ResolvedRelationArgumentScan
    ResolvedSampleScan
    ResolvedSetOperationScan
    ResolvedSingleRowScan
    ResolvedTVFScan
    ResolvedTableScan
    ResolvedUnpivotScan
    ResolvedWithRefScan
    ResolvedWithScan
  ResolvedStatement
    ResolvedAbortBatchStmt
    ResolvedAlterObjectStmt
      ResolvedAlterAllRowAccessPoliciesStmt
      ResolvedAlterDatabaseStmt
      ResolvedAlterEntityStmt
      ResolvedAlterMaterializedViewStmt
      ResolvedAlterRowAccessPolicyStmt
      ResolvedAlterSchemaStmt
      ResolvedAlterTableStmt
      ResolvedAlterViewStmt
    ResolvedAlterTableSetOptionsStmt
    ResolvedAssertStmt
    ResolvedAssignmentStmt
    ResolvedBeginStmt
    ResolvedCallStmt
    ResolvedCommitStmt
    ResolvedCreateDatabaseStmt
    ResolvedCreateRowAccessPolicyStmt
    ResolvedCreateStatement
      ResolvedCreateConstantStmt
      ResolvedCreateEntityStmt
      ResolvedCreateFunctionStmt
      ResolvedCreateIndexStmt
      ResolvedCreateModelStmt
      ResolvedCreateProcedureStmt
      ResolvedCreateSchemaStmt
      ResolvedCreateTableFunctionStmt
      ResolvedCreateTableStmtBase
        ResolvedCreateExternalTableStmt
        ResolvedCreateTableAsSelectStmt
        ResolvedCreateTableStmt
      ResolvedCreateViewBase
        ResolvedCreateMaterializedViewStmt
        ResolvedCreateViewStmt
    ResolvedDefineTableStmt
    ResolvedDeleteStmt
    ResolvedDescribeStmt
    ResolvedDropFunctionStmt
    ResolvedDropMaterializedViewStmt
    ResolvedDropRowAccessPolicyStmt
    ResolvedDropStmt
    ResolvedDropTableFunctionStmt
    ResolvedExecuteImmediateStmt
    ResolvedExplainStmt
    ResolvedExportDataStmt
    ResolvedExportModelStmt
    ResolvedGrantOrRevokeStmt
      ResolvedGrantStmt
      ResolvedRevokeStmt
    ResolvedImportStmt
    ResolvedInsertStmt
    ResolvedMergeStmt
    ResolvedModuleStmt
    ResolvedQueryStmt
    ResolvedRenameStmt
    ResolvedRollbackStmt
    ResolvedRunBatchStmt
    ResolvedSetTransactionStmt
    ResolvedShowStmt
    ResolvedStartBatchStmt
    ResolvedTruncateStmt
    ResolvedUpdateStmt

Node Details

NOTE: This documentation includes only the public field accessors. It excludes constructors, setters, and boilerplate implementation of virtual methods from the base class.

ResolvedArgument


// 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 {
};

ResolvedExpr


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; };

ResolvedLiteral


// 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; };

ResolvedParameter


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; };

ResolvedExpressionColumn


// 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; };

ResolvedColumnRef


// 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; };

ResolvedConstant


// 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; };

ResolvedSystemVariable


// 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; };

ResolvedInlineLambda


// 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; };

ResolvedFilterFieldArg


// 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; };

ResolvedFilterField


// 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; };

ResolvedFunctionCallBase


// 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.
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(...). 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; };

ResolvedFunctionCall


// 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; };

ResolvedNonScalarFunctionCallBase


// Common base class for scalar 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. NullHandlingModifier null_handling_modifier() const; };

ResolvedAggregateFunctionCall


// An aggregate function call.  The signature always has mode AGGREGATE.
// This node only ever shows up as the outer function call in a
// ResolvedAggregateScan::aggregate_list.
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; };

ResolvedAnalyticFunctionCall


// 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; };

ResolvedExtendedCastElement


// 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; };

ResolvedExtendedCast


// 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; };

ResolvedCast


// 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;

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; };

ResolvedMakeStruct


// 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; };

ResolvedMakeProto


// 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; };

ResolvedMakeProtoField


// 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; };

ResolvedGetStructField


// 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; };

ResolvedGetProtoField


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; };

ResolvedGetJsonField


// 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; };

ResolvedFlatten


// 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; };

ResolvedFlattenedArg


// 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;

};

ResolvedReplaceFieldItem


// 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; };

ResolvedReplaceField


// 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; };

ResolvedSubqueryExpr


// 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.
//
// The subquery for a SCALAR or ARRAY or IN 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;

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 subquery of type IN. const ResolvedExpr* in_expr() const;

const ResolvedScan* subquery() const;

// Note: Hints currently happen only for EXISTS or IN 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; };

ResolvedScan


// 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).
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; };

ResolvedModel


// 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; };

ResolvedConnection


// Represents a connection object as a TVF argument.
// <connection> is the connection object encapsulated metadata to connect to
// an external data source.
class ResolvedConnection : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_CONNECTION;

const Connection* connection() const; };

ResolvedDescriptor


// 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; };

ResolvedSingleRowScan


// 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;

};

ResolvedTableScan


// 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; };

ResolvedJoinScan


// 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;

JoinType join_type() const;

const ResolvedScan* left_scan() const;

const ResolvedScan* right_scan() const;

const ResolvedExpr* join_expr() const; };

ResolvedArrayScan


// Scan an array value, produced from some expression.
//
// If input_scan is NULL, this scans the given array value and produces
// one row per array element.  This can occur when using UNNEST(expression).
//
// If <input_scan> is non-NULL, for each row in the stream produced by
// input_scan, this evaluates the expression <array_expr> (which must return
// an array type) and then produces a stream with one row per array element.
//
// If <join_expr> is non-NULL, then this condition is evaluated as an ON
// clause for the array join.  The named column produced in <array_expr>
// 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 a NULL value for
//    the <element_column>.
//
// <element_column> is the new column produced by this scan that stores the
// array element value for each row.
//
// If present, <array_offset_column> defines the column produced by this
// scan that stores the array offset (0-based) for the corresponding
// <element_column>.
//
// This node's column_list can have columns from input_scan, <element_column>
// and <array_offset_column>.
class ResolvedArrayScan : public ResolvedScan {
  static const ResolvedNodeKind TYPE = RESOLVED_ARRAY_SCAN;

const ResolvedScan* input_scan() const;

const ResolvedExpr* array_expr() const;

const ResolvedColumn& element_column() const;

const ResolvedColumnHolder* array_offset_column() const;

const ResolvedExpr* join_expr() const;

bool is_outer() const; };

ResolvedColumnHolder


// 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; };

ResolvedFilterScan


// 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; };

ResolvedGroupingSet


// 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 ResolvedArgument {
  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; };

ResolvedAggregateScanBase


// 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.
//
// 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.
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<std::unique_ptr<const ResolvedComputedColumn>>& aggregate_list() const; int aggregate_list_size() const; const ResolvedComputedColumn* aggregate_list(int i) const; };

ResolvedAggregateScan


// Apply aggregation to rows produced from input_scan, and output aggregated
// rows.
//
// For each item in <grouping_set_list>, output additional rows computing the
// same <aggregate_list> over the input rows using a particular grouping set.
// 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>.
class ResolvedAggregateScan : public ResolvedAggregateScanBase {
  static const ResolvedNodeKind TYPE = RESOLVED_AGGREGATE_SCAN;

const std::vector<std::unique_ptr<const ResolvedGroupingSet>>& grouping_set_list() const; int grouping_set_list_size() const; const ResolvedGroupingSet* 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; };

ResolvedAnonymizedAggregateScan


// Apply differentially private aggregation (anonymization) to rows produced
// from input_scan, and output anonymized rows.
// Spec: (broken link)
//
// <k_threshold_expr> when non-null, points to a function call in
// the <aggregate_list> and 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, or
// k_threshold.
class ResolvedAnonymizedAggregateScan : public ResolvedAggregateScanBase {
  static const ResolvedNodeKind TYPE = RESOLVED_ANONYMIZED_AGGREGATE_SCAN;

const ResolvedColumnRef* 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; };

ResolvedSetOperationItem


// 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; };

ResolvedSetOperationScan


// 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.
class ResolvedSetOperationScan : public ResolvedScan {
  static const ResolvedNodeKind TYPE = RESOLVED_SET_OPERATION_SCAN;

typedef ResolvedSetOperationScanEnums::SetOperationType SetOperationType; 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;

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; };

ResolvedOrderByScan


// 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; };

ResolvedLimitOffsetScan


// 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; };

ResolvedWithRefScan


// 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 name 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; };

ResolvedAnalyticScan


// 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 conain partitioning/ordering
// expression columns if they reference to select columns.
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; };

ResolvedSampleScan


// 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;

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; };

ResolvedComputedColumn


// 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.
class ResolvedComputedColumn : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_COMPUTED_COLUMN;

const ResolvedColumn& column() const;

const ResolvedExpr* expr() const; };

ResolvedOrderByItem


// This represents one column of an ORDER BY clause, with the requested
// ordering direction.
//
// <collation_name> indicates the COLLATE specific rules of ordering.
// If non-NULL, must be a string literal or a string parameter.
// See (broken link).
//
// <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;

NullOrderMode null_order() const; };

ResolvedColumnAnnotations


// This is used in CREATE TABLE statements to provide column annotations
// such as 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;

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; };

ResolvedGeneratedColumnInfo


// <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.
//
// <is_stored> indicates whether the value of the expression should be
// pre-emptively computed to save work at read time. When is_stored is true,
// <expression> cannot contain a volatile function (e.g. RAND).
//
// <is_on_write> indicates that the value of this column should be calculated
// at write time. As opposed to <is_stored> the <expression> can contain
// volatile functions (e.g. RAND).
//
// Only one of <is_stored> or <is_on_write> can be true.
//
// See (broken link).
class ResolvedGeneratedColumnInfo : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_GENERATED_COLUMN_INFO;

const ResolvedExpr* expression() const;

bool is_stored() const;

bool is_on_write() const; };

ResolvedColumnDefinition


// 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 table column is a
// generated column.
//
// <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.
    zetasql_base::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; };

ResolvedPrimaryKey


// 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.
//
// <unenforced> specifies whether the constraint is unenforced.
class ResolvedPrimaryKey : public ResolvedArgument {
  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; };

ResolvedConstraint


// Intermediate class for resolved constraints.
class ResolvedConstraint : public ResolvedArgument {
};

ResolvedForeignKey


// 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;

MatchMode match_mode() const;

ActionOperation update_action() const;

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; };

ResolvedCheckConstraint


// This represents the CHECK constraint on a table. It is of the form:
//
//   CONSTRAINT <constraint_name>
//   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; };

ResolvedOutputColumn


// This is used in ResolvedQueryStmt to provide a user-visible name
// for each output column.
class ResolvedOutputColumn : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_OUTPUT_COLUMN;

const std::string& name() const;

const ResolvedColumn& column() const; };

ResolvedProjectScan


// 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; };

ResolvedTVFScan


// 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; };

ResolvedFunctionArgument


// This represents a generic argument to a function. The argument can be
// semantically an expression, relation, model, connection or descriptor.
// Only one of the five fields will be set.
//
// <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.
//
// This node could be used in multiple places:
// * ResolvedTVFScan supports all of these.
// * ResolvedFunctionCall supports only <expr>.
// * 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.
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; };

ResolvedStatement


// 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; };

ResolvedExplainStmt


// 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; };

ResolvedQueryStmt


// 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; };

ResolvedCreateDatabaseStmt


// 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; };

ResolvedCreateStatement


// 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;

CreateScope create_scope() const;

CreateMode create_mode() const; };

ResolvedIndexItem


// Represents one of indexed items in CREATE INDEX statement, with the
// ordering direction specified.
class ResolvedIndexItem : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_INDEX_ITEM;

const ResolvedColumnRef* column_ref() const;

bool descending() const; };

ResolvedUnnestItem


// 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; };

ResolvedCreateIndexStmt


// This statement:
// CREATE [OR REPLACE] [UNIQUE] [SEARCH] INDEX [IF NOT EXISTS]
//  <index_name_path> ON <table_name_path>
// [STORING (Expression, ...)]
// [UNNEST(path_expression) [[AS] alias] [WITH OFFSET [[AS] alias]], ...]
// (path_expression [ASC|DESC], ...) [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.
// <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.
// <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;

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 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; };

ResolvedCreateSchemaStmt


// This statement:
// CREATE [OR REPLACE] SCHEMA [IF NOT EXISTS] <name>
// [OPTIONS (name=value, ...)];
//
// <option_list> engine-specific options.
class ResolvedCreateSchemaStmt : public ResolvedCreateStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_CREATE_SCHEMA_STMT;

const std::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };

ResolvedCreateTableStmtBase


// This statement:
//   CREATE [TEMP] TABLE <name> [(column type, ...) | LIKE <name_path>]
//   [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 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.
// <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.
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; };

ResolvedCreateTableStmt


// This statement:
//   CREATE [TEMP] TABLE <name>
//   [(column schema, ...) | LIKE <name_path> |
//       CLONE <name_path>
//           [FOR SYSTEM_TIME AS OF <time_expr>]
//           [WHERE <where_clause>]]
//   [PARTITION BY expr, ...] [CLUSTER BY expr, ...]
//   [OPTIONS (...)]
//
// <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 ResolvedCreateTableStmt : public ResolvedCreateTableStmtBase {
  static const ResolvedNodeKind TYPE = RESOLVED_CREATE_TABLE_STMT;

const ResolvedScan* clone_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; };

ResolvedCreateTableAsSelectStmt


// This statement:
//   CREATE [TEMP] TABLE <name> [(column schema, ...) | LIKE <name_path>]
//   [PARTITION BY expr, ...] [CLUSTER BY expr, ...] [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; };

ResolvedCreateModelStmt


// This statement:
//   CREATE [TEMP] MODEL <name> [TRANSFORM(...)] [OPTIONS (...)] AS SELECT ..
//
// <option_list> has engine-specific directives for how to train this model.
// <output_column_list> matches 1:1 with the <query>'s column_list and the
//                      <column_definition_list>, and identifies the names
//                      and types of the columns output from the select
//                      statement.
// <query> is the select statement.
// <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_list> is the list of ResolvedComputedColumn in TRANSFORM
//   clause.
// <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)
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 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; };

ResolvedCreateViewBase


// 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.
//
// 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;

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; };

ResolvedCreateViewStmt


// This statement:
// CREATE [TEMP] VIEW <name> [(...)] [OPTIONS (...)] AS SELECT ...
class ResolvedCreateViewStmt : public ResolvedCreateViewBase {
  static const ResolvedNodeKind TYPE = RESOLVED_CREATE_VIEW_STMT;

};

ResolvedWithPartitionColumns


// 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; };

ResolvedCreateExternalTableStmt


// This statement:
// CREATE [TEMP] EXTERNAL TABLE <name> [(column type, ...)]
// [WITH PARTITION COLUMN [(column type, ...)]] OPTIONS (...)
class ResolvedCreateExternalTableStmt : public ResolvedCreateTableStmtBase {
  static const ResolvedNodeKind TYPE = RESOLVED_CREATE_EXTERNAL_TABLE_STMT;

const ResolvedWithPartitionColumns* with_partition_columns() const; };

ResolvedExportModelStmt


// 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; };

ResolvedExportDataStmt


// This statement:
//   EXPORT DATA [WITH CONNECTION] <connection> (<option_list>) AS SELECT ...
// which is used to run a query and export its 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.
//
// 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;

const ResolvedScan* query() const; };

ResolvedDefineTableStmt


// 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; };

ResolvedDescribeStmt


// 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; };

ResolvedShowStmt


// 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; };

ResolvedBeginStmt


// 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;

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; };

ResolvedSetTransactionStmt


// 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;

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; };

ResolvedCommitStmt


// This statement: COMMIT [TRANSACTION];
class ResolvedCommitStmt : public ResolvedStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_COMMIT_STMT;

};

ResolvedRollbackStmt


// This statement: ROLLBACK [TRANSACTION];
class ResolvedRollbackStmt : public ResolvedStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_ROLLBACK_STMT;

};

ResolvedStartBatchStmt


// 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; };

ResolvedRunBatchStmt


// This statement: RUN BATCH;
class ResolvedRunBatchStmt : public ResolvedStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_RUN_BATCH_STMT;

};

ResolvedAbortBatchStmt


// This statement: ABORT BATCH;
class ResolvedAbortBatchStmt : public ResolvedStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_ABORT_BATCH_STMT;

};

ResolvedDropStmt


// 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;

DropMode drop_mode() const; };

ResolvedDropMaterializedViewStmt


// 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; };

ResolvedRecursiveRefScan


// 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;

};

ResolvedRecursiveScan


// 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: Evaluate the non-recursive term. If UNION DISTINCT
//   is specified, discard duplicates.
//
// Step 2:
//   Repeat until step 2 produces an empty result:
//     Evaluate the recursive term, binding the recursive table to the
//     new rows produced by previous step. 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 (step 1, plus all iterations of step 2).
//
// 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;

RecursiveSetOperationType op_type() const;

const ResolvedSetOperationItem* non_recursive_term() const;

const ResolvedSetOperationItem* recursive_term() const; };

ResolvedWithScan


// 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; };

ResolvedWithEntry


// 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; };

ResolvedOption


// This represents one SQL hint 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 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).
//
// 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.  Unknown hints (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.
//
// 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;

const std::string& qualifier() const;

const std::string& name() const;

const ResolvedExpr* value() const; };

ResolvedWindowPartitioning


// Window partitioning specification for an analytic function call.
//
// PARTITION BY keys in <partition_by_list>.
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; };

ResolvedWindowOrdering


// 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; };

ResolvedWindowFrame


// 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);

FrameUnit frame_unit() const;

const ResolvedWindowFrameExpr* start_expr() const;

const ResolvedWindowFrameExpr* end_expr() const; };

ResolvedAnalyticFunctionGroup


// 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
// ResolvedAggregateFunctionCall 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 ResolvedComputedColumn>>& analytic_function_list() const; int analytic_function_list_size() const; const ResolvedComputedColumn* analytic_function_list(int i) const; };

ResolvedWindowFrameExpr


// 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);

BoundaryType boundary_type() const;

const ResolvedExpr* expression() const; };

ResolvedDMLValue


// 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; };

ResolvedDMLDefault


// 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;

};

ResolvedAssertStmt


// 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; };

ResolvedAssertRowsModified


// 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; };

ResolvedInsertRow


// 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; };

ResolvedInsertStmt


// 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 acccess columns from the <table_scan>.
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). 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; };

ResolvedDeleteStmt


// 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 acccess columns from the <table_scan>.
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 ResolvedColumnHolder* array_offset_column() const;

const ResolvedExpr* where_expr() const; };

ResolvedUpdateItem


// 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; };

ResolvedUpdateArrayItem


// 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; };

ResolvedUpdateStmt


// 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.
class ResolvedUpdateStmt : public ResolvedStatement {
  static const ResolvedNodeKind TYPE = RESOLVED_UPDATE_STMT;

const ResolvedTableScan* table_scan() const;

const std::vector<ObjectAccess>& column_access_list() const; int column_access_list_size() const; 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; };

ResolvedMergeWhen


// 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;

MatchType match_type() const;

const ResolvedExpr* match_expr() const;

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; };

ResolvedMergeStmt


// 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<ObjectAccess>& column_access_list() const; int column_access_list_size() const; 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; };

ResolvedTruncateStmt


// 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; };

ResolvedPrivilege


// 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) the privilege is restricted to. Privilege on the whole object
// should be granted/revoked 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::string>& unit_list() const; int unit_list_size() const; std::string unit_list(int i) const; };

ResolvedGrantOrRevokeStmt


// Common superclass of GRANT/REVOKE statements.
//
// <privilege_list> is the list of privileges to be granted/revoked. ALL
// PRIVILEGES should be granted/fromed if it is empty.
// <object_type> is an optional string identifier, e.g., TABLE, 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 {
  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::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>& 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; };

ResolvedGrantStmt


// 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;

};

ResolvedRevokeStmt


// 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;

};

ResolvedAlterObjectStmt


// 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>.
// <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; };

ResolvedAlterDatabaseStmt


// 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;

};

ResolvedAlterMaterializedViewStmt


// 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;

};

ResolvedAlterSchemaStmt


// This statement:
// ALTER SCHEMA [IF NOT EXISTS] <name_path> <alter_action_list>;
class ResolvedAlterSchemaStmt : public ResolvedAlterObjectStmt {
  static const ResolvedNodeKind TYPE = RESOLVED_ALTER_SCHEMA_STMT;

};

ResolvedAlterTableStmt


// This statement:
// ALTER TABLE [IF EXISTS] <name_path> <alter_action_list>
class ResolvedAlterTableStmt : public ResolvedAlterObjectStmt {
  static const ResolvedNodeKind TYPE = RESOLVED_ALTER_TABLE_STMT;

};

ResolvedAlterViewStmt


// This statement:
// ALTER VIEW [IF EXISTS] <name_path> <alter_action_list>
class ResolvedAlterViewStmt : public ResolvedAlterObjectStmt {
  static const ResolvedNodeKind TYPE = RESOLVED_ALTER_VIEW_STMT;

};

ResolvedAlterAction


// A common super class for all actions in statement ALTER <object>
class ResolvedAlterAction : public ResolvedArgument {
};

ResolvedSetOptionsAction


// 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; };

ResolvedAddColumnAction


// 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; };

ResolvedAddConstraintAction


// 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; };

ResolvedDropConstraintAction


// 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; };

ResolvedAlterColumnOptionsAction


// ALTER COLUMN SET OPTIONS action for ALTER TABLE statement
class ResolvedAlterColumnOptionsAction : public ResolvedAlterAction {
  static const ResolvedNodeKind TYPE = RESOLVED_ALTER_COLUMN_OPTIONS_ACTION;

const std::string& column() 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 ResolvedColumnRef* column_reference() const; };

ResolvedDropColumnAction


// DROP COLUMN action for ALTER TABLE statement
//
// <name> is the name of the column to drop.
// <column_reference> references the column to be dropped, if it exists.
//        It might be missing if DROP IF EXISTS column does not exist.
class ResolvedDropColumnAction : public ResolvedAlterAction {
  static const ResolvedNodeKind TYPE = RESOLVED_DROP_COLUMN_ACTION;

bool is_if_exists() const;

const std::string& name() const;

const ResolvedColumnRef* column_reference() const; };

ResolvedSetAsAction


// SET AS action for generic ALTER <entity_type> statement.
//
// <entity_body_json> is a JSON 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; };

ResolvedAlterTableSetOptionsStmt


// 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; };

ResolvedRenameStmt


// 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; };

ResolvedCreateRowAccessPolicyStmt


// 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;

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; };

ResolvedDropRowAccessPolicyStmt


// 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; };

ResolvedGrantToAction


// 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; };

ResolvedFilterUsingAction


// 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; };

ResolvedRevokeFromAction


// 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; };

ResolvedRenameToAction


// 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; };

ResolvedAlterRowAccessPolicyStmt


// 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; };

ResolvedAlterAllRowAccessPoliciesStmt


// 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; };

ResolvedCreateConstantStmt


// 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; };

ResolvedCreateFunctionStmt


// This statement creates a user-defined function:
//   CREATE [TEMP] FUNCTION [IF NOT EXISTS] <name_path> (<arg_list>)
//     [RETURNS <return_type>] [<determinism_level>] [LANGUAGE <language>]
//     [AS <code> | AS ( <function_expression> )] [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 otherwise to the language
//          name specified in the LANGUAGE clause.
//   <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'.
//
// 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) 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;
    static FunctionEnums::Volatility DeterminismLevelToVolatility(
      ResolvedCreateStatementEnums::DeterminismLevel);

    // 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 {
      return DeterminismLevelToVolatility(determinism_level());
    }

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;

SqlSecurity sql_security() const;

DeterminismLevel determinism_level() const; };

ResolvedArgumentDef


// 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;

ArgumentKind argument_kind() const; };

ResolvedArgumentRef


// 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;

ArgumentKind argument_kind() const; };

ResolvedCreateTableFunctionStmt


// 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'.
//
// ----------------------
// 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;

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;

SqlSecurity sql_security() const; };

ResolvedRelationArgumentScan


// 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; };

ResolvedArgumentList


// 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; };

ResolvedFunctionSignatureHolder


// This wrapper is used for an optional FunctionSignature.
class ResolvedFunctionSignatureHolder : public ResolvedArgument {
  static const ResolvedNodeKind TYPE = RESOLVED_FUNCTION_SIGNATURE_HOLDER;

const FunctionSignature& signature() const; };

ResolvedDropFunctionStmt


// 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; };

ResolvedDropTableFunctionStmt


// 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; };

ResolvedCallStmt


// 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; };

ResolvedImportStmt


// 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);

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; };

ResolvedModuleStmt


// 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; };

ResolvedAggregateHavingModifier


// 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);

HavingModifierKind kind() const;

const ResolvedExpr* having_expr() const; };

ResolvedCreateMaterializedViewStmt


// This statement:
//   CREATE MATERIALIZED VIEW <name> [(...)] [PARTITION BY expr, ...]
//   [CLUSTER BY expr, ...] [OPTIONS (...)] AS SELECT ...
//
// <column_definition_list> matches 1:1 with the <output_column_list> in
// ResolvedCreateViewBase and provides explicit definition for each
// ResolvedColumn produced by <query>. 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_definition_list>, but when/if we
// allow specifying column OPTIONS as part of CMV statement, this information
// will be available only in <column_definition_list>. Therefore, consumers
// are encouraged to read from <column_definition_list> rather than from
// <output_column_list> to determine the schema, if possible.
//
// <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 ResolvedColumnDefinition>>& column_definition_list() const; int column_definition_list_size() const; const ResolvedColumnDefinition* column_definition_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; };

ResolvedCreateProcedureStmt


// This statement creates a user-defined procedure:
// CREATE [OR REPLACE] [TEMP] PROCEDURE [IF NOT EXISTS] <name_path>
// (<arg_list>) [OPTIONS (<option_list>)]
// BEGIN
// <procedure_body>
// END;
//
// <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.
// <option_list> has engine-specific directives for modifying procedures.
// <procedure_body> is a string literal that contains the procedure body.
//        It includes everything from the BEGIN keyword to the END keyword,
//        inclusive.
//
//        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.
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; };

ResolvedExecuteImmediateArgument


// 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; };

ResolvedExecuteImmediateStmt


// 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; };

ResolvedAssignmentStmt


// 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; };

ResolvedCreateEntityStmt


// (broken link)
// This statement:
// CREATE [OR REPLACE] <entity_type> [IF NOT EXISTS] <path_expression>
// [OPTIONS <option_list>]
// [AS <entity_body_json>];
//
// <entity_type> engine-specific entity type to be created.
// <entity_body_json> is a JSON 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::vector<std::unique_ptr<const ResolvedOption>>& option_list() const; int option_list_size() const; const ResolvedOption* option_list(int i) const; };

ResolvedAlterEntityStmt


// (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; };

ResolvedPivotColumn


// 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; };

ResolvedPivotScan


// 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; };

ResolvedReturningClause


// 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; };

ResolvedUnpivotArg


// 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; };

ResolvedUnpivotScan


// 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; };