|
12 | 12 | const joins=['JOIN','LEFT JOIN','INNER JOIN','CROSS JOIN','RIGHT JOIN','FULL JOIN']; |
13 | 13 | const followingSource=['WHERE',...joins,'GROUP BY','ORDER BY','LIMIT']; |
14 | 14 | const followingPredicate=['AND','OR','GROUP BY','ORDER BY','LIMIT']; |
| 15 | + function outputAliases(tokens,position){ |
| 16 | + // Projection names belong to one SELECT, never a CTE, sibling or UNION arm. |
| 17 | + if(tokens.some(token=>is(token,'UNION','INTERSECT','EXCEPT')))return []; |
| 18 | + const begin=tokens.findLastIndex(token=>token.start<position&&is(token,'SELECT'));if(begin<0)return []; |
| 19 | + const finish=tokens.findIndex((token,index)=>index>begin&&is(token,'FROM','WHERE','GROUP','HAVING','ORDER','LIMIT','WINDOW')); |
| 20 | + const projection=tokens.slice(begin+1,finish<0?undefined:finish),groups=[[]]; |
| 21 | + for(const token of projection){if(token.value===','&&!token.quoted)groups.push([]);else groups.at(-1).push(token);} |
| 22 | + const names=[]; |
| 23 | + for(const group of groups){ |
| 24 | + const alias=group.at(-1),previous=group.at(-2);if(!alias||!previous||alias.string||!alias.quoted&&(!/^[\p{L}_][\p{L}\p{N}_$]*$/u.test(alias.value)||reserved.has(alias.upper)))continue; |
| 25 | + const explicit=is(previous,'AS')&&group.length>2; |
| 26 | + const implicit=!is(previous,'AS','COLLATE')&&previous.end<alias.start&&(previous.quoted||previous.value===')'||is(previous,'END')||/^[\p{L}\p{N}_]/u.test(previous.value)&&!reserved.has(previous.upper)); |
| 27 | + if(explicit||implicit)names.push(alias.value); |
| 28 | + } |
| 29 | + return names.filter((name,index)=>names.findIndex(other=>other.toLowerCase()===name.toLowerCase())===index&&names.filter(other=>other.toLowerCase()===name.toLowerCase()).length===1).map(spelling); |
| 30 | + } |
15 | 31 | function joinCondition(a,b){ |
16 | 32 | const possibilities=[]; |
17 | 33 | for(const [child,parent]of [[a,b],[b,a]]){ |
|
110 | 126 | const qualifier=last?.value==='.'?tokens.at(-2)?.value:null; |
111 | 127 | const wildcard=upper==='*'&&(is(tokens.at(-2),'SELECT','DISTINCT')||tokens.at(-2)?.value==='.'||clause==='SELECT'&&!insideExpression&&tokens.at(-2)?.value===','); |
112 | 128 | const operand=last&&(wildcard||last.quoted||last.value===')'||is(last,'END','NULL','TRUE','FALSE')||/^[\p{L}\p{N}_]/u.test(last.value)&&!reserved.has(last.upper)); |
113 | | - const expression=[...columnNames,...funcs,'CASE','NULL']; |
| 129 | + const aliases=!windowScope&&['ORDER','HAVING'].includes(clause)?outputAliases(allSame,position):[]; |
| 130 | + const expression=[...aliases,...columnNames,...funcs,'CASE','NULL']; |
114 | 131 | const frame=windowScope&&['ROWS','RANGE','GROUPS'].includes(clause); |
115 | 132 | const frameTokens=frame?local.slice(local.findLastIndex(t=>is(t,'ROWS','RANGE','GROUPS'))+1):[]; |
116 | 133 | const frameBetween=frameTokens.some(t=>is(t,'BETWEEN')),frameEnd=frameTokens.some(t=>is(t,'AND')); |
|
0 commit comments