mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
Allow forcing nullness of columns during bootstrap.
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
This commit is contained in:
parent
0627eff360
commit
eb68379c38
@ -75,9 +75,12 @@
|
||||
<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>
|
||||
|
@ -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); }
|
||||
;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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'
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user