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;
...
@@ -43,6 +43,7 @@ use Bugzilla::Error;
use
Bugzilla::DB::
Schema
;
use
Bugzilla::DB::
Schema
;
use
List::
Util
qw(max)
;
use
List::
Util
qw(max)
;
use
Storable
qw(dclone)
;
#####################################################################
#####################################################################
# Constants
# Constants
...
@@ -428,6 +429,23 @@ sub bz_populate_enum_tables {
...
@@ -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
# Schema Modification Methods
#####################################################################
#####################################################################
...
@@ -463,6 +481,24 @@ sub bz_add_column {
...
@@ -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
{
sub
bz_alter_column
{
my
(
$self
,
$table
,
$name
,
$new_def
,
$set_nulls_to
)
=
@_
;
my
(
$self
,
$table
,
$name
,
$new_def
,
$set_nulls_to
)
=
@_
;
...
@@ -515,11 +551,10 @@ sub bz_alter_column_raw {
...
@@ -515,11 +551,10 @@ sub bz_alter_column_raw {
my
@statements
=
$self
->
_bz_real_schema
->
get_alter_column_ddl
(
my
@statements
=
$self
->
_bz_real_schema
->
get_alter_column_ddl
(
$table
,
$name
,
$new_def
,
$table
,
$name
,
$new_def
,
defined
$set_nulls_to
?
$self
->
quote
(
$set_nulls_to
)
:
undef
);
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"
;
print
"Updating column $name in table $table ...\n"
;
if
(
defined
$current_def
)
{
if
(
defined
$current_def
)
{
my
$old_ddl
=
$self
->
_bz_schema
->
get_display_ddl
(
$table
,
$name
,
my
$old_ddl
=
$self
->
_bz_schema
->
get_type_ddl
(
$current_def
);
$current_def
);
print
"Old: $old_ddl\n"
;
print
"Old: $old_ddl\n"
;
}
}
print
"New: $new_ddl\n"
;
print
"New: $new_ddl\n"
;
...
@@ -569,8 +604,17 @@ sub bz_add_table {
...
@@ -569,8 +604,17 @@ sub bz_add_table {
if
(
!
$table_exists
)
{
if
(
!
$table_exists
)
{
$self
->
_bz_add_table_raw
(
$name
);
$self
->
_bz_add_table_raw
(
$name
);
$self
->
_bz_real_schema
->
add_table
(
$name
,
my
$table_def
=
dclone
(
$self
->
_bz_schema
->
get_table_abstract
(
$name
));
$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
;
$self
->
_bz_store_real_schema
;
}
}
}
}
...
@@ -751,7 +795,10 @@ sub _bz_get_initial_schema {
...
@@ -751,7 +795,10 @@ sub _bz_get_initial_schema {
sub
bz_column_info
{
sub
bz_column_info
{
my
(
$self
,
$table
,
$column
)
=
@_
;
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
{
sub
bz_index_info
{
...
@@ -1050,6 +1097,39 @@ sub _bz_populate_enum_table {
...
@@ -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
;
1
;
__END__
__END__
...
...
Bugzilla/DB/Schema.pm
View file @
40a19977
...
@@ -40,6 +40,7 @@ use Bugzilla::Hook;
...
@@ -40,6 +40,7 @@ use Bugzilla::Hook;
use
Bugzilla::
Util
;
use
Bugzilla::
Util
;
use
Bugzilla::
Constants
;
use
Bugzilla::
Constants
;
use
Carp
qw(confess)
;
use
Hash::
Util
qw(lock_value unlock_hash lock_keys unlock_keys)
;
use
Hash::
Util
qw(lock_value unlock_hash lock_keys unlock_keys)
;
use
Safe
;
use
Safe
;
# Historical, needed for SCHEMA_VERSION = '1.00'
# Historical, needed for SCHEMA_VERSION = '1.00'
...
@@ -98,20 +99,6 @@ more about how this integrates into the rest of Bugzilla.
...
@@ -98,20 +99,6 @@ more about how this integrates into the rest of Bugzilla.
=over
=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>
=item C<SCHEMA_VERSION>
The 'version' of the internal schema structure. This version number
The 'version' of the internal schema structure. This version number
...
@@ -194,7 +181,7 @@ The column pointed at in that table.
...
@@ -194,7 +181,7 @@ The column pointed at in that table.
=item C<DELETE>
=item C<DELETE>
What to do if the row in the parent table is deleted. Choices are
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
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
be forbidden by the database if there is a row in I<this> table that
...
@@ -203,17 +190,19 @@ C<DELETE>.
...
@@ -203,17 +190,19 @@ C<DELETE>.
C<CASCADE> means that this row will be deleted along with that row.
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>
=item C<UPDATE>
What to do if the value in the parent table is updated. It has the
What to do if the value in the parent table is updated. You can set this
same choices as L</DELETE>, except it defaults to C<CASCADE>, which means
to C<CASCADE> or C<RESTRICT>, which mean the same thing as they do for
"also update this column in this table."
L</DELETE>. This variable defaults to C<CASCADE>, which means "also
update this column in this table."
=back
=back
Note that not all our supported databases actually enforce C<RESTRICT>
and C<CASCADE>, so don't depend on them.
=cut
=cut
use
constant
SCHEMA_VERSION
=>
'2.00'
;
use
constant
SCHEMA_VERSION
=>
'2.00'
;
...
@@ -293,7 +282,9 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -293,7 +282,9 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
attach_id
=>
{
TYPE
=>
'INT3'
},
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
},
bug_when
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
},
fieldid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
fieldid
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
added
=>
{
TYPE
=>
'TINYTEXT'
},
added
=>
{
TYPE
=>
'TINYTEXT'
},
...
@@ -310,7 +301,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -310,7 +301,10 @@ use constant ABSTRACT_SCHEMA => {
cc
=>
{
cc
=>
{
FIELDS
=>
[
FIELDS
=>
[
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
],
],
INDEXES
=>
[
INDEXES
=>
[
cc_bug_id_idx
=>
{
FIELDS
=>
[
qw(bug_id who)
],
cc_bug_id_idx
=>
{
FIELDS
=>
[
qw(bug_id who)
],
...
@@ -359,7 +353,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -359,7 +353,10 @@ use constant ABSTRACT_SCHEMA => {
votes
=>
{
votes
=>
{
FIELDS
=>
[
FIELDS
=>
[
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
who
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
bug_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
vote_count
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
vote_count
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
],
],
...
@@ -379,7 +376,9 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -379,7 +376,9 @@ use constant ABSTRACT_SCHEMA => {
mimetype
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
mimetype
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
ispatch
=>
{
TYPE
=>
'BOOLEAN'
},
ispatch
=>
{
TYPE
=>
'BOOLEAN'
},
filename
=>
{
TYPE
=>
'varchar(100)'
,
NOTNULL
=>
1
},
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
,
isobsolete
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
,
DEFAULT
=>
'FALSE'
},
DEFAULT
=>
'FALSE'
},
isprivate
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
,
isprivate
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
,
...
@@ -725,7 +724,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -725,7 +724,10 @@ use constant ABSTRACT_SCHEMA => {
email_setting
=>
{
email_setting
=>
{
FIELDS
=>
[
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
},
relationship
=>
{
TYPE
=>
'INT1'
,
NOTNULL
=>
1
},
event
=>
{
TYPE
=>
'INT1'
,
NOTNULL
=>
1
},
event
=>
{
TYPE
=>
'INT1'
,
NOTNULL
=>
1
},
],
],
...
@@ -738,8 +740,14 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -738,8 +740,14 @@ use constant ABSTRACT_SCHEMA => {
watch
=>
{
watch
=>
{
FIELDS
=>
[
FIELDS
=>
[
watcher
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
watcher
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
watched
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
watched
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
],
],
INDEXES
=>
[
INDEXES
=>
[
watch_watcher_idx
=>
{
FIELDS
=>
[
qw(watcher watched)
],
watch_watcher_idx
=>
{
FIELDS
=>
[
qw(watcher watched)
],
...
@@ -752,7 +760,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -752,7 +760,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
NOTNULL
=>
1
,
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
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
},
name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
},
query
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
query
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
query_type
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
},
query_type
=>
{
TYPE
=>
'BOOLEAN'
,
NOTNULL
=>
1
},
...
@@ -765,8 +776,14 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -765,8 +776,14 @@ use constant ABSTRACT_SCHEMA => {
namedqueries_link_in_footer
=>
{
namedqueries_link_in_footer
=>
{
FIELDS
=>
[
FIELDS
=>
[
namedquery_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
namedquery_id
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
user_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
=>
[
INDEXES
=>
[
namedqueries_link_in_footer_id_idx
=>
{
FIELDS
=>
[
qw(namedquery_id user_id)
],
namedqueries_link_in_footer_id_idx
=>
{
FIELDS
=>
[
qw(namedquery_id user_id)
],
...
@@ -778,7 +795,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -778,7 +795,10 @@ use constant ABSTRACT_SCHEMA => {
component_cc
=>
{
component_cc
=>
{
FIELDS
=>
[
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
},
component_id
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
],
],
INDEXES
=>
[
INDEXES
=>
[
...
@@ -794,7 +814,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -794,7 +814,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
cookie
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
cookie
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
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
},
ipaddr
=>
{
TYPE
=>
'varchar(40)'
,
NOTNULL
=>
1
},
lastused
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
},
lastused
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
},
],
],
...
@@ -808,7 +831,9 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -808,7 +831,9 @@ use constant ABSTRACT_SCHEMA => {
# for these changes.
# for these changes.
tokens
=>
{
tokens
=>
{
FIELDS
=>
[
FIELDS
=>
[
userid
=>
{
TYPE
=>
'INT3'
},
userid
=>
{
TYPE
=>
'INT3'
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'CASCADE'
}},
issuedate
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
}
,
issuedate
=>
{
TYPE
=>
'DATETIME'
,
NOTNULL
=>
1
}
,
token
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
token
=>
{
TYPE
=>
'varchar(16)'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
},
PRIMARYKEY
=>
1
},
...
@@ -996,8 +1021,13 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -996,8 +1021,13 @@ use constant ABSTRACT_SCHEMA => {
PRIMARYKEY
=>
1
},
PRIMARYKEY
=>
1
},
name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
},
name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
},
product_id
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
product_id
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
},
initialowner
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
},
initialowner
=>
{
TYPE
=>
'INT3'
,
NOTNULL
=>
1
,
initialqacontact
=>
{
TYPE
=>
'INT3'
},
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
}},
initialqacontact
=>
{
TYPE
=>
'INT3'
,
REFERENCES
=>
{
TABLE
=>
'profiles'
,
COLUMN
=>
'userid'
,
DELETE
=>
'SET NULL'
}},
description
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
description
=>
{
TYPE
=>
'MEDIUMTEXT'
,
NOTNULL
=>
1
},
],
],
INDEXES
=>
[
INDEXES
=>
[
...
@@ -1063,7 +1093,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -1063,7 +1093,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
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
,
query_name
=>
{
TYPE
=>
'varchar(64)'
,
NOTNULL
=>
1
,
DEFAULT
=>
"''"
},
DEFAULT
=>
"''"
},
sortkey
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
,
sortkey
=>
{
TYPE
=>
'INT2'
,
NOTNULL
=>
1
,
...
@@ -1082,7 +1115,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -1082,7 +1115,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
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_day
=>
{
TYPE
=>
'varchar(32)'
},
run_time
=>
{
TYPE
=>
'varchar(32)'
},
run_time
=>
{
TYPE
=>
'varchar(32)'
},
run_next
=>
{
TYPE
=>
'DATETIME'
},
run_next
=>
{
TYPE
=>
'DATETIME'
},
...
@@ -1099,7 +1135,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -1099,7 +1135,10 @@ use constant ABSTRACT_SCHEMA => {
FIELDS
=>
[
FIELDS
=>
[
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
id
=>
{
TYPE
=>
'MEDIUMSERIAL'
,
PRIMARYKEY
=>
1
,
NOTNULL
=>
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)'
},
subject
=>
{
TYPE
=>
'varchar(128)'
},
body
=>
{
TYPE
=>
'MEDIUMTEXT'
},
body
=>
{
TYPE
=>
'MEDIUMTEXT'
},
],
],
...
@@ -1159,7 +1198,10 @@ use constant ABSTRACT_SCHEMA => {
...
@@ -1159,7 +1198,10 @@ use constant ABSTRACT_SCHEMA => {
profile_setting
=>
{
profile_setting
=>
{
FIELDS
=>
[
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_name
=>
{
TYPE
=>
'varchar(32)'
,
NOTNULL
=>
1
},
setting_value
=>
{
TYPE
=>
'varchar(32)'
,
NOTNULL
=>
1
},
setting_value
=>
{
TYPE
=>
'varchar(32)'
,
NOTNULL
=>
1
},
],
],
...
@@ -1376,7 +1418,8 @@ C<ALTER TABLE> SQL statement
...
@@ -1376,7 +1418,8 @@ C<ALTER TABLE> SQL statement
my
$self
=
shift
;
my
$self
=
shift
;
my
$finfo
=
(
@_
==
1
&&
ref
(
$_
[
0
])
eq
'HASH'
)
?
$_
[
0
]
:
{
@_
};
my
$finfo
=
(
@_
==
1
&&
ref
(
$_
[
0
])
eq
'HASH'
)
?
$_
[
0
]
:
{
@_
};
my
$type
=
$finfo
->
{
TYPE
};
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
};
my
$default
=
$finfo
->
{
DEFAULT
};
# Replace any abstract default value (such as 'TRUE' or 'FALSE')
# Replace any abstract default value (such as 'TRUE' or 'FALSE')
...
@@ -1397,17 +1440,6 @@ C<ALTER TABLE> SQL statement
...
@@ -1397,17 +1440,6 @@ C<ALTER TABLE> SQL statement
}
#eosub--get_type_ddl
}
#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
{
sub
get_fk_ddl
{
=item C<_get_fk_ddl>
=item C<_get_fk_ddl>
...
@@ -1441,8 +1473,8 @@ is undefined.
...
@@ -1441,8 +1473,8 @@ is undefined.
my
$update
=
$references
->
{
UPDATE
}
||
'CASCADE'
;
my
$update
=
$references
->
{
UPDATE
}
||
'CASCADE'
;
my
$delete
=
$references
->
{
DELETE
}
||
'RESTRICT'
;
my
$delete
=
$references
->
{
DELETE
}
||
'RESTRICT'
;
my
$to_table
=
$references
->
{
TABLE
}
||
die
"No table in reference"
;
my
$to_table
=
$references
->
{
TABLE
}
||
confess
"No table in reference"
;
my
$to_column
=
$references
->
{
COLUMN
}
||
die
"No column in reference"
;
my
$to_column
=
$references
->
{
COLUMN
}
||
confess
"No column in reference"
;
my
$fk_name
=
$self
->
_get_fk_name
(
$table
,
$column
,
$references
);
my
$fk_name
=
$self
->
_get_fk_name
(
$table
,
$column
,
$references
);
return
"\n CONSTRAINT $fk_name FOREIGN KEY ($column)\n"
return
"\n CONSTRAINT $fk_name FOREIGN KEY ($column)\n"
...
@@ -1460,10 +1492,10 @@ sub _get_fk_name {
...
@@ -1460,10 +1492,10 @@ sub _get_fk_name {
return
"fk_${table}_${column}_${to_table}_${to_column}"
;
return
"fk_${table}_${column}_${to_table}_${to_column}"
;
}
}
sub
_
get_add_fk_sql
{
sub
get_add_fk_sql
{
my
(
$self
,
$table
,
$column
,
$
new_
def
)
=
@_
;
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"
);
return
(
"ALTER TABLE $table ADD $fk_string"
);
}
}
...
@@ -1519,22 +1551,12 @@ sub get_table_list {
...
@@ -1519,22 +1551,12 @@ sub get_table_list {
Parameters: none
Parameters: none
Returns: An array of table names. The tables specified
Returns: An array of table names, in alphabetical order.
in L</TABLES_FIRST> will come first, in order. The
rest of the tables will be in random order.
=cut
=cut
my
$self
=
shift
;
my
$self
=
shift
;
return
sort
keys
%
{
$self
->
{
schema
}};
my
%
schema
=
%
{
$self
->
{
schema
}};
my
@tables
;
foreach
my
$table
(
TABLES_FIRST
)
{
push
(
@tables
,
$table
);
delete
$schema
{
$table
};
}
push
(
@tables
,
keys
%
schema
);
return
@tables
;
}
}
sub
get_table_columns
{
sub
get_table_columns
{
...
@@ -1603,14 +1625,6 @@ sub get_table_ddl {
...
@@ -1603,14 +1625,6 @@ sub get_table_ddl {
push
(
@ddl
,
$index_sql
)
if
$index_sql
;
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
}
})
push
(
@ddl
,
@
{
$self
->
{
schema
}{
$table
}{
DB_EXTRAS
}
})
if
(
ref
(
$self
->
{
schema
}{
$table
}{
DB_EXTRAS
}));
if
(
ref
(
$self
->
{
schema
}{
$table
}{
DB_EXTRAS
}));
...
@@ -1704,6 +1718,11 @@ sub get_add_column_ddl {
...
@@ -1704,6 +1718,11 @@ sub get_add_column_ddl {
(
push
(
@statements
,
"UPDATE $table SET $column = $init_value"
))
(
push
(
@statements
,
"UPDATE $table SET $column = $init_value"
))
if
defined
$init_value
;
if
defined
$init_value
;
if
(
defined
$definition
->
{
REFERENCES
})
{
push
(
@statements
,
$self
->
get_add_fk_sql
(
$table
,
$column
,
$definition
->
{
REFERENCES
}));
}
return
(
@statements
);
return
(
@statements
);
}
}
...
@@ -1824,15 +1843,6 @@ sub get_alter_column_ddl {
...
@@ -1824,15 +1843,6 @@ sub get_alter_column_ddl {
push
(
@statements
,
"ALTER TABLE $table DROP PRIMARY KEY"
);
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
;
return
@statements
;
}
}
...
@@ -2220,31 +2230,17 @@ sub columns_equal {
...
@@ -2220,31 +2230,17 @@ sub columns_equal {
$col_one
->
{
TYPE
}
=
uc
(
$col_one
->
{
TYPE
});
$col_one
->
{
TYPE
}
=
uc
(
$col_one
->
{
TYPE
});
$col_two
->
{
TYPE
}
=
uc
(
$col_two
->
{
TYPE
});
$col_two
->
{
TYPE
}
=
uc
(
$col_two
->
{
TYPE
});
# It doesn't work to compare the two REFERENCES items, because
# We don't care about foreign keys when comparing column definitions.
# they look like 'HASH(0xaf3c434)' to diff_arrays--they'll never
delete
$col_one
->
{
REFERENCES
};
# be equal.
delete
$col_two
->
{
REFERENCES
};
my
%
col_one_def
=
%
$col_one
;
delete
$col_one_def
{
REFERENCES
};
my
%
col_two_def
=
%
$col_two
;
delete
$col_two_def
{
REFERENCES
};
my
@col_one_array
=
%
col_one_def
;
my
@col_one_array
=
%
$col_one
;
my
@col_two_array
=
%
col_two_def
;
my
@col_two_array
=
%
$col_two
;
my
(
$removed
,
$added
)
=
diff_arrays
(
\
@col_one_array
,
\
@col_two_array
);
my
(
$removed
,
$added
)
=
diff_arrays
(
\
@col_one_array
,
\
@col_two_array
);
# If there are no differences between the arrays, then they are equal.
# If there are no differences between the arrays, then they are equal.
my
$defs_identical
=
!
scalar
(
@$removed
)
&&
!
scalar
(
@$added
);
return
!
scalar
(
@$removed
)
&&
!
scalar
(
@$added
)
?
1
:
0
;
# 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
;
}
}
...
...
Bugzilla/DB/Schema/Mysql.pm
View file @
40a19977
...
@@ -176,17 +176,10 @@ sub get_alter_column_ddl {
...
@@ -176,17 +176,10 @@ sub get_alter_column_ddl {
# keys are not allowed.
# keys are not allowed.
delete
$new_def_copy
{
PRIMARYKEY
};
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
$new_ddl
=
$self
->
get_type_ddl
(
\%
new_def_copy
);
my
@statements
;
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
push
(
@statements
,
"UPDATE $table SET $column = $set_nulls_to
WHERE $column IS NULL"
)
if
defined
$set_nulls_to
;
WHERE $column IS NULL"
)
if
defined
$set_nulls_to
;
push
(
@statements
,
"ALTER TABLE $table CHANGE COLUMN
push
(
@statements
,
"ALTER TABLE $table CHANGE COLUMN
...
@@ -196,10 +189,6 @@ sub get_alter_column_ddl {
...
@@ -196,10 +189,6 @@ sub get_alter_column_ddl {
push
(
@statements
,
"ALTER TABLE $table DROP PRIMARY KEY"
);
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
;
return
@statements
;
}
}
...
...
Bugzilla/Install/DB.pm
View file @
40a19977
...
@@ -49,39 +49,6 @@ sub indicate_progress {
...
@@ -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
# NOTE: This is NOT the function for general table updates. See
# update_table_definitions for that. This is only for the fielddefs table.
# update_table_definitions for that. This is only for the fielddefs table.
sub
update_fielddefs_definition
{
sub
update_fielddefs_definition
{
...
@@ -413,9 +380,9 @@ sub update_table_definitions {
...
@@ -413,9 +380,9 @@ sub update_table_definitions {
if
(
$dbh
->
bz_column_info
(
'components'
,
'initialqacontact'
)
->
{
NOTNULL
})
{
if
(
$dbh
->
bz_column_info
(
'components'
,
'initialqacontact'
)
->
{
NOTNULL
})
{
$dbh
->
bz_alter_column
(
'components'
,
'initialqacontact'
,
$dbh
->
bz_alter_column
(
'components'
,
'initialqacontact'
,
{
TYPE
=>
'INT3'
});
{
TYPE
=>
'INT3'
});
}
$dbh
->
do
(
"UPDATE components SET initialqacontact = NULL "
.
$dbh
->
do
(
"UPDATE components SET initialqacontact = NULL "
.
"WHERE initialqacontact = 0"
);
"WHERE initialqacontact = 0"
);
}
_migrate_email_prefs_to_new_table
();
_migrate_email_prefs_to_new_table
();
_initialize_dependency_tree_changes_email_pref
();
_initialize_dependency_tree_changes_email_pref
();
...
@@ -552,25 +519,13 @@ sub update_table_definitions {
...
@@ -552,25 +519,13 @@ sub update_table_definitions {
$dbh
->
bz_add_column
(
'milestones'
,
'id'
,
$dbh
->
bz_add_column
(
'milestones'
,
'id'
,
{
TYPE
=>
'MEDIUMSERIAL'
,
NOTNULL
=>
1
,
PRIMARYKEY
=>
1
});
{
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 #
# New --TABLE-- changes should go *** A B O V E *** this point #
################################################################
################################################################
Bugzilla::Hook::
process
(
'install-update_db'
);
Bugzilla::Hook::
process
(
'install-update_db'
);
$dbh
->
bz_setup_foreign_keys
();
}
}
# Subroutines should be ordered in the order that they are called.
# 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 @@
...
@@ -382,6 +382,9 @@
[% ELSIF message_tag == "install_file_perms_fix" %]
[% ELSIF message_tag == "install_file_perms_fix" %]
Fixing file permissions...
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" %]
[% ELSIF message_tag == "install_group_create" %]
Creating group [% name FILTER html %]...
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