| 3749 | |
| 3750 | |
| 3751 | static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* source) |
| 3752 | { |
| 3753 | bool couldBeCte = true; |
| 3754 | MetaName relName; |
| 3755 | string relAlias; |
| 3756 | |
| 3757 | if (auto procNode = nodeAs<ProcedureSourceNode>(source)) |
| 3758 | { |
| 3759 | relName = procNode->dsqlName.identifier; |
| 3760 | relAlias = procNode->alias; |
| 3761 | couldBeCte = !procNode->sourceList && procNode->dsqlName.package.isEmpty(); |
| 3762 | } |
| 3763 | else if (auto relNode = nodeAs<RelationSourceNode>(source)) |
| 3764 | { |
| 3765 | relName = relNode->dsqlName; |
| 3766 | relAlias = relNode->alias; |
| 3767 | } |
| 3768 | //// TODO: LocalTableSourceNode |
| 3769 | else |
| 3770 | fb_assert(false); |
| 3771 | |
| 3772 | if (relAlias.isEmpty()) |
| 3773 | relAlias = relName.c_str(); |
| 3774 | |
| 3775 | SelectExprNode* cte = couldBeCte ? dsqlScratch->findCTE(relName) : NULL; |
| 3776 | |
| 3777 | if (!cte) |
| 3778 | return PASS1_relation(dsqlScratch, source); |
| 3779 | |
| 3780 | cte->dsqlFlags |= RecordSourceNode::DFLAG_DT_CTE_USED; |
| 3781 | |
| 3782 | if ((dsqlScratch->flags & DsqlCompilerScratch::FLAG_RECURSIVE_CTE) && |
| 3783 | dsqlScratch->currCtes.hasData() && |
| 3784 | (dsqlScratch->currCtes.object() == cte)) |
| 3785 | { |
| 3786 | ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << |
| 3787 | // Recursive CTE member (%s) can refer itself only in FROM clause |
| 3788 | Arg::Gds(isc_dsql_cte_wrong_reference) << relName); |
| 3789 | } |
| 3790 | |
| 3791 | for (Stack<SelectExprNode*>::const_iterator stack(dsqlScratch->currCtes); stack.hasData(); ++stack) |
| 3792 | { |
| 3793 | SelectExprNode* cte1 = stack.object(); |
| 3794 | if (cte1 == cte) |
| 3795 | { |
| 3796 | ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << |
| 3797 | // CTE %s has cyclic dependencies |
| 3798 | Arg::Gds(isc_dsql_cte_cycle) << relName); |
| 3799 | } |
| 3800 | } |
| 3801 | |
| 3802 | RecordSourceNode* const query = cte->querySpec; |
| 3803 | UnionSourceNode* unionQuery = nodeAs<UnionSourceNode>(query); |
| 3804 | const bool isRecursive = unionQuery && unionQuery->recursive; |
| 3805 | |
| 3806 | const string saveCteName = cte->alias; |
| 3807 | if (!isRecursive) |
| 3808 | cte->alias = relAlias; |
no test coverage detected