visitSelectStatement method

  1. @override
void visitSelectStatement(
  1. SelectStatement e,
  2. void arg
)
override

Implementation

@override
void visitSelectStatement(SelectStatement e, void arg) {
  // a select statement can appear as a sub query which has its own scope, so
  // we need to fork the scope here. There is one special case though:
  // Select statements that appear as a query source can't depend on data
  // defined in the outer scope. This is different from select statements
  // that work as expressions.
  // For instance, if you go to sqliteonline.com and issue the following
  // query: "SELECT * FROM demo d1,
  //   (SELECT * FROM demo i WHERE i.id = d1.id) d2;"
  // it won't work.

  final isInFROM = e.parent is Queryable;
  StatementScope scope;

  if (isInFROM) {
    final surroundingSelect = e.parents
        .firstWhere((node) => node is HasFrom)
        .scope as StatementScope;
    scope = StatementScope(SourceScope(surroundingSelect));
  } else {
    scope = StatementScope.forStatement(context.rootScope, e);
  }

  e.scope = scope;

  for (final windowDecl in e.windowDeclarations) {
    scope.windowDeclarations[windowDecl.name] = windowDecl;
  }

  // only the last statement in a compound select statement may have an order
  // by or a limit clause
  if (e.parent is CompoundSelectPart || e.parent is CompoundSelectStatement) {
    bool isLast;
    if (e.parent is CompoundSelectPart) {
      final part = e.parent as CompoundSelectPart;
      final compoundSelect = part.parent as CompoundSelectStatement;

      final index = compoundSelect.additional.indexOf(part);
      isLast = index == compoundSelect.additional.length - 1;
    } else {
      // if the parent is the compound select statement, this select query is
      // the [CompoundSelectStatement.base], so definitely not the last query.
      isLast = false;
    }

    if (!isLast) {
      if (e.limit != null) {
        context.reportError(AnalysisError(
          type: AnalysisErrorType.synctactic,
          message: 'Limit clause must appear in the last compound statement',
          relevantNode: e.limit,
        ));
      }
      if (e.orderBy != null) {
        context.reportError(AnalysisError(
          type: AnalysisErrorType.synctactic,
          message: 'Order by clause must appear in the compound statement',
          relevantNode: e.orderBy,
        ));
      }
    }
  }

  visitChildren(e, arg);
}