@@ -704,6 +704,7 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
704704PG_TRY ();
705705{
706706const PartRelationInfo * prel ;
707+ LockAcquireResult lock_result ;/* could we lock the parent? */
707708Datum values [Natts_pathman_config ];
708709bool isnull [Natts_pathman_config ];
709710
@@ -713,57 +714,91 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
713714Oid base_atttype ;/* base type of prel->atttype */
714715Oid base_value_type ;/* base type of value_type */
715716
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-
725717/* Fetch PartRelationInfo by 'relid' */
726- prel = get_pathman_relation_info (relid );
718+ prel = get_pathman_relation_info_after_lock (relid , true, & lock_result );
727719shout_if_prel_is_invalid (relid ,prel ,PT_RANGE );
728720
729721/* Fetch base types of prel->atttype & value_type */
730722base_atttype = getBaseType (prel -> atttype );
731723base_value_type = getBaseType (value_type );
732724
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 ;
740731
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 ) ;
743734
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 );
748738
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 );
751744
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+ }
754748
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+ }
759752
760- /*while (value < MIN) ... */
753+ /*Else spawn a new one (we hold a lock on the parent) */
761754if (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 ];
765775
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+ }
767802}
768803else
769804elog (ERROR ,"pg_pathman's config does not contain relation \"%s\"" ,
@@ -1082,7 +1117,7 @@ handle_binary_opexpr(WalkerContext *context, WrapperNode *result,
10821117PrelGetRangesArray (context -> prel ),
10831118PrelChildrenCount (context -> prel ),
10841119strategy ,
1085- result );
1120+ result );/* output */
10861121
10871122result -> paramsel = estimate_paramsel_using_prel (prel ,strategy );
10881123
@@ -1169,7 +1204,7 @@ search_range_partition_eq(const Datum value,
11691204ranges ,
11701205nranges ,
11711206BTEqualStrategyNumber ,
1172- & result );
1207+ & result );/* output */
11731208
11741209if (result .found_gap )
11751210{
@@ -1220,7 +1255,7 @@ handle_const(const Const *c, WalkerContext *context)
12201255
12211256/*
12221257 * 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;
12241259 */
12251260if (!context -> for_insert || c -> constisnull )
12261261{
@@ -1234,9 +1269,30 @@ handle_const(const Const *c, WalkerContext *context)
12341269{
12351270case PT_HASH :
12361271{
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 ));
12401296
12411297result -> paramsel = estimate_paramsel_using_prel (prel ,strategy );
12421298result -> rangeset = list_make1_irange (make_irange (idx ,idx ,IR_LOSSY ));
@@ -1245,7 +1301,7 @@ handle_const(const Const *c, WalkerContext *context)
12451301
12461302case PT_RANGE :
12471303{
1248- FmgrInfo cmp_finfo ;
1304+ FmgrInfo cmp_finfo ;
12491305
12501306fill_type_cmp_fmgr_info (& cmp_finfo ,
12511307getBaseType (c -> consttype ),
@@ -1256,7 +1312,7 @@ handle_const(const Const *c, WalkerContext *context)
12561312PrelGetRangesArray (context -> prel ),
12571313PrelChildrenCount (context -> prel ),
12581314strategy ,
1259- result );
1315+ result );/* output */
12601316
12611317result -> paramsel = estimate_paramsel_using_prel (prel ,strategy );
12621318}