* ExpandColumnRefStar() * Transforms foo.* into a list of expressions or targetlist entries. * * This handles the case where '*' appears as the last or only item in a * ColumnRef. The code is shared between the case of foo.* at the top level * in a SELECT target list (where we want TargetEntry nodes in the result) * and foo.* in a ROW() or VALUES() construct (where we want just bare * exp
| 1115 | * The referenced columns are marked as requiring SELECT access. |
| 1116 | */ |
| 1117 | static List * |
| 1118 | ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref, |
| 1119 | bool make_target_entry) |
| 1120 | { |
| 1121 | List *fields = cref->fields; |
| 1122 | int numnames = list_length(fields); |
| 1123 | |
| 1124 | if (numnames == 1) |
| 1125 | { |
| 1126 | /* |
| 1127 | * Target item is a bare '*', expand all tables |
| 1128 | * |
| 1129 | * (e.g., SELECT * FROM emp, dept) |
| 1130 | * |
| 1131 | * Since the grammar only accepts bare '*' at top level of SELECT, we |
| 1132 | * need not handle the make_target_entry==false case here. |
| 1133 | */ |
| 1134 | if (!make_target_entry) |
| 1135 | elog(ERROR, "invalid use of *"); |
| 1136 | |
| 1137 | return ExpandAllTables(pstate, cref->location); |
| 1138 | } |
| 1139 | else |
| 1140 | { |
| 1141 | /* |
| 1142 | * Target item is relation.*, expand that table |
| 1143 | * |
| 1144 | * (e.g., SELECT emp.*, dname FROM emp, dept) |
| 1145 | * |
| 1146 | * Note: this code is a lot like transformColumnRef; it's tempting to |
| 1147 | * call that instead and then replace the resulting whole-row Var with |
| 1148 | * a list of Vars. However, that would leave us with the RTE's |
| 1149 | * selectedCols bitmap showing the whole row as needing select |
| 1150 | * permission, as well as the individual columns. That would be |
| 1151 | * incorrect (since columns added later shouldn't need select |
| 1152 | * permissions). We could try to remove the whole-row permission bit |
| 1153 | * after the fact, but duplicating code is less messy. |
| 1154 | */ |
| 1155 | char *nspname = NULL; |
| 1156 | char *relname = NULL; |
| 1157 | ParseNamespaceItem *nsitem = NULL; |
| 1158 | int levels_up; |
| 1159 | enum |
| 1160 | { |
| 1161 | CRSERR_NO_RTE, |
| 1162 | CRSERR_WRONG_DB, |
| 1163 | CRSERR_TOO_MANY |
| 1164 | } crserr = CRSERR_NO_RTE; |
| 1165 | |
| 1166 | /* |
| 1167 | * Give the PreParseColumnRefHook, if any, first shot. If it returns |
| 1168 | * non-null then we should use that expression. |
| 1169 | */ |
| 1170 | if (pstate->p_pre_columnref_hook != NULL) |
| 1171 | { |
| 1172 | Node *node; |
| 1173 | |
| 1174 | node = pstate->p_pre_columnref_hook(pstate, cref); |
no test coverage detected