]> granicus.if.org Git - postgresql/commitdiff
Allow forcing nullness of columns during bootstrap.
authorAndres Freund <andres@anarazel.de>
Sat, 21 Feb 2015 21:25:49 +0000 (22:25 +0100)
committerAndres Freund <andres@anarazel.de>
Sat, 21 Feb 2015 21:31:54 +0000 (22:31 +0100)
Bootstrap determines whether a column is null based on simple builtin
rules. Those work surprisingly well, but nonetheless a few existing
columns aren't set correctly. Additionally there is at least one patch
sent to hackers where forcing the nullness of a column would be helpful.

The boostrap format has gained FORCE [NOT] NULL for this, which will be
emitted by genbki.pl when BKI_FORCE_(NOT_)?NULL is specified for a
column in a catalog header.

This patch doesn't change the marking of any existing columns.

Discussion: 20150215170014.GE15326@awork2.anarazel.de

doc/src/sgml/bki.sgml
src/backend/bootstrap/bootparse.y
src/backend/bootstrap/bootscanner.l
src/backend/bootstrap/bootstrap.c
src/backend/catalog/Catalog.pm
src/backend/catalog/genbki.pl
src/backend/utils/Gen_fmgrtab.pl
src/include/bootstrap/bootstrap.h
src/include/catalog/genbki.h

index aaf500ad082f8bd41c65560a0af62552d88c6cc4..af6d8d1d2a9c0cb41aa4d1303ba379a0904ded7a 100644 (file)
      <optional><literal>without_oids</></optional>
      <optional><literal>rowtype_oid</> <replaceable>oid</></optional>
      (<replaceable class="parameter">name1</replaceable> =
-     <replaceable class="parameter">type1</replaceable> <optional>,
-     <replaceable class="parameter">name2</replaceable> = <replaceable
-     class="parameter">type2</replaceable>, ...</optional>)
+     <replaceable class="parameter">type1</replaceable>
+     <optional>FORCE NOT NULL | FORCE NULL </optional> <optional>,
+     <replaceable class="parameter">name2</replaceable> =
+     <replaceable class="parameter">type2</replaceable>
+     <optional>FORCE NOT NULL | FORCE NULL </optional>,
+     ...</optional>)
     </term>
 
     <listitem>
index 56fa1aaa5db64736a70cd22b60f64e53adecd1d5..9edd1a0aff908c1bbff3d3912e0d777015f0452e 100644 (file)
@@ -107,7 +107,7 @@ static int num_columns_read = 0;
 %type <list>  boot_index_params
 %type <ielem> boot_index_param
 %type <str>   boot_const boot_ident
-%type <ival>  optbootstrap optsharedrelation optwithoutoids
+%type <ival>  optbootstrap optsharedrelation optwithoutoids boot_column_nullness
 %type <oidval> oidspec optoideq optrowtypeoid
 
 %token <str> CONST_P ID
@@ -115,6 +115,7 @@ static int num_columns_read = 0;
 %token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
 %token COMMA EQUALS LPAREN RPAREN
 %token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID NULLVAL
+%token XFORCE XNOT XNULL
 
 %start TopLevel
 
@@ -427,14 +428,20 @@ boot_column_list:
                ;
 
 boot_column_def:
-                 boot_ident EQUALS boot_ident
+                 boot_ident EQUALS boot_ident boot_column_nullness
                                {
                                   if (++numattr > MAXATTR)
                                                elog(FATAL, "too many columns");
-                                  DefineAttr($1, $3, numattr-1);
+                                  DefineAttr($1, $3, numattr-1, $4);
                                }
                ;
 
+boot_column_nullness:
+                       XFORCE XNOT XNULL       { $$ = BOOTCOL_NULL_FORCE_NOT_NULL; }
+               |       XFORCE XNULL            {  $$ = BOOTCOL_NULL_FORCE_NULL; }
+               | { $$ = BOOTCOL_NULL_AUTO; }
+               ;
+
 oidspec:
                        boot_ident                                                      { $$ = atooid($1); }
                ;
index fa4e2ff108955545034d11ea1f4907a93f319e77..72714f474bf3f7a48c9f71fadacb3541dee9cb04 100644 (file)
@@ -109,6 +109,9 @@ insert                      { return(INSERT_TUPLE); }
 "on"                   { return(ON); }
 "using"                        { return(USING); }
 "toast"                        { return(XTOAST); }
