docs: protected SqlNode performUnconditionalRewrites(
  		SqlNode node,
  		boolean underFrom) {
  		if (node == null) {
  			return node;
  		}
  
  		SqlNode newOperand;
  
  		// first transform operands and invoke generic call rewrite
  		if (node instanceof SqlCall) {
  			if (node instanceof SqlMerge) {
  				validatingSqlMerge = true;
  			}
  			SqlCall call = (SqlCall) node;
  			final SqlKind kind = call.getKind();
  			final List<SqlNode> operands = call.getOperandList();
  			for (int i = 0; i < operands.size(); i++) {
  				SqlNode operand = operands.get(i);
  				boolean childUnderFrom;
  				if (kind == SqlKind.SELECT) {
  					childUnderFrom = i == SqlSelect.FROM_OPERAND;
  				} else if (kind == SqlKind.AS && (i == 0)) {
  					// for an aliased expression, it is under FROM if
  					// the AS expression is under FROM
  					childUnderFrom = underFrom;
  				} else {
  					childUnderFrom = false;
  				}
  				newOperand =
  					performUnconditionalRewrites(operand, childUnderFrom);
  				if (newOperand != null && newOperand != operand) {
  					call.setOperand(i, newOperand);
  				}
  			}
  
  			if (call.getOperator() instanceof SqlUnresolvedFunction) {
  				assert call instanceof SqlBasicCall;
  				final SqlUnresolvedFunction function =
  					(SqlUnresolvedFunction) call.getOperator();
  				// This function hasn't been resolved yet.  Perform
  				// a half-hearted resolution now in case it's a
  				// builtin function requiring special casing.  If it's
  				// not, we'll handle it later during overload resolution.
  				final List<SqlOperator> overloads = new ArrayList<>();
  				opTab.lookupOperatorOverloads(function.getNameAsId(),
  					function.getFunctionType(), SqlSyntax.FUNCTION, overloads);
  				if (overloads.size() == 1) {
  					((SqlBasicCall) call).setOperator(overloads.get(0));
  				}
  			}
  			if (rewriteCalls) {
  				node = call.getOperator().rewriteCall(this, call);
  			}
  		} else if (node instanceof SqlNodeList) {
  			SqlNodeList list = (SqlNodeList) node;
  			for (int i = 0, count = list.size(); i < count; i++) {
  				SqlNode operand = list.get(i);
  				newOperand =
  					performUnconditionalRewrites(
  						operand,
  						false);
  				if (newOperand != null) {
  					list.getList().set(i, newOperand);
  				}
  			}
  		}
  
  		// now transform node itself
  		final SqlKind kind = node.getKind();
  		switch (kind) {
  			case VALUES:
  				// CHECKSTYLE: IGNORE 1
  				if (underFrom || true) {
  					// leave FROM (VALUES(...)) [ AS alias ] clauses alone,
  					// otherwise they grow cancerously if this rewrite is invoked
  					// over and over
  					return node;
  				} else {
  					final SqlNodeList selectList =
  						new SqlNodeList(SqlParserPos.ZERO);
  					selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
  					return new SqlSelect(node.getParserPosition(), null, selectList, node,
  						null, null, null, null, null, null, null);
  				}
  
  			case ORDER_BY: {
  				SqlOrderBy orderBy = (SqlOrderBy) node;
  				handleOffsetFetch(orderBy.offset, orderBy.fetch);
  				if (orderBy.query instanceof SqlSelect) {
  					SqlSelect select = (SqlSelect) orderBy.query;
  
  					// Don't clobber existing ORDER BY.  It may be needed for
  					// an order-sensitive function like RANK.
  					if (select.getOrderList() == null) {
  						// push ORDER BY into existing select
  						select.setOrderBy(orderBy.orderList);
  						select.setOffset(orderBy.offset);
  						select.setFetch(orderBy.fetch);
  						return select;
  					}
  				}
  				if (orderBy.query instanceof SqlWith
  					&& ((SqlWith) orderBy.query).body instanceof SqlSelect) {
  					SqlWith with = (SqlWith) orderBy.query;
  					SqlSelect select = (SqlSelect) with.body;
  
  					// Don't clobber existing ORDER BY.  It may be needed for
  					// an order-sensitive function like RANK.
  					if (select.getOrderList() == null) {
  						// push ORDER BY into existing select
  						select.setOrderBy(orderBy.orderList);
  						select.setOffset(orderBy.offset);
  						select.setFetch(orderBy.fetch);
  						return with;
  					}
  				}
  				final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
  				selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
  				final SqlNodeList orderList;
  				if (getInnerSelect(node) != null && isAggregate(getInnerSelect(node))) {
  					orderList = SqlNode.clone(orderBy.orderList);
  					// We assume that ORDER BY item does not have ASC etc.
  					// We assume that ORDER BY item is present in SELECT list.
  					for (int i = 0; i < orderList.size(); i++) {
  						SqlNode sqlNode = orderList.get(i);
  						SqlNodeList selectList2 = getInnerSelect(node).getSelectList();
  						for (Ord<SqlNode> sel : Ord.zip(selectList2)) {
  							if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) {
  								orderList.set(i,
  									SqlLiteral.createExactNumeric(Integer.toString(sel.i + 1),
  										SqlParserPos.ZERO));
  							}
  						}
  					}
  				} else {
  					orderList = orderBy.orderList;
  				}
  				return new SqlSelect(SqlParserPos.ZERO, null, selectList, orderBy.query,
  					null, null, null, null, orderList, orderBy.offset,
  					orderBy.fetch);
  			}
  
  			case EXPLICIT_TABLE: {
  				// (TABLE t) is equivalent to (SELECT * FROM t)
  				SqlCall call = (SqlCall) node;
  				final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
  				selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
  				return new SqlSelect(SqlParserPos.ZERO, null, selectList, call.operand(0),
  					null, null, null, null, null, null, null);
  			}
  
  			case DELETE: {
  				SqlDelete call = (SqlDelete) node;
  				SqlSelect select = createSourceSelectForDelete(call);
  				call.setSourceSelect(select);
  				break;
  			}
  
  			case UPDATE: {
  				SqlUpdate call = (SqlUpdate) node;
  				SqlSelect select = createSourceSelectForUpdate(call);
  				call.setSourceSelect(select);
  
  				// See if we're supposed to rewrite UPDATE to MERGE
  				// (unless this is the UPDATE clause of a MERGE,
  				// in which case leave it alone).
  				if (!validatingSqlMerge) {
  					SqlNode selfJoinSrcExpr =
  						getSelfJoinExprForUpdate(
  							call.getTargetTable(),
  							UPDATE_SRC_ALIAS);
  					if (selfJoinSrcExpr != null) {
  						node = rewriteUpdateToMerge(call, selfJoinSrcExpr);
  					}
  				}
  				break;
  			}
  
  			case MERGE: {
  				SqlMerge call = (SqlMerge) node;
  				rewriteMerge(call);
  				break;
  			}
  		}
  		return node;
  	}