diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index aaf500ad08..af6d8d1d2a 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -75,9 +75,12 @@
without_oids>
rowtype_oid> oid>
(name1 =
- type1 ,
- name2 = type2, ...)
+ type1
+ FORCE NOT NULL | FORCE NULL ,
+ name2 =
+ type2
+ FORCE NOT NULL | FORCE NULL ,
+ ...)
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 56fa1aaa5d..9edd1a0aff 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -107,7 +107,7 @@ static int num_columns_read = 0;
%type boot_index_params
%type boot_index_param
%type boot_const boot_ident
-%type optbootstrap optsharedrelation optwithoutoids
+%type optbootstrap optsharedrelation optwithoutoids boot_column_nullness
%type oidspec optoideq optrowtypeoid
%token 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); }
;
diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l
index fa4e2ff108..72714f474b 100644
--- a/src/backend/bootstrap/bootscanner.l
+++ b/src/backend/bootstrap/bootscanner.l
@@ -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);
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index bc66eac984..ad49964732 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -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)
{
- int i;
+ attrtypes[attnum]->attnotnull = true;
+ }
+ else if (nullness == BOOTCOL_NULL_FORCE_NULL)
+ {
+ 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;
}
}
diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm
index c773eca809..c7b1c1785e 100644
--- a/src/backend/catalog/Catalog.pm
+++ b/src/backend/catalog/Catalog.pm
@@ -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;
}
}
}
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index e1c7fe5bf0..a5c78eed49 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -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'
diff --git a/src/backend/utils/Gen_fmgrtab.pl b/src/backend/utils/Gen_fmgrtab.pl
index 8b7186419e..f5cc2655f3 100644
--- a/src/backend/utils/Gen_fmgrtab.pl
+++ b/src/backend/utils/Gen_fmgrtab.pl
@@ -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};
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index be4430adff..f9cbc137e7 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -23,6 +23,10 @@
*/
#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);
diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h
index 5d6039db83..cebf51d509 100644
--- a/src/include/catalog/genbki.h
+++ b/src/include/catalog/genbki.h
@@ -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.