From 0582e3339dbe4cc185f1f25362a47a6a0b3b89b1 Mon Sep 17 00:00:00 2001 From: Jeff Janes Date: Mon, 5 May 2014 11:20:52 -0700 Subject: [PATCH] PostgreSQL: Make l10n_cache.lc_value binary Change-Id I427c6de5a0a29b43cff755db0eb8a750db620173 increases the probability that a null byte will attempt to be stored in the lc_value column. PostgreSQL does not allow that byte in a text column, so convert the column to bytea. If the column already contains corrupted data, the upgrade routine might fail. To prevent this, delete the contents of the table before changing the type. Bug: 62098 Change-Id: Ie8368bde398b2ae4d3cfc9ee7bf35874bd2ded68 --- includes/cache/LocalisationCache.php | 4 ++-- includes/installer/PostgresUpdater.php | 30 ++++++++++++++++++++++++++ maintenance/postgres/tables.sql | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/includes/cache/LocalisationCache.php b/includes/cache/LocalisationCache.php index 3bbf1bb89e..1153fd2962 100644 --- a/includes/cache/LocalisationCache.php +++ b/includes/cache/LocalisationCache.php @@ -1171,7 +1171,7 @@ class LCStoreDB implements LCStore { $row = $db->selectRow( 'l10n_cache', array( 'lc_value' ), array( 'lc_lang' => $code, 'lc_key' => $key ), __METHOD__ ); if ( $row ) { - return unserialize( $row->lc_value ); + return unserialize( $db->decodeBlob( $row->lc_value ) ); } else { return null; } @@ -1233,7 +1233,7 @@ class LCStoreDB implements LCStore { $this->batch[] = array( 'lc_lang' => $this->currentLang, 'lc_key' => $key, - 'lc_value' => serialize( $value ) ); + 'lc_value' => $this->dbw->encodeBlob( serialize( $value ) ) ); if ( count( $this->batch ) >= 100 ) { $this->dbw->insert( 'l10n_cache', $this->batch, __METHOD__ ); diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php index 8f6aac71ca..e7aab8aa9b 100644 --- a/includes/installer/PostgresUpdater.php +++ b/includes/installer/PostgresUpdater.php @@ -406,6 +406,7 @@ class PostgresUpdater extends DatabaseUpdater { array( 'addPgField', 'recentchanges', 'rc_source', "TEXT NOT NULL DEFAULT ''" ), array( 'addPgField', 'page', 'page_links_updated', "TIMESTAMPTZ NULL" ), array( 'addPgField', 'mwuser', 'user_password_expires', 'TIMESTAMPTZ NULL' ), + array( 'changeFieldPurgeTable', 'l10n_cache', 'lc_value', 'bytea', "replace(lc_value,'\','\\\\')::bytea" ), // 1.24 array( 'addPgField', 'page_props', 'pp_sortkey', 'float NULL' ), @@ -677,6 +678,35 @@ END; } } + protected function changeFieldPurgeTable( $table, $field, $newtype, $default ) { + ## For a cache table, empty it if the field needs to be changed, because the old contents + ## may be corrupted. If the column is already the desired type, refrain from purging. + $fi = $this->db->fieldInfo( $table, $field ); + if ( is_null( $fi ) ) { + $this->output( "...ERROR: expected column $table.$field to exist\n" ); + exit( 1 ); + } + + if ( $fi->type() === $newtype ) { + $this->output( "...column '$table.$field' is already of type '$newtype'\n" ); + } else { + $this->output( "Purging data from cache table '$table'\n" ); + $this->db->query("DELETE from $table" ); + $this->output( "Changing column type of '$table.$field' from '{$fi->type()}' to '$newtype'\n" ); + $sql = "ALTER TABLE $table ALTER $field TYPE $newtype"; + if ( strlen( $default ) ) { + $res = array(); + if ( preg_match( '/DEFAULT (.+)/', $default, $res ) ) { + $sqldef = "ALTER TABLE $table ALTER $field SET DEFAULT $res[1]"; + $this->db->query( $sqldef ); + $default = preg_replace( '/\s*DEFAULT .+/', '', $default ); + } + $sql .= " USING $default"; + } + $this->db->query( $sql ); + } + } + protected function setDefault( $table, $field, $default ) { $info = $this->db->fieldInfo( $table, $field ); diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index 6a2c41d065..abbfd3a166 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -678,7 +678,7 @@ CREATE INDEX user_properties_property ON user_properties (up_property); CREATE TABLE l10n_cache ( lc_lang TEXT NOT NULL, lc_key TEXT NOT NULL, - lc_value TEXT NOT NULL + lc_value BYTEA NOT NULL ); CREATE INDEX l10n_cache_lc_lang_key ON l10n_cache (lc_lang, lc_key); -- 2.20.1