* get_partition_for_tuple * Finds partition of relation which accepts the partition key specified * in values and isnull. * * Calling this function can be quite expensive when LIST and RANGE * partitioned tables have many partitions. This is due to the binary search * that's done to find the correct partition. Many of the use cases for LIST * and RANGE partitioned tables make it likely
| 1359 | * found or -1 if none found. |
| 1360 | */ |
| 1361 | int |
| 1362 | get_partition_for_tuple(PartitionKey key, PartitionDesc partdesc, Datum *values, bool *isnull) |
| 1363 | { |
| 1364 | int bound_offset = -1; |
| 1365 | int part_index = -1; |
| 1366 | PartitionBoundInfo boundinfo = partdesc->boundinfo; |
| 1367 | |
| 1368 | if (partdesc->nparts == 0) |
| 1369 | return part_index; |
| 1370 | /* |
| 1371 | * In the switch statement below, when we perform a cached lookup for |
| 1372 | * RANGE and LIST partitioned tables, if we find that the last found |
| 1373 | * partition matches the 'values', we return the partition index right |
| 1374 | * away. We do this instead of breaking out of the switch as we don't |
| 1375 | * want to execute the code about the DEFAULT partition or do any updates |
| 1376 | * for any of the cache-related fields. That would be a waste of effort |
| 1377 | * as we already know it's not the DEFAULT partition and have no need to |
| 1378 | * increment the number of times we found the same partition any higher |
| 1379 | * than PARTITION_CACHED_FIND_THRESHOLD. |
| 1380 | */ |
| 1381 | |
| 1382 | /* Route as appropriate based on partitioning strategy. */ |
| 1383 | switch (key->strategy) |
| 1384 | { |
| 1385 | case PARTITION_STRATEGY_HASH: |
| 1386 | { |
| 1387 | uint64 rowHash; |
| 1388 | |
| 1389 | /* hash partitioning is too cheap to bother caching */ |
| 1390 | rowHash = compute_partition_hash_value(key->partnatts, |
| 1391 | key->partsupfunc, |
| 1392 | key->partcollation, |
| 1393 | values, isnull); |
| 1394 | |
| 1395 | /* |
| 1396 | * HASH partitions can't have a DEFAULT partition and we don't |
| 1397 | * do any caching work for them, so just return the part index |
| 1398 | */ |
| 1399 | return boundinfo->indexes[rowHash % boundinfo->nindexes]; |
| 1400 | } |
| 1401 | |
| 1402 | case PARTITION_STRATEGY_LIST: |
| 1403 | if (isnull[0]) |
| 1404 | { |
| 1405 | /* this is far too cheap to bother doing any caching */ |
| 1406 | if (partition_bound_accepts_nulls(boundinfo)) |
| 1407 | { |
| 1408 | /* |
| 1409 | * When there is a NULL partition we just return that |
| 1410 | * directly. We don't have a bound_offset so it's not |
| 1411 | * valid to drop into the code after the switch which |
| 1412 | * checks and updates the cache fields. We perhaps should |
| 1413 | * be invalidating the details of the last cached |
| 1414 | * partition but there's no real need to. Keeping those |
| 1415 | * fields set gives a chance at matching to the cached |
| 1416 | * partition on the next lookup. |
| 1417 | */ |
| 1418 | return boundinfo->null_index; |
no test coverage detected