+"FORCE"                        { return(XFORCE); }
+"NOT"                  { return(XNOT); }
+"NULL"                 { return(XNULL); }
 
 {arrayid}              {
                                        yylval.str = MapArrayTypeName(yytext);
index bc66eac9848a30d7dd01e102dc8c97c2cee2bf96..ad49964732f8a901a60f9743d2e431a1e7124323 100644 (file)
@@ -642,7 +642,7 @@ closerel(char *name)
  * ----------------
  */
 void
-DefineAttr(char *name, char *type, int attnum)
+DefineAttr(char *name, char *type, int attnum, int nullness)
 {
        Oid                     typeoid;
 
@@ -697,30 +697,44 @@ DefineAttr(char *name, char *type, int attnum)
        attrtypes[attnum]->atttypmod = -1;
        attrtypes[attnum]->attislocal = true;
 
-       /*
-        * Mark as "not null" if type is fixed-width and prior columns are too.
-        * This corresponds to case where column can be accessed directly via C
-        * struct declaration.
-        *
-        * oidvector and int2vector are also treated as not-nullable, even though
-        * they are no longer fixed-width.
-        */
-#define MARKNOTNULL(att) \
-       ((att)->attlen > 0 || \
-        (att)->atttypid == OIDVECTOROID || \
-        (att)->atttypid == INT2VECTOROID)
-
-       if (MARKNOTNULL(attrtypes[attnum]))
+       if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
+       {
+               attrtypes[attnum]->attnotnull = true;
+       }
+       else if (nullness == BOOTCOL_NULL_FORCE_NULL)
        {
-               int                     i;
+               attrtypes[attnum]->attnotnull = false;
+       }
+       else
+       {
+               Assert(nullness == BOOTCOL_NULL_AUTO);
 
-               for (i = 0; i < attnum; i++)
+               /*
+                * Mark as "not null" if type is fixed-width and prior columns are
+                * too.  This corresponds to case where column can be accessed
+                * directly via C struct declaration.
+                *
+                * oidvector and int2vector are also treated as not-nullable, even
+                * though they are no longer fixed-width.
+                */
+#define MARKNOTNULL(att) \
+               ((att)->attlen > 0 || \
+                (att)->atttypid == OIDVECTOROID || \
+                (att)->atttypid == INT2VECTOROID)
+
+               if (MARKNOTNULL(attrtypes[attnum]))
                {
-                       if (!MARKNOTNULL(attrtypes[i]))
-                               break;
+                       int                     i;
+
+                       /* check earlier attributes */
+                       for (i = 0; i < attnum; i++)
+                       {
+                               if (!attrtypes[i]->attnotnull)
+                                       break;
+                       }
+                       if (i == attnum)
+                               attrtypes[attnum]->attnotnull = true;
                }
-               if (i == attnum)
-                       attrtypes[attnum]->attnotnull = true;
        }
 }
 
index c773eca80925e137f081f82da60ce57d6f0e2e3a..c7b1c1785e456590b15e96f26e0c30151debe198 100644 (file)
@@ -161,7 +161,8 @@ sub Catalogs
                                }
                                else
                                {
-                                       my ($atttype, $attname) = split /\s+/, $_;
+                                       my %row;
+                                       my ($atttype, $attname, $attopt) = split /\s+/, $_;
                                        die "parse error ($input_file)" unless $attname;
                                        if (exists $RENAME_ATTTYPE{$atttype})
                                        {
@@ -172,7 +173,26 @@ sub Catalogs
                                                $attname = $1;
                                                $atttype .= '[]';            # variable-length only
                                        }
-                                       push @{ $catalog{columns} }, { $attname => $atttype };
+
+                                       $row{'type'} = $atttype;
+                                       $row{'name'} = $attname;
+
+                                       if (defined $attopt)
+                                       {
+                                               if ($attopt eq 'PG_FORCE_NULL')
+                                               {
+                                                       $row{'forcenull'} = 1;
+                                               }
+                                               elsif ($attopt eq 'BKI_FORCE_NOT_NULL')
+                                               {
+                                                       $row{'forcenotnull'} = 1;
+                                               }
+                                               else
+                                               {
+                                                       die "unknown column option $attopt on column $attname"
+                                               }
+                                       }
+                                       push @{ $catalog{columns} }, \%row;
                                }
                        }
                }
index e1c7fe5bf015795c00e93771faa9761976af87de..a5c78eed4931f68ea52112683b863faa0760b227 100644 (file)
@@ -118,17 +118,36 @@ foreach my $catname (@{ $catalogs->{names} })
 
        my %bki_attr;
        my @attnames;
+       my $first = 1;
+
+       print BKI " (\n";
        foreach my $column (@{ $catalog->{columns} })
        {
-               my ($attname, $atttype) = %$column;
-               $bki_attr{$attname} = $atttype;
+               my $attname = $column->{name};
+               my $atttype = $column->{type};
+               $bki_attr{$attname} = $column;
                push @attnames, $attname;
+
+               if (!$first)
+               {
+                       print BKI " ,\n";
+               }
+               $first = 0;
+
+               print BKI " $attname = $atttype";
+
+               if (defined $column->{forcenotnull})
+               {
+                       print BKI " FORCE NOT NULL";
+               }
+               elsif (defined $column->{forcenull})
+               {
+                       print BKI " FORCE NULL";
+               }
        }
-       print BKI " (\n";
-       print BKI join " ,\n", map(" $_ = $bki_attr{$_}", @attnames);
        print BKI "\n )\n";
 
