Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
40a19977
Commit
40a19977
authored
Mar 11, 2007
by
mkanat%bugzilla.org
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 373442: Add referential integrity against the profiles table in some more simple places
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> (module owner) a=mkanat
parent
2884cd86
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
194 additions
and
171 deletions
+194
-171
DB.pm
Bugzilla/DB.pm
+86
-6
Schema.pm
Bugzilla/DB/Schema.pm
+102
-106
Mysql.pm
Bugzilla/DB/Schema/Mysql.pm
+0
-11
DB.pm
Bugzilla/Install/DB.pm
+3
-48
messages.html.tmpl
template/en/default/global/messages.html.tmpl
+3
-0
No files found.
Bugzilla/DB.pm
View file @
40a19977
...
...
@@ -43,6 +43,7 @@ use Bugzilla::Error;
use
Bugzilla::DB::
Schema
;
use
List::
Util
qw(max)
;
use
Storable
qw(dclone)
;
#####################################################################
# Constants
...
...
@@ -428,6 +429,23 @@ sub bz_populate_enum_tables {
}
}
sub
bz_setup_foreign_keys
{
my
(
$self
)
=
@_
;
# We use _bz_schema because bz_add_table has removed all REFERENCES
# items from _bz_real_schema.
my
@tables
=
$self
->
_bz_schema
->
get_table_list
();
foreach
my
$table
(
@tables
)
{
my
@columns
=
$self
->
_bz_schema
->
get_table_columns
(
$table
);
foreach
my
$column
(
@columns
)
{
my
$def
=
$self
->
_bz_schema
->
get_column_abstract
(
$table
,
$column
);
if
(
$def
->
{
REFERENCES
})
{
$self
->
bz_add_fk
(
$table
,
$column
,
$def
->
{
REFERENCES
});
}
}
}
}
#####################################################################
# Schema Modification Methods
#####################################################################
...
...
@@ -463,6 +481,24 @@ sub bz_add_column {
}
}
sub
bz_add_fk
{
my
(
$self
,
$table
,
$column
,
$def
)
=
@_
;
my
$col_def
=
$self
->
bz_column_info
(
$table
,
$column
);
if
(
!
$col_def
->
{
REFERENCES
})
{
$self
->
_check_references
(
$table
,
$column
,
$def
->
{
TABLE
},
$def
->
{
COLUMN
});
print
get_text
(
'install_fk_add'
,
{
table
=>
$table
,
column
=>
$column
,
fk
=>
$def
})
.
"\n"
if
Bugzilla
->
usage_mode
==
USAGE_MODE_CMDLINE
;
my
@sql
=
$self
->
_bz_real_schema
->
get_add_fk_sql
(
$table
,
$column
,
$def
);
$self
->
do
(
$_
)
foreach
@sql
;
$col_def
->
{
REFERENCES
}
=
$def
;
$self
->
_bz_real_schema
->
set_column
(
$table
,
$column
,
$col_def
);
$self
->
_bz_store_real_schema
;
}
}
sub
bz_alter_column
{
my
(
$self
,
$table
,
$name
,
$new_def
,
$set_nulls_to
)
=
@_
;
...
...
@@ -515,11 +551,10 @@ sub bz_alter_column_raw {
my
@statements
=
$self
->
_bz_real_schema
->
get_alter_column_ddl
(
$table
,
$name
,
$new_def
,
defined
$set_nulls_to
?
$self
->
quote
(
$set_nulls_to
)
:
undef
);
my
$new_ddl
=
$self
->
_bz_schema
->
get_
display_ddl
(
$table
,
$name
,
$new_def
);
my
$new_ddl
=
$self
->
_bz_schema
->
get_
type_ddl
(
$new_def
);
print
"Updating column $name in table $table ...\n"
;
if
(
defined
$current_def
)
{
my
$old_ddl
=
$self
->
_bz_schema
->
get_display_ddl
(
$table
,
$name
,
$current_def
);
my
$old_ddl
=
$self
->
_bz_schema
->
get_type_ddl
(
$current_def
);
print
"Old: $old_ddl\n"
;
}
print
"New: $new_ddl\n"
;
...
...
@@ -569,8 +604,17 @@ sub bz_add_table {
if
(
!
$table_exists
)
{
$self
->
_bz_add_table_raw
(
$name
);
$self
->
_bz_real_schema
->
add_table
(
$name
,
$self
->
_bz_schema
->
get_table_abstract
(
$name
));
my
$table_def
=
dclone
(
$self
->
_bz_schema
->
get_table_abstract
(
$name
));
my
%
fields
=
@
{
$table_def
->
{
FIELDS
}};
foreach
my
$col
(
keys
%
fields
)
{
# Foreign Key references have to be added by Install::DB after
# initial table creation, because column names have changed
# over history and it's impossible to keep track of that info
# in ABSTRACT_SCHEMA.
delete
$fields
{
$col
}
->
{
REFERENCES
};
}
$self
->
_bz_real_schema
->
add_table
(
$name
,
$table_def
);
$self
->
_bz_store_real_schema
;
}
}
...
...
@@ -751,7 +795,10 @@ sub _bz_get_initial_schema {
sub
bz_column_info
{
my
(
$self
,
$table
,
$column
)
=
@_
;
return
$self
->
_bz_real_schema
->
get_column_abstract
(
$table
,
$column
);
my
$def
=
$self
->
_bz_real_schema
->
get_column_abstract
(
$table
,
$column
);
# We dclone it so callers can't modify the Schema.
$def
=
dclone
(
$def
)
if
defined
$def
;
return
$def
;
}
sub
bz_index_info
{
...
...
@@ -1050,6 +1097,39 @@ sub _bz_populate_enum_table {
}
}
# This is used before adding a foreign key to a column, to make sure
# that the database won't fail adding the key.
sub
_check_references
{
my
(
$self
,
$table
,
$column
,
$foreign_table
,
$foreign_column
)
=
@_
;
my
$bad_values
=
$self
->
selectcol_arrayref
(
"SELECT DISTINCT $table.$column
FROM $table LEFT JOIN $foreign_table
ON $table.$column = $foreign_table.$foreign_column
WHERE $foreign_table.$foreign_column IS NULL
AND $table.$column IS NOT NULL"
);
if
(
@$bad_values
)
{
my
$values
=
join
(
', '
,
@$bad_values
);
print
<<EOT;
ERROR: There are invalid values for the $column column in the $table
table. (These values do not exist in the $foreign_table table, in the
$foreign_column column.)
Before continuing with checksetup, you will need to fix these values,
either by deleting these rows from the database, or changing the values
of $column in $table to point to valid values in $foreign_table.$foreign_column.
The bad values from the $table.$column column are:
$values
EOT
# I just picked a number above 2, to be considered "abnormal exit."
exit
3
;
}
}
1
;
__END__
...
...
Bugzilla/DB/Schema.pm
View file @
40a19977
...
...
@@ -40,6 +40,7 @@ use Bugzilla::Hook;
use
Bugzilla::
Util
;
use
Bugzilla::
Constants
;
use
Carp
qw(confess)
;
use
Hash::
Util
qw(lock_value unlock_hash lock_keys unlock_keys)
;
use
Safe
;
# Historical, needed for SCHEMA_VERSION = '1.00'
...
...
@@ -98,20 +99,6 @@ more about how this integrates into the rest of Bugzilla.
=over
=item C<TABLES_FIRST>
Because of L</"Referential Integrity">, certain tables must be created
before other tables. L</ABSTRACT_SCHEMA> can't specify this, because
it's a hash. So we specify it here. When calling C<get_table_list()>,
these tables will be returned before the other tables.
=cut
use
constant
TABLES_FIRST
=>
qw(
fielddefs
profiles
)
;
=item C<SCHEMA_VERSION>
The 'version' of the internal schema structure. This version number
...
...
@@ -194,7 +181,7 @@ The column pointed at in that table.
=item C<DELETE>
What to do if the row in the parent table is deleted. Choices are
C<RESTRICT>
or C<CASCADE
>.
C<RESTRICT>
, C<CASCADE>, or C<SET NULL
>.
C<RESTRICT> means the deletion of the row in the parent table will
be forbidden by the database if there is a row in I<this> table that
...
...
@@ -203,17 +190,19 @@ C<DELETE>.
C<CASCADE> means that this row will be deleted along with that row.
C<SET NULL> means that the column will be set to C<NULL> when the parent
row is deleted. Note that this is only valid if the column can actually
be set to C<NULL>. (That is, the column isn't C<NOT NULL>.)
=item C<UPDATE>
What to do if the value in the parent table is updated. It has the
same choices as L</DELETE>, except it defaults to C<CASCADE>, which means
"also update this column in this table."
What to do if the value in the parent table is updated. You can set this
to C<CASCADE> or C<RESTRICT>, which mean the same thing as they do for
L</DELETE>. This variable defaults to C<CASCADE>, which means "also
update this column in this table."
=back
Note that not all our supported databases actually enforce C<RESTRICT>
and C<CASCADE>, so don't depend on them.
=cut
use
constant
SCHEMA_VERSION
=>
'2.00'
;
...
...
@@ -293,7 +282,9 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
attach_id
=>
{
TYPE
=>
'INT3'
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
}},
bug_when
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
},
fieldid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
added
=>
{
TYPE
=>
'TINYTEXT'
},
...
...
@@ -310,7 +301,10 @@ use constant ABSTRACT_SCHEMA => {
cc
=>
{
FIELDS
=>
[
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
],
INDEXES
=>
[
cc_bug_id_idx
=>
{
FIELDS
=>
[
qw(bug_id who)
],
...
...
@@ -359,7 +353,10 @@ use constant ABSTRACT_SCHEMA => {
votes
=>
{
FIELDS
=>
[
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
vote_count
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
],
...
...
@@ -379,7 +376,9 @@ use constant ABSTRACT_SCHEMA => {
mimetype
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
ispatch
=>
{
TYPE
=>
'BOOLEAN'
},
filename
=>
{
TYPE
=>
'varchar(100)'
,
NOTNULL
=>
1
},
submitter_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
submitter_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
}},
isobsolete
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
,
DEFAULT
=>
'FALSE'
},
isprivate
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
,
...
...
@@ -725,7 +724,10 @@ use constant ABSTRACT_SCHEMA => {
email_setting
=>
{
FIELDS
=>
[
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
relationship
=>
{
TYPE
=>
'INT1'
,
NOTNULL
=>
1
},
event
=>
{
TYPE
=>
'INT1'
,
NOTNULL
=>
1
},
],
...
...
@@ -738,8 +740,14 @@ use constant ABSTRACT_SCHEMA => {
watch
=>
{
FIELDS
=>
[
watcher
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
watched
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
watcher
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
watched
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
],
INDEXES
=>
[
watch_watcher_idx
=>
{
FIELDS
=>
[
qw(watcher watched)
],
...
...
@@ -752,7 +760,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
},
userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
},
query
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
query_type
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
},
...
...
@@ -765,8 +776,14 @@ use constant ABSTRACT_SCHEMA => {
namedqueries_link_in_footer
=>
{
FIELDS
=>
[
namedquery_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
namedquery_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'namedqueries'
,
COLUMN
=>
'id'
,
DELETE
=>
'CASCADE'
}},
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
],
INDEXES
=>
[
namedqueries_link_in_footer_id_idx
=>
{
FIELDS
=>
[
qw(namedquery_id user_id)
],
...
...
@@ -778,7 +795,10 @@ use constant ABSTRACT_SCHEMA => {
component_cc
=>
{
FIELDS
=>
[
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
component_id
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
],
INDEXES
=>
[
...
...
@@ -794,7 +814,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
cookie
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
},
userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
ipaddr
=>
{
TYPE
=>
'varchar(40)'
,
NOTNULL
=>
1
},
lastused
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
},
],
...
...
@@ -808,7 +831,9 @@ use constant ABSTRACT_SCHEMA => {
# for these changes.
tokens
=>
{
FIELDS
=>
[
userid
=>
{
TYPE
=>
'INT3'
},
userid
=>
{
TYPE
=>
'INT3'
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
issuedate
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
}
,
token
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
},
...
...
@@ -996,8 +1021,13 @@ use constant ABSTRACT_SCHEMA => {
PRIMARYKEY
=>
1
},
name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
},
product_id
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
initialowner
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
initialqacontact
=>
{
TYPE
=>
'INT3'
},
initialowner
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
}},
initialqacontact
=>
{
TYPE
=>
'INT3'
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'SET NULL'
}},
description
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
],
INDEXES
=>
[
...
...
@@ -1063,7 +1093,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
1
},
eventid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
eventid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'whine_events'
,
COLUMN
=>
'id'
,
DELETE
=>
'CASCADE'
}},
query_name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
,
DEFAULT
=>
"''"
},
sortkey
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
,
...
...
@@ -1082,7 +1115,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
1
},
eventid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
eventid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'whine_events'
,
COLUMN
=>
'id'
,
DELETE
=>
'CASCADE'
}},
run_day
=>
{
TYPE
=>
'varchar(32)'
},
run_time
=>
{
TYPE
=>
'varchar(32)'
},
run_next
=>
{
TYPE
=>
'DATETIME'
},
...
...
@@ -1099,7 +1135,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
1
},
owner_userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
owner_userid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
subject
=>
{
TYPE
=>
'varchar(128)'
},
body
=>
{
TYPE
=>
'MEDIUMTEXT'
},
],
...
...
@@ -1159,7 +1198,10 @@ use constant ABSTRACT_SCHEMA => {
profile_setting
=>
{
FIELDS
=>
[
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
user_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
setting_name
=>
{
TYPE
=>
'varchar(32)'
,
NOTNULL
=>
1
},
setting_value
=>
{
TYPE
=>
'varchar(32)'
,
NOTNULL
=>
1
},
],
...
...
@@ -1376,7 +1418,8 @@ C<ALTER TABLE> SQL statement
my
$self
=
shift
;
my
$finfo
=
(
@_
==
1
&&
ref
(
$_
[
0
])
eq
'HASH'
)
?
$_
[
0
]
:
{
@_
};
my
$type
=
$finfo
->
{
TYPE
};
die
"A valid TYPE was not specified for this column."
unless
(
$type
);
confess
"A valid TYPE was not specified for this column (got "
.
Dumper
(
$finfo
)
.
")"
unless
(
$type
);
my
$default
=
$finfo
->
{
DEFAULT
};
# Replace any abstract default value (such as 'TRUE' or 'FALSE')
...
...
@@ -1397,17 +1440,6 @@ C<ALTER TABLE> SQL statement
}
#eosub--get_type_ddl
# Used if you want to display the DDL to the user, as opposed to actually
# use it in the database.
sub
get_display_ddl
{
my
(
$self
,
$table
,
$column
,
$def
)
=
@_
;
my
$ddl
=
$self
->
get_type_ddl
(
$def
);
if
(
$def
->
{
REFERENCES
})
{
$ddl
.=
$self
->
get_fk_ddl
(
$table
,
$column
,
$def
->
{
REFERENCES
});
}
return
$ddl
;
}
sub
get_fk_ddl
{
=item C<_get_fk_ddl>
...
...
@@ -1441,8 +1473,8 @@ is undefined.
my
$update
=
$references
->
{
UPDATE
}
||
'CASCADE'
;
my
$delete
=
$references
->
{
DELETE
}
||
'RESTRICT'
;
my
$to_table
=
$references
->
{
TABLE
}
||
die
"No table in reference"
;
my
$to_column
=
$references
->
{
COLUMN
}
||
die
"No column in reference"
;
my
$to_table
=
$references
->
{
TABLE
}
||
confess
"No table in reference"
;
my
$to_column
=
$references
->
{
COLUMN
}
||
confess
"No column in reference"
;
my
$fk_name
=
$self
->
_get_fk_name
(
$table
,
$column
,
$references
);
return
"\n CONSTRAINT $fk_name FOREIGN KEY ($column)\n"
...
...
@@ -1460,10 +1492,10 @@ sub _get_fk_name {
return
"fk_${table}_${column}_${to_table}_${to_column}"
;
}
sub
_
get_add_fk_sql
{
my
(
$self
,
$table
,
$column
,
$
new_
def
)
=
@_
;
sub
get_add_fk_sql
{
my
(
$self
,
$table
,
$column
,
$def
)
=
@_
;
my
$fk_string
=
$self
->
get_fk_ddl
(
$table
,
$column
,
$
new_def
->
{
REFERENCES
}
);
my
$fk_string
=
$self
->
get_fk_ddl
(
$table
,
$column
,
$
def
);
return
(
"ALTER TABLE $table ADD $fk_string"
);
}
...
...
@@ -1519,22 +1551,12 @@ sub get_table_list {
Parameters: none
Returns: An array of table names. The tables specified
in L</TABLES_FIRST> will come first, in order. The
rest of the tables will be in random order.
Returns: An array of table names, in alphabetical order.
=cut
my
$self
=
shift
;
my
%
schema
=
%
{
$self
->
{
schema
}};
my
@tables
;
foreach
my
$table
(
TABLES_FIRST
)
{
push
(
@tables
,
$table
);
delete
$schema
{
$table
};
}
push
(
@tables
,
keys
%
schema
);
return
@tables
;
return
sort
keys
%
{
$self
->
{
schema
}};
}
sub
get_table_columns
{
...
...
@@ -1603,14 +1625,6 @@ sub get_table_ddl {
push
(
@ddl
,
$index_sql
)
if
$index_sql
;
}
my
%
fields
=
@
{
$self
->
{
schema
}{
$table
}{
FIELDS
}};
foreach
my
$col
(
keys
%
fields
)
{
my
$def
=
$fields
{
$col
};
if
(
$def
->
{
REFERENCES
})
{
push
(
@ddl
,
$self
->
_get_add_fk_sql
(
$table
,
$col
,
$def
));
}
}
push
(
@ddl
,
@
{
$self
->
{
schema
}{
$table
}{
DB_EXTRAS
}
})
if
(
ref
(
$self
->
{
schema
}{
$table
}{
DB_EXTRAS
}));
...
...
@@ -1704,6 +1718,11 @@ sub get_add_column_ddl {
(
push
(
@statements
,
"UPDATE $table SET $column = $init_value"
))
if
defined
$init_value
;
if
(
defined
$definition
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
get_add_fk_sql
(
$table
,
$column
,
$definition
->
{
REFERENCES
}));
}
return
(
@statements
);
}
...
...
@@ -1824,15 +1843,6 @@ sub get_alter_column_ddl {
push
(
@statements
,
"ALTER TABLE $table DROP PRIMARY KEY"
);
}
# If we went from not having an FK to having an FK
# XXX For right now, you can't change an FK's actual definition.
if
(
!
$old_def
->
{
REFERENCES
}
&&
$new_def
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
_get_add_fk_sql
(
$table
,
$column
,
$new_def
));
}
elsif
(
$old_def
->
{
REFERENCES
}
&&
!
$new_def
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
_get_drop_fk_sql
(
$table
,
$column
,
$old_def
));
}
return
@statements
;
}
...
...
@@ -2220,31 +2230,17 @@ sub columns_equal {
$col_one
->
{
TYPE
}
=
uc
(
$col_one
->
{
TYPE
});
$col_two
->
{
TYPE
}
=
uc
(
$col_two
->
{
TYPE
});
# It doesn't work to compare the two REFERENCES items, because
# they look like 'HASH(0xaf3c434)' to diff_arrays--they'll never
# be equal.
my
%
col_one_def
=
%
$col_one
;
delete
$col_one_def
{
REFERENCES
};
my
%
col_two_def
=
%
$col_two
;
delete
$col_two_def
{
REFERENCES
};
# We don't care about foreign keys when comparing column definitions.
delete
$col_one
->
{
REFERENCES
};
delete
$col_two
->
{
REFERENCES
};
my
@col_one_array
=
%
col_one_def
;
my
@col_two_array
=
%
col_two_def
;
my
@col_one_array
=
%
$col_one
;
my
@col_two_array
=
%
$col_two
;
my
(
$removed
,
$added
)
=
diff_arrays
(
\
@col_one_array
,
\
@col_two_array
);
# If there are no differences between the arrays, then they are equal.
my
$defs_identical
=
!
scalar
(
@$removed
)
&&
!
scalar
(
@$added
);
# If the basic definitions are identical, we still want to check
# if the two foreign key definitions are different.
my
@fk_array_one
=
%
{
$col_one
->
{
REFERENCES
}
||
{}};
my
@fk_array_two
=
%
{
$col_two
->
{
REFERENCES
}
||
{}};
my
(
$fk_removed
,
$fk_added
)
=
diff_arrays
(
\
@fk_array_one
,
\
@fk_array_two
);
my
$fk_identical
=
!
scalar
(
@$fk_removed
)
&&
!
scalar
(
@$fk_added
);
return
$defs_identical
&&
$fk_identical
?
1
:
0
;
return
!
scalar
(
@$removed
)
&&
!
scalar
(
@$added
)
?
1
:
0
;
}
...
...
Bugzilla/DB/Schema/Mysql.pm
View file @
40a19977
...
...
@@ -176,17 +176,10 @@ sub get_alter_column_ddl {
# keys are not allowed.
delete
$new_def_copy
{
PRIMARYKEY
};
}
# CHANGE COLUMN doesn't support REFERENCES
delete
$new_def_copy
{
REFERENCES
};
my
$new_ddl
=
$self
->
get_type_ddl
(
\%
new_def_copy
);
my
@statements
;
# Drop the FK if the new definition doesn't have one.
if
(
$old_def
->
{
REFERENCES
}
&&
!
$new_def
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
_get_drop_fk_sql
(
$table
,
$column
,
$old_def
));
}
push
(
@statements
,
"UPDATE $table SET $column = $set_nulls_to
WHERE $column IS NULL"
)
if
defined
$set_nulls_to
;
push
(
@statements
,
"ALTER TABLE $table CHANGE COLUMN
...
...
@@ -196,10 +189,6 @@ sub get_alter_column_ddl {
push
(
@statements
,
"ALTER TABLE $table DROP PRIMARY KEY"
);
}
# Add the FK if the new definition has one and the old definition doesn't.
if
(
$new_def
->
{
REFERENCES
}
&&
!
$old_def
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
_get_add_fk_sql
(
$table
,
$column
,
$new_def
));
}
return
@statements
;
}
...
...
Bugzilla/Install/DB.pm
View file @
40a19977
...
...
@@ -49,39 +49,6 @@ sub indicate_progress {
}
}
# This is used before adding a foreign key to a column, to make sure
# that the database won't fail adding the key.
sub
check_references
{
my
(
$table
,
$column
,
$foreign_table
,
$foreign_column
)
=
@_
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$bad_values
=
$dbh
->
selectcol_arrayref
(
"SELECT DISTINCT $table.$column
FROM $table LEFT JOIN $foreign_table
ON $table.$column = $foreign_table.$foreign_column
WHERE $foreign_table.$foreign_column IS NULL"
);
if
(
@$bad_values
)
{
my
$values
=
join
(
', '
,
@$bad_values
);
print
<<EOT;
ERROR: There are invalid values for the $column column in the $table
table. (These values do not exist in the $foreign_table table, in the
$foreign_column column.)
Before continuing with checksetup, you will need to fix these values,
either by deleting these rows from the database, or changing the values
of $column in $table to point to valid values in $foreign_table.$foreign_column.
The bad values from the $table.$column column are:
$values
EOT
# I just picked a number above 2, to be considered "abnormal exit."
exit
3
;
}
}
# NOTE: This is NOT the function for general table updates. See
# update_table_definitions for that. This is only for the fielddefs table.
sub
update_fielddefs_definition
{
...
...
@@ -413,9 +380,9 @@ sub update_table_definitions {
if
(
$dbh
->
bz_column_info
(
'components'
,
'initialqacontact'
)
->
{
NOTNULL
})
{
$dbh
->
bz_alter_column
(
'components'
,
'initialqacontact'
,
{
TYPE
=>
'INT3'
});
}
$dbh
->
do
(
"UPDATE components SET initialqacontact = NULL "
.
"WHERE initialqacontact = 0"
);
}
_migrate_email_prefs_to_new_table
();
_initialize_dependency_tree_changes_email_pref
();
...
...
@@ -552,25 +519,13 @@ sub update_table_definitions {
$dbh
->
bz_add_column
(
'milestones'
,
'id'
,
{
TYPE
=>
'MEDIUMSERIAL'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
});
# Referential Integrity begins here
check_references
(
'profiles_activity'
,
'userid'
,
'profiles'
,
'userid'
);
$dbh
->
bz_alter_column
(
'profiles_activity'
,
'userid'
,
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}});
check_references
(
'profiles_activity'
,
'who'
,
'profiles'
,
'userid'
);
$dbh
->
bz_alter_column
(
'profiles_activity'
,
'who'
,
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
}});
check_references
(
'profiles_activity'
,
'fieldid'
,
'fielddefs'
,
'id'
);
$dbh
->
bz_alter_column
(
'profiles_activity'
,
'fieldid'
,
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'fielddefs'
,
COLUMN
=>
'id'
}});
################################################################
# New --TABLE-- changes should go *** A B O V E *** this point #
################################################################
Bugzilla::Hook::
process
(
'install-update_db'
);
$dbh
->
bz_setup_foreign_keys
();
}
# Subroutines should be ordered in the order that they are called.
...
...
template/en/default/global/messages.html.tmpl
View file @
40a19977
...
...
@@ -382,6 +382,9 @@
[% ELSIF message_tag == "install_file_perms_fix" %]
Fixing file permissions...
[% ELSIF message_tag == "install_fk_add" %]
Adding foreign key: [% table FILTER html %].[% column FILTER html %] -> [% fk.TABLE FILTER html %].[% fk.COLUMN FILTER html %]...
[% ELSIF message_tag == "install_group_create" %]
Creating group [% name FILTER html %]...
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment