Check if rse is recursive. If recursive reference is a table in the FROM list remove it. If recursive reference is a part of join add join boolean (returned by pass1JoinIsRecursive) to the WHERE clause. Punt if more than one recursive reference is found.
| 926 | // If recursive reference is a part of join add join boolean (returned by pass1JoinIsRecursive) |
| 927 | // to the WHERE clause. Punt if more than one recursive reference is found. |
| 928 | RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input) |
| 929 | { |
| 930 | MemoryPool& pool = getPool(); |
| 931 | |
| 932 | RseNode* result = FB_NEW_POOL(getPool()) RseNode(getPool()); |
| 933 | result->dsqlFirst = input->dsqlFirst; |
| 934 | result->dsqlSkip = input->dsqlSkip; |
| 935 | result->dsqlDistinct = input->dsqlDistinct; |
| 936 | result->dsqlSelectList = input->dsqlSelectList; |
| 937 | result->dsqlWhere = input->dsqlWhere; |
| 938 | result->dsqlGroup = input->dsqlGroup; |
| 939 | result->dsqlHaving = input->dsqlHaving; |
| 940 | result->rse_plan = input->rse_plan; |
| 941 | |
| 942 | RecSourceListNode* srcTables = input->dsqlFrom; |
| 943 | RecSourceListNode* dstTables = FB_NEW_POOL(pool) RecSourceListNode(pool, srcTables->items.getCount()); |
| 944 | result->dsqlFrom = dstTables; |
| 945 | |
| 946 | NestConst<RecordSourceNode>* pDstTable = dstTables->items.begin(); |
| 947 | NestConst<RecordSourceNode>* pSrcTable = srcTables->items.begin(); |
| 948 | NestConst<RecordSourceNode>* end = srcTables->items.end(); |
| 949 | bool found = false; |
| 950 | |
| 951 | for (NestConst<RecordSourceNode>* prev = pDstTable; pSrcTable < end; ++pSrcTable, ++pDstTable) |
| 952 | { |
| 953 | *prev++ = *pDstTable = *pSrcTable; |
| 954 | |
| 955 | RseNode* rseNode = nodeAs<RseNode>(*pDstTable); |
| 956 | |
| 957 | if (rseNode) |
| 958 | { |
| 959 | fb_assert(rseNode->dsqlExplicitJoin); |
| 960 | |
| 961 | RseNode* dstRse = rseNode->clone(getPool()); |
| 962 | |
| 963 | *pDstTable = dstRse; |
| 964 | |
| 965 | BoolExprNode* joinBool = pass1JoinIsRecursive(*pDstTable->getAddress()); |
| 966 | |
| 967 | if (joinBool) |
| 968 | { |
| 969 | if (found) |
| 970 | { |
| 971 | ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << |
| 972 | // Recursive member of CTE can't reference itself more than once |
| 973 | Arg::Gds(isc_dsql_cte_mult_references)); |
| 974 | } |
| 975 | |
| 976 | found = true; |
| 977 | |
| 978 | result->dsqlWhere = PASS1_compose(result->dsqlWhere, joinBool, blr_and); |
| 979 | } |
| 980 | } |
| 981 | else if (nodeIs<ProcedureSourceNode>(*pDstTable) || nodeIs<RelationSourceNode>(*pDstTable)) |
| 982 | //// TODO: LocalTableSourceNode |
| 983 | { |
| 984 | if (pass1RelProcIsRecursive(*pDstTable)) |
| 985 | { |
nothing calls this directly
no test coverage detected