* Verify that the tuples to be produced by INSERT match the * target relation's rowtype * * We do this to guard against stale plans. If plan invalidation is * functioning properly then we should never get a failure here, but better * safe than sorry. Note that this is called after we have obtained lock * on the target rel, so the rowtype can't change underneath us. * * The plan output is
| 161 | * are done in ExecBuildUpdateProjection. |
| 162 | */ |
| 163 | static void |
| 164 | ExecCheckPlanOutput(Relation resultRel, List *targetList) |
| 165 | { |
| 166 | TupleDesc resultDesc = RelationGetDescr(resultRel); |
| 167 | int attno = 0; |
| 168 | ListCell *lc; |
| 169 | |
| 170 | foreach(lc, targetList) |
| 171 | { |
| 172 | TargetEntry *tle = (TargetEntry *) lfirst(lc); |
| 173 | Form_pg_attribute attr; |
| 174 | |
| 175 | Assert(!tle->resjunk); /* caller removed junk items already */ |
| 176 | |
| 177 | if (attno >= resultDesc->natts) |
| 178 | ereport(ERROR, |
| 179 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 180 | errmsg("table row type and query-specified row type do not match"), |
| 181 | errdetail("Query has too many columns."))); |
| 182 | attr = TupleDescAttr(resultDesc, attno); |
| 183 | attno++; |
| 184 | |
| 185 | if (!attr->attisdropped) |
| 186 | { |
| 187 | /* Normal case: demand type match */ |
| 188 | if (exprType((Node *) tle->expr) != attr->atttypid) |
| 189 | ereport(ERROR, |
| 190 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 191 | errmsg("table row type and query-specified row type do not match"), |
| 192 | errdetail("Table has type %s at ordinal position %d, but query expects %s.", |
| 193 | format_type_be(attr->atttypid), |
| 194 | attno, |
| 195 | format_type_be(exprType((Node *) tle->expr))))); |
| 196 | } |
| 197 | else |
| 198 | { |
| 199 | /* |
| 200 | * For a dropped column, we can't check atttypid (it's likely 0). |
| 201 | * In any case the planner has most likely inserted an INT4 null. |
| 202 | * What we insist on is just *some* NULL constant. |
| 203 | */ |
| 204 | /* GPDB_96_MERGE_FIXME: the subplan can be a Motion, so that the NULLs |
| 205 | * are transferred through the Motion node. |
| 206 | */ |
| 207 | #if 0 |
| 208 | if (!IsA(tle->expr, Const) || |
| 209 | !((Const *) tle->expr)->constisnull) |
| 210 | ereport(ERROR, |
| 211 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 212 | errmsg("table row type and query-specified row type do not match"), |
| 213 | errdetail("Query provides a value for a dropped column at ordinal position %d.", |
| 214 | attno))); |
| 215 | #endif |
| 216 | } |
| 217 | } |
| 218 | if (attno != resultDesc->natts) |
| 219 | ereport(ERROR, |
| 220 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
no test coverage detected