-   # open it, unless bootstrap case (create bootstrap does this automatically)
+       # open it, unless bootstrap case (create bootstrap does this automatically)
        if ($catalog->{bootstrap} eq '')
        {
                print BKI "open $catname\n";
@@ -210,7 +229,7 @@ foreach my $catname (@{ $catalogs->{names} })
                                # Store schemapg entries for later.
                                $row =
                                  emit_schemapg_row($row,
-                                       grep { $bki_attr{$_} eq 'bool' } @attnames);
+                                       grep { $bki_attr{$_}{type} eq 'bool' } @attnames);
                                push @{ $schemapg_entries{$table_name} }, '{ '
                                  . join(
                                        ', ',             grep { defined $_ }
@@ -223,13 +242,13 @@ foreach my $catname (@{ $catalogs->{names} })
                        {
                                $attnum = 0;
                                my @SYS_ATTRS = (
-                                       { ctid     => 'tid' },
-                                       { oid      => 'oid' },
-                                       { xmin     => 'xid' },
-                                       { cmin     => 'cid' },
-                                       { xmax     => 'xid' },
-                                       { cmax     => 'cid' },
-                                       { tableoid => 'oid' });
+                                       { name => 'ctid', type => 'tid' },
+                                       { name => 'oid', type => 'oid' },
+                                       { name => 'xmin', type => 'xid' },
+                                       { name => 'cmin', type=> 'cid' },
+                                       { name => 'xmax', type=> 'xid' },
+                                       { name => 'cmax', type => 'cid' },
+                                       { name => 'tableoid', type => 'oid' });
                                foreach my $attr (@SYS_ATTRS)
                                {
                                        $attnum--;
@@ -326,7 +345,8 @@ exit 0;
 sub emit_pgattr_row
 {
        my ($table_name, $attr, $priornotnull) = @_;
-       my ($attname, $atttype) = %$attr;
+       my $attname = $attr->{name};
+       my $atttype = $attr->{type};
        my %row;
 
        $row{attrelid} = $catalogs->{$table_name}->{relation_oid};
@@ -354,11 +374,20 @@ sub emit_pgattr_row
                        $row{attndims} = $type->{typcategory} eq 'A' ? '1' : '0';
                        $row{attcollation} = $type->{typcollation};
 
-                       # attnotnull must be set true if the type is fixed-width and
-                       # prior columns are too --- compare DefineAttr in bootstrap.c.
-                       # oidvector and int2vector are also treated as not-nullable.
-                       if ($priornotnull)
+                       if (defined $attr->{forcenotnull})
+                       {
+                               $row{attnotnull} = 't';
+                       }
+                       elsif (defined $attr->{forcenull})
+                       {
+                               $row{attnotnull} = 'f';
+                       }
+                       elsif ($priornotnull)
                        {
+                               # attnotnull will automatically be set if the type is
+                               # fixed-width and prior columns are all NOT NULL ---
+                               # compare DefineAttr in bootstrap.c. oidvector and
+                               # int2vector are also treated as not-nullable.
                                $row{attnotnull} =
                                    $type->{typname} eq 'oidvector'   ? 't'
                                  : $type->{typname} eq 'int2vector'  ? 't'
index 8b7186419e3d6adff45c47f0e9188b64e70cd9a1..f5cc2655f3559dd0a9ca95172ae3d87817c7c5c3 100644 (file)
@@ -52,7 +52,7 @@ my @fmgr = ();
 my @attnames;
 foreach my $column (@{ $catalogs->{pg_proc}->{columns} })
 {
-       push @attnames, keys %$column;
+       push @attnames, $column->{name};
 }
 
 my $data = $catalogs->{pg_proc}->{data};
index be4430adffdb15037abaf350d7efb0dd8a4c0f12..f9cbc137e72215e50a9e3e1e66e23a96f19ae6ab 100644 (file)
  */
 #define MAXATTR 40
 
+#define BOOTCOL_NULL_AUTO                      1
+#define BOOTCOL_NULL_FORCE_NULL                2
+#define BOOTCOL_NULL_FORCE_NOT_NULL    3
+
 extern Relation boot_reldesc;
 extern Form_pg_attribute attrtypes[MAXATTR];
 extern int     numattr;
@@ -35,7 +39,7 @@ extern void err_out(void);
 extern void closerel(char *name);
 extern void boot_openrel(char *name);
 
-extern void DefineAttr(char *name, char *type, int attnum);
+extern void DefineAttr(char *name, char *type, int attnum, int nullness);
 extern void InsertOneTuple(Oid objectid);
 extern void InsertOneValue(char *value, int i);
 extern void InsertOneNull(int i);
index 5d6039db83570ab1cbe592ac8c8adcdddca53efd..cebf51d509d8925c48dd90e1f35633d1fe9fc67c 100644 (file)
@@ -28,6 +28,8 @@
 #define BKI_WITHOUT_OIDS
 #define BKI_ROWTYPE_OID(oid)
 #define BKI_SCHEMA_MACRO
+#define BKI_FORCE_NULL
+#define BKI_FORCE_NOT_NULL
 
 /*
  * This is never defined; it's here only for documentation.