* GetCachedPlan: get a cached plan from a CachedPlanSource. * * This function hides the logic that decides whether to use a generic * plan or a custom plan for the given parameters: the caller does not know * which it will get. * * On return, the plan is valid and we have sufficient locks to begin * execution. * * On return, the refcount of the plan has been incremented; a later * Releas
| 1246 | * therefore also forces the plan to be re-planned on next call. |
| 1247 | */ |
| 1248 | CachedPlan * |
| 1249 | GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, |
| 1250 | ResourceOwner owner, QueryEnvironment *queryEnv, IntoClause *intoClause) |
| 1251 | { |
| 1252 | CachedPlan *plan = NULL; |
| 1253 | List *qlist; |
| 1254 | bool customplan; |
| 1255 | |
| 1256 | /* Assert caller is doing things in a sane order */ |
| 1257 | Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); |
| 1258 | Assert(plansource->is_complete); |
| 1259 | /* This seems worth a real test, though */ |
| 1260 | if (owner && !plansource->is_saved) |
| 1261 | elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan"); |
| 1262 | |
| 1263 | /* Make sure the querytree list is valid and we have parse-time locks */ |
| 1264 | qlist = RevalidateCachedQuery(plansource, queryEnv, intoClause); |
| 1265 | |
| 1266 | /* Decide whether to use a custom plan */ |
| 1267 | customplan = choose_custom_plan(plansource, boundParams, intoClause); |
| 1268 | |
| 1269 | if (!customplan) |
| 1270 | { |
| 1271 | if (CheckCachedPlan(plansource)) |
| 1272 | { |
| 1273 | /* We want a generic plan, and we already have a valid one */ |
| 1274 | plan = plansource->gplan; |
| 1275 | Assert(plan->magic == CACHEDPLAN_MAGIC); |
| 1276 | } |
| 1277 | else |
| 1278 | { |
| 1279 | /* Build a new generic plan */ |
| 1280 | plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv, NULL); |
| 1281 | /* Just make real sure plansource->gplan is clear */ |
| 1282 | ReleaseGenericPlan(plansource); |
| 1283 | /* Link the new generic plan into the plansource */ |
| 1284 | plansource->gplan = plan; |
| 1285 | plan->refcount++; |
| 1286 | /* Immediately reparent into appropriate context */ |
| 1287 | if (plansource->is_saved) |
| 1288 | { |
| 1289 | /* saved plans all live under CacheMemoryContext */ |
| 1290 | MemoryContextSetParent(plan->context, CacheMemoryContext); |
| 1291 | plan->is_saved = true; |
| 1292 | } |
| 1293 | else |
| 1294 | { |
| 1295 | /* otherwise, it should be a sibling of the plansource */ |
| 1296 | MemoryContextSetParent(plan->context, |
| 1297 | MemoryContextGetParent(plansource->context)); |
| 1298 | } |
| 1299 | /* Update generic_cost whenever we make a new generic plan */ |
| 1300 | plansource->generic_cost = cached_plan_cost(plan, false); |
| 1301 | |
| 1302 | /* |
| 1303 | * If, based on the now-known value of generic_cost, we'd not have |
| 1304 | * chosen to use a generic plan, then forget it and make a custom |
| 1305 | * plan. This is a bit of a wart but is necessary to avoid a |
no test coverage detected