@@ -632,8 +632,7 @@ cook_partitioning_expression(const Oid relid,
632632 const char * expr_cstr ,
633633 Oid * expr_type_out ) /* ret value #1 */
634634{
635- Node * parse_tree ,
636- * raw_expr ;
635+ Node * parse_tree ;
637636 List * query_tree_list ;
638637
639638 char * query_string ,
@@ -658,37 +657,8 @@ cook_partitioning_expression(const Oid relid,
658657 old_mcxt = MemoryContextSwitchTo (parse_mcxt );
659658
660659 /* First we have to build a raw AST */
661- raw_expr = parse_partitioning_expression (relid , expr_cstr ,
662- & query_string , & parse_tree );
663-
664- /* Check if raw_expr is NULLable */
665- if (IsA (raw_expr , ColumnRef ))
666- {
667- ColumnRef * column = (ColumnRef * ) raw_expr ;
668-
669- if (list_length (column -> fields ) == 1 )
670- {
671- HeapTuple htup ;
672- bool attnotnull ;
673- char * attname = strVal (linitial (column -> fields ));
674-
675- /* check if attribute is nullable */
676- htup = SearchSysCacheAttName (relid , attname );
677- if (HeapTupleIsValid (htup ))
678- {
679- Form_pg_attribute att_tup = (Form_pg_attribute ) GETSTRUCT (htup );
680- attnotnull = att_tup -> attnotnull ;
681- ReleaseSysCache (htup );
682- }
683- else elog (ERROR , "cannot find type name for attribute \"%s\""
684- " of relation \"%s\"" ,
685- attname , get_rel_name_or_relid (relid ));
686-
687- if (!attnotnull )
688- elog (ERROR , "partitioning key \"%s\" must be marked NOT NULL" ,
689- attname );
690- }
691- }
660+ (void ) parse_partitioning_expression (relid , expr_cstr ,
661+ & query_string , & parse_tree );
692662
693663 /* We don't need pg_pathman's magic here */
694664 pathman_hooks_enabled = false;
@@ -697,7 +667,9 @@ cook_partitioning_expression(const Oid relid,
697667 {
698668 Query * query ;
699669 Node * expr ;
670+ int expr_attr ;
700671 Relids expr_varnos ;
672+ Bitmapset * expr_varattnos = NULL ;
701673
702674 /* This will fail with ERROR in case of wrong expression */
703675 query_tree_list = pg_analyze_and_rewrite (parse_tree , query_string , NULL , 0 );
@@ -729,12 +701,41 @@ cook_partitioning_expression(const Oid relid,
729701 /* Sanity check #5 */
730702 expr_varnos = pull_varnos (expr );
731703 if (bms_num_members (expr_varnos ) != 1 ||
732- ((RangeTblEntry * ) linitial (query -> rtable ))-> relid != relid )
704+ relid != ((RangeTblEntry * ) linitial (query -> rtable ))-> relid )
733705 {
734706 elog (ERROR , "partitioning expression should reference table \"%s\"" ,
735707 get_rel_name (relid ));
736708 }
709+
710+ /* Sanity check #6 */
711+ pull_varattnos (expr , bms_singleton_member (expr_varnos ), & expr_varattnos );
712+ expr_attr = -1 ;
713+ while ((expr_attr = bms_next_member (expr_varattnos , expr_attr )) >= 0 )
714+ {
715+ AttrNumber attnum = expr_attr + FirstLowInvalidHeapAttributeNumber ;
716+ HeapTuple htup ;
717+
718+ htup = SearchSysCache2 (ATTNUM ,
719+ ObjectIdGetDatum (relid ),
720+ Int16GetDatum (attnum ));
721+ if (HeapTupleIsValid (htup ))
722+ {
723+ bool nullable ;
724+
725+ /* Fetch 'nullable' and free syscache tuple */
726+ nullable = !((Form_pg_attribute ) GETSTRUCT (htup ))-> attnotnull ;
727+ ReleaseSysCache (htup );
728+
729+ if (nullable )
730+ ereport (ERROR , (errcode (ERRCODE_NOT_NULL_VIOLATION ),
731+ errmsg ("column \"%s\" should be marked NOT NULL" ,
732+ get_attname (relid , attnum ))));
733+ }
734+ }
735+
736+ /* Free sets */
737737 bms_free (expr_varnos );
738+ bms_free (expr_varattnos );
738739
739740 Assert (expr );
740741 expr_serialized = nodeToString (expr );
0 commit comments