2626#include "utils/array.h"
2727#include "utils/builtins.h"
2828#include "utils/lsyscache.h"
29+ #include "utils/numeric.h"
2930#include "utils/ruleutils.h"
31+ #include "utils/syscache.h"
3032
3133
3234static char * deparse_constraint (Oid relid ,Node * expr );
@@ -48,7 +50,9 @@ static void modify_range_constraint(Oid child_relid,
4850const Bound * upper );
4951static char * get_qualified_rel_name (Oid relid );
5052static void drop_table_by_oid (Oid relid );
51-
53+ static bool interval_is_trivial (Oid atttype ,
54+ Datum interval ,
55+ Oid interval_type );
5256
5357/* Function declarations */
5458
@@ -620,7 +624,9 @@ validate_interval_value(PG_FUNCTION_ARGS)
620624Oid partrel = PG_GETARG_OID (0 );
621625text * attname = PG_GETARG_TEXT_P (1 );
622626PartType parttype = DatumGetPartType (PG_GETARG_DATUM (2 ));
623- Datum range_interval = PG_GETARG_DATUM (3 );
627+ Datum interval_text = PG_GETARG_DATUM (3 );
628+ Datum interval_value ;
629+ Oid interval_type ;
624630
625631char * attname_cstr ;
626632Oid atttype ;/* type of partitioned attribute */
@@ -643,12 +649,106 @@ validate_interval_value(PG_FUNCTION_ARGS)
643649atttype = get_attribute_type (partrel ,attname_cstr , false);
644650
645651/* Try converting textual representation */
646- extract_binary_interval_from_text (range_interval ,atttype ,NULL );
652+ interval_value = extract_binary_interval_from_text (interval_text ,
653+ atttype ,
654+ & interval_type );
655+
656+ /* Check that interval isn't trivial */
657+ if (interval_is_trivial (atttype ,interval_value ,interval_type ))
658+ elog (ERROR ,"Interval must not be trivial" );
647659
648660PG_RETURN_BOOL (true);
649661}
650662
651663
664+ /*
665+ * Check that interval is somehow significant to avoid of infinite loops while
666+ * adding new partitions
667+ *
668+ * The main idea behind this function is to add specified interval to some
669+ * default value (zero for numeric types and '1970-01-01' for datetime types)
670+ * and look if it is changed. If it is then return true.
671+ */
672+ static bool
673+ interval_is_trivial (Oid atttype ,Datum interval ,Oid interval_type )
674+ {
675+ Datum default_value ;
676+ Datum op_result ;
677+ Oid op_result_type ;
678+ Operator op ;
679+ Oid op_func ;
680+ FmgrInfo cmp_func ;
681+
682+ /* Generate default value */
683+ switch (atttype )
684+ {
685+ case INT2OID :
686+ case INT4OID :
687+ case INT8OID :
688+ default_value = Int16GetDatum (0 );
689+ break ;
690+ case FLOAT4OID :
691+ default_value = Float4GetDatum (0 );
692+ break ;
693+ case FLOAT8OID :
694+ default_value = Float8GetDatum (0 );
695+ break ;
696+ case NUMERICOID :
697+ default_value = NumericGetDatum (0 );
698+ break ;
699+ case TIMESTAMPOID :
700+ case TIMESTAMPTZOID :
701+ default_value = TimestampGetDatum (GetCurrentTimestamp ());
702+ break ;
703+ case DATEOID :
704+ {
705+ Datum ts = TimestampGetDatum (GetCurrentTimestamp ());
706+
707+ default_value = perform_type_cast (ts ,TIMESTAMPTZOID ,DATEOID ,NULL );
708+ }
709+ break ;
710+ default :
711+ return false;
712+ }
713+
714+ /* Find suitable addition operator for default value and interval */
715+ op = get_binary_operator ("+" ,atttype ,interval_type );
716+ if (!op )
717+ elog (ERROR ,"missing \"+\" operator for types %s and %s" ,
718+ format_type_be (atttype ),
719+ format_type_be (interval_type ));
720+
721+ op_func = oprfuncid (op );
722+ op_result_type = get_operator_ret_type (op );
723+ ReleaseSysCache (op );
724+
725+ /* Invoke addition operator and get a result*/
726+ op_result = OidFunctionCall2 (op_func ,default_value ,interval );
727+
728+ /*
729+ * If operator result type isn't the same as original value then
730+ * convert it
731+ */
732+ if (op_result_type != atttype )
733+ {
734+ op_result = perform_type_cast (op_result ,op_result_type ,atttype ,NULL );
735+ op_result_type = atttype ;
736+ }
737+
738+ /*
739+ * Compare it to the default_value. If they are the same then obviously
740+ * interval is trivial
741+ */
742+ fill_type_cmp_fmgr_info (& cmp_func ,
743+ getBaseType (atttype ),
744+ getBaseType (op_result_type ));
745+ if (DatumGetInt32 (FunctionCall2 (& cmp_func ,default_value ,op_result ))== 0 )
746+ return true;
747+
748+ return false;
749+ }
750+
751+
652752/*
653753 * ------------------
654754 * Helper functions