[Rt-commit] rt branch 4.4/mysql-8 created. rt-4.4.6-16-gfe7069b34e
BPS Git Server
git at git.bestpractical.com
Mon Jul 18 18:33:26 UTC 2022
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".
The branch, 4.4/mysql-8 has been created
at fe7069b34e93ead613d890cf48da425d0b5a2fa9 (commit)
- Log -----------------------------------------------------------------
commit fe7069b34e93ead613d890cf48da425d0b5a2fa9
Author: Brian Conry <bconry at bestpractical.com>
Date: Mon Jul 18 13:12:51 2022 -0500
Add github action for testing with mysql 8
This adds a github action for testing with mysql8 using the latest
version of the official image from Oracle.
diff --git a/.github/workflows/github-action.yml b/.github/workflows/github-action.yml
index f706368ad6..c0bf3b725b 100644
--- a/.github/workflows/github-action.yml
+++ b/.github/workflows/github-action.yml
@@ -111,6 +111,62 @@ jobs:
fields: |
[{ "title": "Configuration", "value": "RT Server, MariaDB 10.3", "short": true },
{ "title": "URL", "value": "${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}?check_suite_focus=true", "short": true }]
+ rt_test_mysql8:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set up for tests
+ shell: bash
+ run: |
+ echo "RT_BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
+ echo "RT_GA_START_TIME=$(date +%s)" >> $GITHUB_ENV
+ - name: Checkout RT
+ uses: actions/checkout at v2
+ - name: Build RT
+ env:
+ RT_TEST_PARALLEL: 1
+ RT_DBA_USER: root
+ RT_DBA_PASSWORD: password
+ DB_VERSION_TAG: 8.0
+ shell: bash
+ run: |
+ docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -d mysql:$DB_VERSION_TAG --default-authentication-plugin=mysql_native_password
+ docker build -t rt-base .
+ docker run -d -v $GITHUB_WORKSPACE:/rt --name rt --link mysql:db rt-base
+ docker ps -a
+ docker exec rt bash -c "cd /rt && ./configure.ac --with-db-type=mysql --with-my-user-group --enable-layout=inplace --enable-developer --enable-externalauth --enable-gpg --enable-smime && mkdir -p /rt/var && make testdeps"
+ - name: Run RT tests
+ env:
+ RT_TEST_PARALLEL: 1
+ RT_DBA_USER: root
+ RT_DBA_PASSWORD: password
+ DB_VERSION_TAG: 8.0
+ shell: bash
+ run: docker exec -e RT_TEST_PARALLEL=1 -e RT_DBA_USER=root -e RT_DBA_PASSWORD=password rt bash -c "cd /rt && prove -lj6 t/*"
+ - name: Get run time
+ shell: bash
+ run: |
+ export RT_GA_END_TIME=$(date +%s)
+ echo RT_GA_START_TIME ${{ env.RT_GA_START_TIME }}
+ echo RT_GA_END_TIME $RT_GA_END_TIME
+ echo "RT_GA_END_TIME=$RT_GA_END_TIME" >> $GITHUB_ENV
+ export RT_GA_TEST_TIME=$(( RT_GA_END_TIME - ${{ env.RT_GA_START_TIME }} ))
+ # Convert seconds to HH::MM::SS
+ export RT_GA_TEST_TIME=$(date -u -d @"$RT_GA_TEST_TIME" +"%T")
+ echo "RT_GA_TEST_TIME=$RT_GA_TEST_TIME" >> $GITHUB_ENV
+ - name: Post results to Slack
+ if: always()
+ uses: edge/simple-slack-notify at v1.1.1
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_NOTIFICATIONS }}
+ with:
+ channel: '#github'
+ status: ${{ job.status }}
+ success_text: '${env.RT_BRANCH_NAME} (${env.GITHUB_RUN_NUMBER}) tests completed successfully in ${env.RT_GA_TEST_TIME}'
+ failure_text: '${env.RT_BRANCH_NAME} (${env.GITHUB_RUN_NUMBER}) tests failed in ${env.RT_GA_TEST_TIME}'
+ cancelled_text: '${env.RT_BRANCH_NAME} (${env.GITHUB_RUN_NUMBER}) tests cancelled in ${env.RT_GA_TEST_TIME}'
+ fields: |
+ [{ "title": "Configuration", "value": "RT Server, MySQL 8.0", "short": true },
+ { "title": "URL", "value": "${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}?check_suite_focus=true", "short": true }]
rt_test_postgresql_apache_mod_fcgid:
runs-on: ubuntu-latest
steps:
commit bd568d21817465c3edff42f4feff3ac748b24b51
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jan 21 05:19:42 2021 +0800
Update DBIx::SearchBuilder to 1.69 to work with MySQL 8
diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index 941af7834d..1a5eb434b0 100644
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -249,7 +249,7 @@ FCGI 0.74
.
$deps{'MYSQL'} = [ text_to_hash( << '.') ];
-DBIx::SearchBuilder 1.68
+DBIx::SearchBuilder 1.69
DBD::mysql 2.1018
.
commit 27a7d8c02fe1182d6284a7234f14f9418385e190
Author: Aaron Trevena <ast at bestpractical.com>
Date: Tue Sep 1 16:19:56 2020 +0100
Make RT work with MySQL 8
Update code for the following changes in MySQL 8:
* "Groups" is a reversed word
We need to quote it accordingly.
* Can't create user using GRANT any more
We need to create user first and then grant privileges.
diff --git a/etc/acl.mysql b/etc/acl.mysql
index 26e27fbfbc..da148bde66 100644
--- a/etc/acl.mysql
+++ b/etc/acl.mysql
@@ -1,5 +1,6 @@
sub acl {
+ my $dbh = shift;
my $db_name = RT->Config->Get('DatabaseName');
my $db_rthost = RT->Config->Get('DatabaseRTHost');
my $db_user = RT->Config->Get('DatabaseUser');
@@ -13,6 +14,19 @@ sub acl {
return;
}
$db_name =~ s/([_%\\])/\\$1/g;
+
+ if ( my $version = ( $dbh->selectrow_array("show variables like 'version'") )[1] ) {
+ if ( $version !~ /mariadb/i && $version =~ /^(\d+)\./ ) {
+ # run 2 part acl update for mysql 8 or higher
+ if ( $1 >= 8 ) {
+ return (
+ "CREATE USER IF NOT EXISTS '$db_user'\@'$db_rthost' IDENTIFIED BY '$db_pass';",
+ "GRANT SELECT,INSERT,CREATE,INDEX,UPDATE,DELETE ON `$db_name`.* TO '$db_user'\@'$db_rthost';",
+ );
+ }
+ }
+ }
+
return (
"GRANT SELECT,INSERT,CREATE,INDEX,UPDATE,DELETE
ON `$db_name`.*
diff --git a/etc/schema.mysql b/etc/schema.mysql
index 21975aba55..a2d361c866 100644
--- a/etc/schema.mysql
+++ b/etc/schema.mysql
@@ -70,7 +70,7 @@ CREATE TABLE Principals (
) ENGINE=InnoDB CHARACTER SET ascii;
-CREATE TABLE Groups (
+CREATE TABLE `Groups` (
id INTEGER NOT NULL AUTO_INCREMENT,
Name varchar(200) NULL ,
Description varchar(255) NULL ,
@@ -83,8 +83,8 @@ CREATE TABLE Groups (
PRIMARY KEY (id)
) ENGINE=InnoDB CHARACTER SET utf8;
-CREATE INDEX Groups1 ON Groups (Domain, Name, Instance);
-CREATE INDEX Groups2 On Groups (Instance);
+CREATE INDEX Groups1 ON `Groups` (Domain, Name, Instance);
+CREATE INDEX Groups2 On `Groups` (Instance);
CREATE TABLE ScripConditions (
id INTEGER NOT NULL AUTO_INCREMENT,
diff --git a/etc/upgrade/3.9.5/schema.mysql b/etc/upgrade/3.9.5/schema.mysql
index 83f2f4087f..2a40f46414 100644
--- a/etc/upgrade/3.9.5/schema.mysql
+++ b/etc/upgrade/3.9.5/schema.mysql
@@ -6,7 +6,7 @@ AND CustomFieldValues.id = Attributes.ObjectId);
DELETE FROM Attributes WHERE Name = 'Category' AND ObjectType = 'RT::CustomFieldValue';
-ALTER TABLE Groups
+ALTER TABLE `Groups`
ADD COLUMN Creator integer NOT NULL DEFAULT 0,
ADD COLUMN Created DATETIME NULL,
ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0,
diff --git a/etc/upgrade/4.1.13/backcompat b/etc/upgrade/4.1.13/backcompat
index 0dc53d224f..1126995277 100644
--- a/etc/upgrade/4.1.13/backcompat
+++ b/etc/upgrade/4.1.13/backcompat
@@ -22,6 +22,12 @@ if ( $groups->Next ) {
WHERE LOWER(Domain) IN ('aclequivalence', 'systeminternal')
OR LOWER(Domain) LIKE '%-role'"
);
+ } elsif ( $db_type eq 'mysql' ) {
+ $dbh->do(
+ "UPDATE `Groups` SET Name = Type
+ WHERE Domain IN ('ACLEquivalence', 'SystemInternal')
+ OR Domain LIKE '%-Role'"
+ );
} else {
$dbh->do(
"UPDATE Groups SET Name = Type
diff --git a/etc/upgrade/4.1.13/schema.mysql b/etc/upgrade/4.1.13/schema.mysql
index a429007e30..33e162fca2 100644
--- a/etc/upgrade/4.1.13/schema.mysql
+++ b/etc/upgrade/4.1.13/schema.mysql
@@ -1,2 +1,2 @@
-UPDATE Groups SET Name = Type
-WHERE Domain IN ('ACLEquivalence', 'SystemInternal') OR Domain LIKE '%-Role';
\ No newline at end of file
+UPDATE `Groups` SET Name = Type
+WHERE Domain IN ('ACLEquivalence', 'SystemInternal') OR Domain LIKE '%-Role';
diff --git a/etc/upgrade/4.1.4/schema.mysql b/etc/upgrade/4.1.4/schema.mysql
index e530ede81d..8a727b5eef 100644
--- a/etc/upgrade/4.1.4/schema.mysql
+++ b/etc/upgrade/4.1.4/schema.mysql
@@ -1 +1 @@
-UPDATE Groups SET Instance = 1 WHERE Domain = 'RT::System-Role' AND Instance = 0;
+UPDATE `Groups` SET Instance = 1 WHERE Domain = 'RT::System-Role' AND Instance = 0;
diff --git a/etc/upgrade/4.3.13/schema.mysql b/etc/upgrade/4.3.13/schema.mysql
index 31328a030b..d7ade7e2a7 100644
--- a/etc/upgrade/4.3.13/schema.mysql
+++ b/etc/upgrade/4.3.13/schema.mysql
@@ -15,6 +15,6 @@ ALTER TABLE Users
ALTER TABLE Principals
DROP COLUMN ObjectId;
-ALTER TABLE Groups
+ALTER TABLE `Groups`
DROP COLUMN Type;
diff --git a/etc/upgrade/4.4.2/content b/etc/upgrade/4.4.2/content
index 790342ddf8..e9998e54f1 100644
--- a/etc/upgrade/4.4.2/content
+++ b/etc/upgrade/4.4.2/content
@@ -22,9 +22,10 @@ our @Initial = (
# fix up inconsistent denormalized owner vs owner-role group members (#32381)
sub {
- my $sth = RT->DatabaseHandle->dbh->prepare(q[
+ my $groups_table = RT->Config->Get('DatabaseType') eq 'mysql' ? '`Groups`' : 'Groups';
+ my $sth = RT->DatabaseHandle->dbh->prepare(qq[
SELECT Tickets.Id, Tickets.Owner, GroupMembers.MemberId
- FROM Groups
+ FROM $groups_table
JOIN GroupMembers ON Groups.Id = GroupMembers.GroupId
JOIN Tickets ON Tickets.Id = Groups.Instance
WHERE Groups.Name = 'Owner'
diff --git a/etc/upgrade/upgrade-mysql-schema.pl b/etc/upgrade/upgrade-mysql-schema.pl
index 6ef9247e08..f50572be9b 100755
--- a/etc/upgrade/upgrade-mysql-schema.pl
+++ b/etc/upgrade/upgrade-mysql-schema.pl
@@ -306,7 +306,7 @@ sub convert_table {
}
for my $conversiontype (qw(char_to_binary binary_to_char)) {
next unless @{$alter_aggregator{$conversiontype}};
- push @sql_commands, qq{ALTER TABLE $table\n }.
+ push @sql_commands, qq{ALTER TABLE `$table`\n }.
join(",\n ",@{$alter_aggregator{$conversiontype}});
}
}
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 9f1da0cdec..1cda36e485 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -1765,7 +1765,7 @@ sub DropIndex {
if ( $db_type eq 'mysql' ) {
$args{'Table'} = $self->_CanonicTableNameMysql( $args{'Table'} );
$res = $dbh->do(
- 'drop index '. $dbh->quote_identifier($args{'Name'}) ." on $args{'Table'}",
+ 'drop index '. $dbh->quote_identifier($args{'Name'}) ." on ". $dbh->quote_identifier($args{'Table'}),
);
}
elsif ( $db_type eq 'Pg' ) {
@@ -1844,9 +1844,10 @@ sub CreateIndex {
}
}
+ my $table = $self->can('QuoteName') ? $self->QuoteName( $args{'Table'} ) : $args{'Table'};
my $sql = "CREATE"
. ($args{'Unique'}? ' UNIQUE' : '')
- ." INDEX $name ON $args{'Table'}"
+ ." INDEX $name ON $table"
."(". join( ', ', @columns ) .")"
;
diff --git a/lib/RT/Principal.pm b/lib/RT/Principal.pm
index 7489a02eca..18dde5caaf 100644
--- a/lib/RT/Principal.pm
+++ b/lib/RT/Principal.pm
@@ -615,8 +615,9 @@ sub _HasRoleRightQuery {
$groups->LimitToUserDefinedGroups;
$groups->WithMember( PrincipalId => $self->id, Recursively => 1 );
+ my $groups_table = $self->can('QuotedTableName') ? $self->QuotedTableName('Groups') : 'Groups';
my $query =
- " FROM Groups, Principals, CachedGroupMembers WHERE "
+ " FROM $groups_table, Principals, CachedGroupMembers WHERE "
# Never find disabled things
. "Principals.Disabled = 0 " . "AND CachedGroupMembers.Disabled = 0 "
diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
index 7189125a8b..6dc972542a 100644
--- a/lib/RT/Record.pm
+++ b/lib/RT/Record.pm
@@ -1601,6 +1601,7 @@ entire database.
sub LockForUpdate {
my $self = shift;
+ my $table = $self->can('QuotedTableName') ? $self->QuotedTableName($self->Table) : $self->Table;
my $pk = $self->_PrimaryKey;
my $id = @_ ? $_[0] : $self->$pk;
$self->_expire if $self->isa("DBIx::SearchBuilder::Record::Cachable");
@@ -1609,12 +1610,11 @@ sub LockForUpdate {
# "RESERVED" on the first UPDATE/INSERT/DELETE. Do a no-op
# UPDATE to force the upgade.
return RT->DatabaseHandle->dbh->do(
- "UPDATE " .$self->Table.
- " SET $pk = $pk WHERE 1 = 0");
+ "UPDATE $table SET $pk = $pk WHERE 1 = 0"
+ );
} else {
return $self->_LoadFromSQL(
- "SELECT * FROM ".$self->Table
- ." WHERE $pk = ? FOR UPDATE",
+ "SELECT * FROM $table WHERE $pk = ? FOR UPDATE",
$id,
);
}
diff --git a/sbin/rt-validator.in b/sbin/rt-validator.in
index 14cb5f3df6..5b4771bc5b 100644
--- a/sbin/rt-validator.in
+++ b/sbin/rt-validator.in
@@ -97,6 +97,7 @@ END
my $dbh = $RT::Handle->dbh;
my $db_type = RT->Config->Get('DatabaseType');
+my $groups_table = $db_type eq 'mysql' ? '`Groups`' : 'Groups' ;
my %TYPE = (
'Transactions.Field' => 'text',
@@ -608,7 +609,7 @@ FROM
AND cgm3.MemberId = gm2.MemberId
AND cgm3.Via = cgm1.id
AND cgm3.ImmediateParentId = cgm1.MemberId )
- LEFT JOIN Groups g ON (
+ LEFT JOIN $groups_table g ON (
cgm1.GroupId = g.id
)
WHERE cgm1.GroupId != cgm1.MemberId
@@ -680,7 +681,7 @@ push @CHECKS, 'Tickets -> other' => sub {
{
my $query = <<END;
SELECT Tickets.Id, Tickets.Owner
-FROM Groups
+FROM $groups_table
JOIN Tickets ON Tickets.Id = Groups.Instance
LEFT JOIN GroupMembers ON Groups.Id = GroupMembers.GroupId
WHERE Groups.Name = 'Owner'
@@ -717,7 +718,7 @@ END
{
my $query = <<END;
SELECT Tickets.Id, Tickets.Owner, GroupMembers.MemberId
-FROM Groups
+FROM $groups_table
JOIN GroupMembers ON Groups.Id = GroupMembers.GroupId
JOIN Tickets ON Tickets.Id = Groups.Instance
WHERE Groups.Name = 'Owner'
@@ -1006,10 +1007,11 @@ push @CHECKS, 'FIX: LastUpdatedBy and Creator' => sub {
next unless $object->_Accessible( $column, 'auto' );
my $table = m2t($model);
+ $table = "`$table`" if $db_type eq 'mysql';
my $query = <<END;
SELECT m.id, g.id, g.Instance
FROM
- Groups g JOIN $table m ON g.id = m.$column
+ $groups_table g JOIN $table m ON g.id = m.$column
WHERE
g.Domain = ?
AND g.Name = ?
@@ -1230,17 +1232,18 @@ push @CHECKS, 'Links: missing object' => sub {
foreach my $use ( @URI_USES ) {
my $stable = m2t( $use->{'model'} );
+ my $stablename = $db_type eq 'mysql' ? "`$stable`" : $stable;
my $scolumn = $use->{'column'};
foreach my $tmodel ( @models ) {
my $tclass = 'RT::'. $tmodel;
my $ttable = m2t($tmodel);
-
+ my $ttablename = ($db_type eq 'mysql') ? "`$ttable`" : $ttable;
my $tprefix = $prefix .'/'. ($tclass eq 'RT::Ticket'? 'ticket' : $tclass) .'/';
$tprefix = $prefix . '/article/' if $tclass eq 'RT::Article';
- my $query = "SELECT s.id FROM $stable s LEFT JOIN $ttable t "
+ my $query = "SELECT s.id FROM $stablename s LEFT JOIN $ttablename t "
." ON t.id = ". sql_str2int("SUBSTR(s.$scolumn, ?)")
." WHERE s.$scolumn LIKE ? AND t.id IS NULL";
my @binds = (length($tprefix) + 1, sql_escape_like($tprefix).'%');
@@ -1310,6 +1313,9 @@ sub check_integrity {
my ($ttable, @tcols) = (shift, shift);
my %args = @_;
+ my $stablename = $db_type eq 'mysql' ? "`$stable`" : $stable;
+ my $ttablename = $db_type eq 'mysql' ? "`$ttable`" : $ttable;
+
@scols = @{ $scols[0] } if ref $scols[0];
@tcols = @{ $tcols[0] } if ref $tcols[0];
@@ -1317,7 +1323,7 @@ sub check_integrity {
if $opt{'verbose'};
my $query = "SELECT s.id, ". join(', ', map "s.$_", @scols)
- ." FROM $stable s LEFT JOIN $ttable t"
+ ." FROM $stablename s LEFT JOIN $ttablename t"
." ON (". join(
' AND ', map columns_eq_cond('s', $stable, $scols[$_] => 't', $ttable, $tcols[$_]), (0..(@scols-1))
) .")"
@@ -1387,6 +1393,7 @@ sub check_uniqueness {
my $on = shift;
my %args = @_;
+ $on = "`$on`" if $db_type eq 'mysql';
my @columns = @{ $args{'columns'} };
print "Checking uniqueness of ( ", join(', ', map "'$_'", @columns )," ) in table '$on'\n"
@@ -1427,14 +1434,16 @@ sub check_uniqueness {
sub load_record {
my ($table, $id) = @_;
- my $sth = execute_query( "SELECT * FROM $table WHERE id = ?", $id );
+ my $tablename = $db_type eq 'mysql' ? "`$table`" : $table;
+ my $sth = execute_query( "SELECT * FROM $tablename WHERE id = ?", $id );
return $sth->fetchrow_hashref('NAME_lc');
}
sub delete_record {
my ($table, $id) = (@_);
print "Deleting record #$id in $table\n" if $opt{'verbose'};
- my $query = "DELETE FROM $table WHERE id = ?";
+ my $tablename = $db_type eq 'mysql' ? "`$table`" : $table;
+ my $query = "DELETE FROM $tablename WHERE id = ?";
$redo_check{ $_ } = 1 foreach @{ $redo_on{'Delete'}{ $table } || [] };
return execute_query( $query, $id );
}
@@ -1450,6 +1459,8 @@ sub update_records {
my $where = shift;
my $what = shift;
+ my $tablename = $db_type eq 'mysql' ? "`$table`" : $table;
+
my (@where_cols, @where_binds);
while ( my ($k, $v) = each %$where ) { push @where_cols, $k; push @where_binds, $v; }
@@ -1457,7 +1468,7 @@ sub update_records {
while ( my ($k, $v) = each %$what ) { push @what_cols, $k; push @what_binds, $v; }
print "Updating record(s) in $table\n" if $opt{'verbose'};
- my $query = "UPDATE $table SET ". join(', ', map "$_ = ?", @what_cols)
+ my $query = "UPDATE $tablename SET ". join(', ', map "$_ = ?", @what_cols)
." WHERE ". join(' AND ', map "$_ = ?", @where_cols);
$redo_check{ $_ } = 1 foreach @{ $redo_on{'Update'}{ $table } || [] };
return execute_query( $query, @what_binds, @where_binds );
diff --git a/t/validator/role_groups.t b/t/validator/role_groups.t
index a32ddcf138..5fe56634d9 100644
--- a/t/validator/role_groups.t
+++ b/t/validator/role_groups.t
@@ -7,7 +7,9 @@ my $ticket = RT::Test->create_ticket( Queue => 'General', Subject => 'test ticke
RT::Test->db_is_valid;
-$RT::Handle->dbh->do("DELETE FROM Groups where Domain IN ('RT::Queue-Role', 'RT::Ticket-Role')");
+my $groups_table = RT::Group->can('QuotedTableName') ? RT::Group->QuotedTableName('Groups') : 'Groups';
+
+$RT::Handle->dbh->do("DELETE FROM $groups_table where Domain IN ('RT::Queue-Role', 'RT::Ticket-Role')");
DBIx::SearchBuilder::Record::Cachable->FlushCache;
for my $object ( $ticket, $ticket->QueueObj ) {
diff --git a/t/web/query_log.t b/t/web/query_log.t
index cfb4d81d71..4d9ac87eb7 100644
--- a/t/web/query_log.t
+++ b/t/web/query_log.t
@@ -15,4 +15,6 @@ $m->get_ok("/Admin/Tools/Queries.html");
$m->text_contains("/index.html", "we include info about a page we hit while logging in");
$m->text_contains("Stack:", "stack traces");
$m->text_like(qr{/autohandler:\d+}, "stack trace includes mason components");
-$m->text_contains("SELECT * FROM Principals WHERE id = '".$root->id."'", "we interpolate bind params");
+
+my $id = $root->id;
+$m->text_like(qr/SELECT \* FROM .?Principals.? WHERE id = '$id'/, "we interpolate bind params");
-----------------------------------------------------------------------
hooks/post-receive
--
rt
More information about the rt-commit
mailing list