| Line | Hits | Source | Commit |
| 118 |
- |
transformWithClause(ParseState *pstate, WithClause *withClause) |
- |
| 119 |
- |
{ |
- |
| 120 |
- |
ListCell *lc; |
- |
| 121 |
- |
|
- |
| 122 |
- |
/* Only one WITH clause per query level */ |
- |
| 123 |
- |
Assert(pstate->p_ctenamespace == NIL); |
- |
| 124 |
- |
Assert(pstate->p_future_ctes == NIL); |
- |
| 125 |
- |
|
- |
| 126 |
- |
/* |
- |
| 127 |
- |
* For either type of WITH, there must not be duplicate CTE names in the |
- |
| 128 |
- |
* list. Check this right away so we needn't worry later. |
- |
| 129 |
- |
* |
- |
| 130 |
- |
* Also, tentatively mark each CTE as non-recursive, and initialize its |
- |
| 131 |
- |
* reference count to zero, and set pstate->p_hasModifyingCTE if needed. |
- |
| 132 |
- |
*/ |
- |
| 133 |
- |
foreach(lc, withClause->ctes) |
- |
| 134 |
- |
{ |
- |
| 135 |
- |
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); |
- |
| 136 |
- |
ListCell *rest; |
- |
| 137 |
- |
|
- |
| 138 |
- |
for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc)) |
- |
| 139 |
- |
{ |
- |
| 140 |
- |
CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest); |
- |
| 141 |
- |
|
- |
| 142 |
- |
if (strcmp(cte->ctename, cte2->ctename) == 0) |
- |
| 143 |
- |
ereport(ERROR, |
- |
| 144 |
- |
(errcode(ERRCODE_DUPLICATE_ALIAS), |
- |
| 145 |
- |
errmsg("WITH query name \"%s\" specified more than once", |
- |
| 146 |
- |
cte2->ctename), |
- |
| 147 |
- |
parser_errposition(pstate, cte2->location))); |
- |
| 148 |
- |
} |
- |
| 149 |
- |
|
- |
| 150 |
- |
cte->cterecursive = false; |
- |
| 151 |
- |
cte->cterefcount = 0; |
- |
| 152 |
- |
|
- |
| 153 |
- |
if (!IsA(cte->ctequery, SelectStmt)) |
- |
| 154 |
- |
{ |
- |
| 155 |
- |
/* must be a data-modifying statement */ |
- |
| 156 |
- |
Assert(IsA(cte->ctequery, InsertStmt) || |
- |
| 157 |
- |
IsA(cte->ctequery, UpdateStmt) || |
- |
| 158 |
- |
IsA(cte->ctequery, DeleteStmt) || |
- |
| 159 |
- |
IsA(cte->ctequery, MergeStmt)); |
- |
| 160 |
- |
|
- |
| 161 |
- |
pstate->p_hasModifyingCTE = true; |
- |
| 162 |
- |
} |
- |
| 163 |
- |
} |
- |
| 164 |
- |
|
- |
| 165 |
- |
if (withClause->recursive) |
- |
| 166 |
- |
{ |
- |
| 167 |
- |
/* |
- |
| 168 |
- |
* For WITH RECURSIVE, we rearrange the list elements if needed to |
- |
| 169 |
- |
* eliminate forward references. First, build a work array and set up |
- |
| 170 |
- |
* the data structure needed by the tree walkers. |
- |
| 171 |
- |
*/ |
- |
| 172 |
- |
CteState cstate; |
- |
| 173 |
- |
int i; |
- |
| 174 |
- |
|
- |
| 175 |
- |
/* |
c54ba27Row pattern recognition patch (parse/analysis). |
| 176 |
- |
* Per ISO/IEC 9075-2:2016 7.17 Syntax Rule 3)e)f), every <with list |
c54ba27Row pattern recognition patch (parse/analysis). |
| 177 |
- |
* element> in a WITH RECURSIVE clause is "potentially recursive" and |
c54ba27Row pattern recognition patch (parse/analysis). |
| 178 |
- |
* shall not contain a <row pattern common syntax>. (PostgreSQL does |
c54ba27Row pattern recognition patch (parse/analysis). |
| 179 |
- |
* not implement <row pattern measures>, so only the common syntax |
c54ba27Row pattern recognition patch (parse/analysis). |
| 180 |
- |
* needs to be checked.) ISO/IEC 19075-5 6.17.5 (R020) and 4.18.5 |
c54ba27Row pattern recognition patch (parse/analysis). |
| 181 |
- |
* (R010) restate the prohibition for CREATE RECURSIVE VIEW, which is |
c54ba27Row pattern recognition patch (parse/analysis). |
| 182 |
- |
* rewritten to WITH RECURSIVE by makeRecursiveViewSelect() and so |
c54ba27Row pattern recognition patch (parse/analysis). |
| 183 |
- |
* flows through here as well. |
c54ba27Row pattern recognition patch (parse/analysis). |
| 184 |
- |
*/ |
c54ba27Row pattern recognition patch (parse/analysis). |
| 185 |
1622 |
foreach_node(CommonTableExpr, cte, withClause->ctes) |
c54ba27Row pattern recognition patch (parse/analysis). |
| 186 |
- |
{ |
c54ba27Row pattern recognition patch (parse/analysis). |
| 187 |
847 |
ContainRPRContext ctx; |
c54ba27Row pattern recognition patch (parse/analysis). |
| 188 |
- |
|
c54ba27Row pattern recognition patch (parse/analysis). |
| 189 |
847 |
ctx.location = -1; |
c54ba27Row pattern recognition patch (parse/analysis). |
| 190 |
847 |
if (contain_rpr_walker(cte->ctequery, &ctx)) |
c54ba27Row pattern recognition patch (parse/analysis). |
| 191 |
847 |
ereport(ERROR, |
c54ba27Row pattern recognition patch (parse/analysis). |
| 192 |
- |
errcode(ERRCODE_SYNTAX_ERROR), |
c54ba27Row pattern recognition patch (parse/analysis). |
| 193 |
- |
errmsg("cannot use row pattern recognition in a recursive query"), |
c54ba27Row pattern recognition patch (parse/analysis). |
| 194 |
- |
parser_errposition(pstate, ctx.location)); |
c54ba27Row pattern recognition patch (parse/analysis). |
| 195 |
- |
} |
c54ba27Row pattern recognition patch (parse/analysis). |
| 196 |
- |
|
c54ba27Row pattern recognition patch (parse/analysis). |
| 197 |
- |
cstate.pstate = pstate; |
- |
| 198 |
- |
cstate.numitems = list_length(withClause->ctes); |
- |
| 199 |
- |
cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem)); |
- |
| 200 |
- |
i = 0; |
- |
| 201 |
- |
foreach(lc, withClause->ctes) |
- |
| 202 |
- |
{ |
- |
| 203 |
- |
cstate.items[i].cte = (CommonTableExpr *) lfirst(lc); |
- |
| 204 |
- |
cstate.items[i].id = i; |
- |
| 205 |
- |
i++; |
- |
| 206 |
- |
} |
- |
| 207 |
- |
|
- |
| 208 |
- |
/* |
- |
| 209 |
- |
* Find all the dependencies and sort the CteItems into a safe |
- |
| 210 |
- |
* processing order. Also, mark CTEs that contain self-references. |
- |
| 211 |
- |
*/ |
- |
| 212 |
- |
makeDependencyGraph(&cstate); |
- |
| 213 |
- |
|
- |
| 214 |
- |
/* |
- |
| 215 |
- |
* Check that recursive queries are well-formed. |
- |
| 216 |
- |
*/ |
- |
| 217 |
- |
checkWellFormedRecursion(&cstate); |
- |
| 218 |
- |
|
- |
| 219 |
- |
/* |
- |
| 220 |
- |
* Set up the ctenamespace for parse analysis. Per spec, all the WITH |
- |
| 221 |
- |
* items are visible to all others, so stuff them all in before parse |
- |
| 222 |
- |
* analysis. We build the list in safe processing order so that the |
- |
| 223 |
- |
* planner can process the queries in sequence. |
- |
| 224 |
- |
*/ |
- |
| 225 |
- |
for (i = 0; i < cstate.numitems; i++) |
- |
| 226 |
- |
{ |
- |
| 227 |
- |
CommonTableExpr *cte = cstate.items[i].cte; |
- |
| 228 |
- |
|
- |
| 229 |
- |
pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte); |
- |
| 230 |
- |
} |
- |
| 231 |
- |
|
- |
| 232 |
- |
/* |
- |
| 233 |
- |
* Do parse analysis in the order determined by the topological sort. |
- |
| 234 |
- |
*/ |
- |
| 235 |
- |
for (i = 0; i < cstate.numitems; i++) |
- |
| 236 |
- |
{ |
- |
| 237 |
- |
CommonTableExpr *cte = cstate.items[i].cte; |
- |
| 238 |
- |
|
- |
| 239 |
- |
analyzeCTE(pstate, cte); |
- |
| 240 |
- |
} |
- |
| 241 |
- |
} |
- |
| 242 |
- |
else |
- |
| 243 |
- |
{ |
- |
| 244 |
- |
/* |
- |
| 245 |
- |
* For non-recursive WITH, just analyze each CTE in sequence and then |
- |
| 246 |
- |
* add it to the ctenamespace. This corresponds to the spec's |
- |
| 247 |
- |
* definition of the scope of each WITH name. However, to allow error |
- |
| 248 |
- |
* reports to be aware of the possibility of an erroneous reference, |
- |
| 249 |
- |
* we maintain a list in p_future_ctes of the not-yet-visible CTEs. |
- |
| 250 |
- |
*/ |
- |
| 251 |
- |
pstate->p_future_ctes = list_copy(withClause->ctes); |
- |
| 252 |
- |
|
- |
| 253 |
- |
foreach(lc, withClause->ctes) |
- |
| 254 |
- |
{ |
- |
| 255 |
- |
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); |
- |
| 256 |
- |
|
- |
| 257 |
- |
analyzeCTE(pstate, cte); |
- |
| 258 |
- |
pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte); |
- |
| 259 |
- |
pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes); |
- |
| 260 |
- |
} |
- |
| 261 |
- |
} |
- |
| 262 |
- |
|
- |
| 263 |
- |
return pstate->p_ctenamespace; |
- |
| 264 |
- |
} |
- |