@@ -704,6 +704,7 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
704
704
PG_TRY ();
705
705
{
706
706
const PartRelationInfo * prel ;
707
+ LockAcquireResult lock_result ; /* could we lock the parent? */
707
708
Datum values [Natts_pathman_config ];
708
709
bool isnull [Natts_pathman_config ];
709
710
@@ -713,57 +714,91 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
713
714
Oid base_atttype ; /* base type of prel->atttype */
714
715
Oid base_value_type ; /* base type of value_type */
715
716
716
- Datum min_rvalue , /* absolute MIN */
717
- max_rvalue ; /* absolute MAX */
718
-
719
- Oid interval_type = InvalidOid ;
720
- Datum interval_binary , /* assigned 'width' of a single partition */
721
- interval_text ;
722
-
723
- FmgrInfo interval_type_cmp ;
724
-
725
717
/* Fetch PartRelationInfo by 'relid' */
726
- prel = get_pathman_relation_info (relid );
718
+ prel = get_pathman_relation_info_after_lock (relid , true, & lock_result );
727
719
shout_if_prel_is_invalid (relid , prel , PT_RANGE );
728
720
729
721
/* Fetch base types of prel->atttype & value_type */
730
722
base_atttype = getBaseType (prel -> atttype );
731
723
base_value_type = getBaseType (value_type );
732
724
733
- /* Read max & min range values from PartRelationInfo */
734
- min_rvalue = PrelGetRangesArray (prel )[0 ].min ;
735
- max_rvalue = PrelGetRangesArray (prel )[PrelLastChild (prel )].max ;
736
-
737
- /* Copy datums on order to protect them from cache invalidation */
738
- min_rvalue = datumCopy (min_rvalue , prel -> attbyval , prel -> attlen );
739
- max_rvalue = datumCopy (max_rvalue , prel -> attbyval , prel -> attlen );
725
+ /* Search for a suitable partition if we didn't hold it */
726
+ Assert (lock_result != LOCKACQUIRE_NOT_AVAIL );
727
+ if (lock_result == LOCKACQUIRE_OK )
728
+ {
729
+ Oid * parts ;
730
+ int nparts ;
740
731
741
- /* Retrieve interval as TEXT from tuple */
742
- interval_text = values [ Anum_pathman_config_range_interval - 1 ] ;
732
+ /* Search for matching partitions */
733
+ parts = find_partitions_for_value ( value , value_type , prel , & nparts ) ;
743
734
744
- /* Convert interval to binary representation */
745
- interval_binary = extract_binary_interval_from_text (interval_text ,
746
- base_atttype ,
747
- & interval_type );
735
+ /* Shout if there's more than one */
736
+ if (nparts > 1 )
737
+ elog (ERROR , ERR_PART_ATTR_MULTIPLE );
748
738
749
- /* Fill the FmgrInfo struct with a cmp(value, part_attribute) function */
750
- fill_type_cmp_fmgr_info (& interval_type_cmp , base_value_type , base_atttype );
739
+ /* It seems that we got a partition! */
740
+ else if (nparts == 1 )
741
+ {
742
+ /* Unlock the parent (we're not going to spawn) */
743
+ xact_unlock_partitioned_rel (relid );
751
744
752
- if (SPI_connect () != SPI_OK_CONNECT )
753
- elog (ERROR , "could not connect using SPI" );
745
+ /* Simply return the suitable partition */
746
+ partid = parts [0 ];
747
+ }
754
748
755
- /* while (value >= MAX) ... */
756
- spawn_partitions (PrelParentRelid (prel ), value , max_rvalue ,
757
- base_atttype , & interval_type_cmp , interval_binary ,
758
- interval_type , true, & partid );
749
+ /* Don't forget to free */
750
+ pfree (parts );
751
+ }
759
752
760
- /* while (value < MIN) ... */
753
+ /* Else spawn a new one (we hold a lock on the parent) */
761
754
if (partid == InvalidOid )
762
- spawn_partitions (PrelParentRelid (prel ), value , min_rvalue ,
763
- base_atttype , & interval_type_cmp , interval_binary ,
764
- interval_type , false, & partid );
755
+ {
756
+ Datum min_rvalue , /* absolute MIN */
757
+ max_rvalue ; /* absolute MAX */
758
+
759
+ Oid interval_type = InvalidOid ;
760
+ Datum interval_binary , /* assigned 'width' of one partition */
761
+ interval_text ;
762
+
763
+ FmgrInfo interval_type_cmp ;
764
+
765
+ /* Read max & min range values from PartRelationInfo */
766
+ min_rvalue = PrelGetRangesArray (prel )[0 ].min ;
767
+ max_rvalue = PrelGetRangesArray (prel )[PrelLastChild (prel )].max ;
768
+
769
+ /* Copy datums on order to protect them from cache invalidation */
770
+ min_rvalue = datumCopy (min_rvalue , prel -> attbyval , prel -> attlen );
771
+ max_rvalue = datumCopy (max_rvalue , prel -> attbyval , prel -> attlen );
772
+
773
+ /* Retrieve interval as TEXT from tuple */
774
+ interval_text = values [Anum_pathman_config_range_interval - 1 ];
765
775
766
- SPI_finish (); /* close SPI connection */
776
+ /* Convert interval to binary representation */
777
+ interval_binary = extract_binary_interval_from_text (interval_text ,
778
+ base_atttype ,
779
+ & interval_type );
780
+
781
+ /* Fill the FmgrInfo struct with a cmp(value, part_attribute) */
782
+ fill_type_cmp_fmgr_info (& interval_type_cmp ,
783
+ base_value_type ,
784
+ base_atttype );
785
+
786
+ if (SPI_connect () != SPI_OK_CONNECT )
787
+ elog (ERROR , "could not connect using SPI" );
788
+
789
+ /* while (value >= MAX) ... */
790
+ spawn_partitions (PrelParentRelid (prel ), value , max_rvalue ,
791
+ base_atttype , & interval_type_cmp ,
792
+ interval_binary , interval_type , true, & partid );
793
+
794
+ /* while (value < MIN) ... */
795
+ if (partid == InvalidOid )
796
+ spawn_partitions (PrelParentRelid (prel ), value , min_rvalue ,
797
+ base_atttype , & interval_type_cmp ,
798
+ interval_binary , interval_type , false, & partid );
799
+
800
+ SPI_finish (); /* close SPI connection */
801
+ }
767
802
}
768
803
else
769
804
elog (ERROR , "pg_pathman's config does not contain relation \"%s\"" ,
@@ -1082,7 +1117,7 @@ handle_binary_opexpr(WalkerContext *context, WrapperNode *result,
1082
1117
PrelGetRangesArray (context -> prel ),
1083
1118
PrelChildrenCount (context -> prel ),
1084
1119
strategy ,
1085
- result );
1120
+ result ); /* output */
1086
1121
1087
1122
result -> paramsel = estimate_paramsel_using_prel (prel , strategy );
1088
1123
@@ -1169,7 +1204,7 @@ search_range_partition_eq(const Datum value,
1169
1204
ranges ,
1170
1205
nranges ,
1171
1206
BTEqualStrategyNumber ,
1172
- & result );
1207
+ & result ); /* output */
1173
1208
1174
1209
if (result .found_gap )
1175
1210
{
@@ -1220,7 +1255,7 @@ handle_const(const Const *c, WalkerContext *context)
1220
1255
1221
1256
/*
1222
1257
* Had to add this check for queries like:
1223
- * select * from test.hash_rel where txt = NULL;
1258
+ * select * from test.hash_rel where txt = NULL;
1224
1259
*/
1225
1260
if (!context -> for_insert || c -> constisnull )
1226
1261
{
@@ -1234,9 +1269,30 @@ handle_const(const Const *c, WalkerContext *context)
1234
1269
{
1235
1270
case PT_HASH :
1236
1271
{
1237
- Datum value = OidFunctionCall1 (prel -> hash_proc , c -> constvalue );
1238
- uint32 idx = hash_to_part_index (DatumGetInt32 (value ),
1239
- PrelChildrenCount (prel ));
1272
+ Datum value , /* value to be hashed */
1273
+ hash ; /* 32-bit hash */
1274
+ uint32 idx ; /* index of partition */
1275
+ bool cast_success ;
1276
+
1277
+ /* Peform type cast if types mismatch */
1278
+ if (prel -> atttype != c -> consttype )
1279
+ {
1280
+ value = perform_type_cast (c -> constvalue ,
1281
+ getBaseType (c -> consttype ),
1282
+ getBaseType (prel -> atttype ),
1283
+ & cast_success );
1284
+
1285
+ if (!cast_success )
1286
+ elog (ERROR , "Cannot select partition: "
1287
+ "unable to perform type cast" );
1288
+ }
1289
+ /* Else use the Const's value */
1290
+ else value = c -> constvalue ;
1291
+
1292
+ /* Calculate 32-bit hash of 'value' and corresponding index */
1293
+ hash = OidFunctionCall1 (prel -> hash_proc , value );
1294
+ idx = hash_to_part_index (DatumGetInt32 (hash ),
1295
+ PrelChildrenCount (prel ));
1240
1296
1241
1297
result -> paramsel = estimate_paramsel_using_prel (prel , strategy );
1242
1298
result -> rangeset = list_make1_irange (make_irange (idx , idx , IR_LOSSY ));
@@ -1245,7 +1301,7 @@ handle_const(const Const *c, WalkerContext *context)
1245
1301
1246
1302
case PT_RANGE :
1247
1303
{
1248
- FmgrInfo cmp_finfo ;
1304
+ FmgrInfo cmp_finfo ;
1249
1305
1250
1306
fill_type_cmp_fmgr_info (& cmp_finfo ,
1251
1307
getBaseType (c -> consttype ),
@@ -1256,7 +1312,7 @@ handle_const(const Const *c, WalkerContext *context)
1256
1312
PrelGetRangesArray (context -> prel ),
1257
1313
PrelChildrenCount (context -> prel ),
1258
1314
strategy ,
1259
- result );
1315
+ result ); /* output */
1260
1316
1261
1317
result -> paramsel = estimate_paramsel_using_prel (prel , strategy );
1262
1318
}
0 commit comments