FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
dbmigrate_3.7-3.8.php
Go to the documentation of this file.
1 <?php
2 /***********************************************************
3  Copyright (C) 2020 Siemens AG
4  Author: Gaurav Mishra <mishra.gaurav@siemens.com>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License
8  version 2 as published by the Free Software Foundation.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License along
16  with this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  ***********************************************************/
19 
26 
31 const MAX_ROW_SIZE = 100;
32 
37 const ENCODE_TABLES = array(
38  "copyright",
39  "ecc",
40  "keyword"
41 );
42 
48 {
49  $sql = "SELECT count(*) AS cnt FROM ";
50  $statement = __METHOD__ . ".getCountsFor";
51  $count = 0;
52  foreach (ENCODE_TABLES as $table) {
53  $row = $dbManager->getSingleRow($sql . $table, array(), $statement . $table);
54  $count += intval($row['cnt']);
55  }
56  return $count;
57 }
58 
66 function updateRecodedValues($dbManager, $table, $rows)
67 {
68  if (empty($rows)) {
69  return 0;
70  }
71 
72  $values = array_map(function($id,$content)
73  {
74  return "($id,'" . pg_escape_string($content) . "')";
75  }, array_keys($rows), $rows);
76 
77  $sql = "UPDATE $table AS cp " .
78  "SET content = up.content, hash = md5(up.content) " .
79  "FROM (VALUES" . join(",", $values) .
80  ") AS up(id,content) " .
81  "WHERE up.id = cp." . $table . "_pk";
82  unset($values);
83  $statement = __METHOD__ . ".updateContentFor.$table";
84 
85  $dbManager->begin();
86  foreach ($rows as $id => $content) {
87  $dbManager->queryOnce($sql, $statement);
88  }
89  $dbManager->commit();
90  return count($rows);
91 }
92 
100 function recodeContents(&$rows, $MODDIR)
101 {
102  $cmd = "$MODDIR/copyright/agent/fo_unicode_clean";
103  $descriptorspec = array(
104  0 => array("pipe", "r"),
105  1 => array("pipe", "w")
106  );
107 
108  $input = "";
109  foreach ($rows as $key => $content) {
110  if (empty($content)) {
111  continue;
112  }
113  $input .= "$key,|>$content<|\n";
114  }
115 
116  $pipes = array();
117  $escaper = proc_open($cmd, $descriptorspec, $pipes);
118 
119  if (is_resource($escaper)) {
120  fwrite($pipes[0], $input);
121  fclose($pipes[0]);
122  unset($input);
123 
124  $output = trim(stream_get_contents($pipes[1]));
125  fclose($pipes[1]);
126 
127  $returnVal = proc_close($escaper);
128  assert($returnVal == 0, "Encoder tool failed. Returned $returnVal.");
129  } else {
130  throw new \UnexpectedValueException("Unable to fork encoder tool ($cmd)");
131  }
132 
133  $output = explode("<|\n", $output);
134 
135  // Remove last delimiter as well
136  $lastIndex = count($output) - 1;
137  $output[$lastIndex] = str_replace("<|", "", $output[$lastIndex]);
138 
139  foreach ($output as $row) {
140  if (empty($row)) {
141  continue;
142  }
143  $line = explode(",|>", $row);
144  $id = $line[0];
145  $recodedContent = $line[1];
146  if ($rows[$id] == $recodedContent) {
147  unset($rows[$id]);
148  } else {
149  $rows[$id] = $recodedContent;
150  }
151  }
152 }
153 
158 function startRecodingTables($dbManager, $MODDIR)
159 {
160  if ($dbManager == NULL) {
161  echo "No connection object passed!\n";
162  return false;
163  }
164 
165  $sql = "SHOW client_encoding;";
166  $statement = __METHOD__ . ".getOldClientEncoding";
167  $oldEnc = $dbManager->getSingleRow($sql, array(), $statement);
168  $oldEnc = $oldEnc['client_encoding'];
169 
170  $sql = "SET client_encoding = 'SQL_ASCII';";
171  $dbManager->queryOnce($sql);
172 
173  foreach (ENCODE_TABLES as $table) {
174  $countSql = "SELECT count(*) AS cnt FROM $table;";
175  $countStatement = __METHOD__ . ".getCountFor.$table";
176  $contentSql = "SELECT " . $table . "_pk AS id, content " .
177  "FROM $table " .
178  "ORDER BY " . $table . "_pk " .
179  "LIMIT $1 OFFSET $2;";
180  $contentStatement = __METHOD__ . ".getContentFor.$table";
181 
182  $length = $dbManager->getSingleRow($countSql, array(), $countStatement);
183  $length = $length['cnt'];
184  echo "*** Recoding $length records from $table table ***\n";
185  $i = 0;
186  $updatedCount = 0;
187  while ($i < $length) {
188  $rows = $dbManager->getRows($contentSql, array(MAX_ROW_SIZE, $i),
189  $contentStatement);
190  $i += count($rows);
191  $data = array();
192  foreach ($rows as $row) {
193  $data[$row['id']] = $row['content'];
194  }
195  recodeContents($data, $MODDIR);
196  $updatedCount += updateRecodedValues($dbManager, $table, $data);
197  if ($i % 10000 == 0) {
198  echo " Processed $i rows for $table table\n";
199  }
200  }
201  echo "*** Recoded $updatedCount for $table table ***\n";
202  }
203 
204  $sql = "SET client_encoding = '$oldEnc';";
205  $dbManager->queryOnce($sql);
206 }
207 
213 function getDbEncoding($dbManager)
214 {
215  $dbName = $GLOBALS["SysConf"]["DBCONF"]["dbname"];
216  $sql = "SELECT pg_encoding_to_char(encoding) AS encoding " .
217  "FROM pg_database WHERE datname = '$dbName';";
218  $row = $dbManager->getSingleRow($sql);
219  return $row["encoding"];
220 }
221 
226 function updateDbEncoding($dbManager)
227 {
228  if (strcasecmp(getDbEncoding($dbManager), 'sql_ascii') == 0) {
229  $dbName = $GLOBALS["SysConf"]["DBCONF"]["dbname"];
230  $sql = "UPDATE pg_database SET encoding = pg_char_to_encoding('UTF8') " .
231  "WHERE datname = '$dbName';";
232  $cmd = 'su postgres --command "psql --command=\"BEGIN;' . $sql .
233  '\"COMMIT;"';
234  shell_exec($cmd);
235  }
236 }
237 
243 function checkMigrate3738Required($dbManager)
244 {
245  if ($dbManager == NULL){
246  echo "No connection object passed!\n";
247  return false;
248  }
249 
250  $migRequired = true;
251  foreach (ENCODE_TABLES as $table) {
252  if (DB_TableExists($table) != 1) {
253  $migRequired = false;
254  break;
255  }
256  }
257  if ($migRequired) {
258  $migRequired = false;
259  if (strcasecmp(getDbEncoding($dbManager), 'sql_ascii') == 0) {
260  $migRequired = true;
261  }
262  }
263 
264  return $migRequired;
265 }
266 
274 function recodeTables($dbManager, $MODDIR, $force = false)
275 {
276  if (! checkMigrate3738Required($dbManager)) {
277  // Migration not required
278  // Still change encoding of database from SQL_ASCII to UTF-8
279  updateDbEncoding($dbManager);
280  return 0;
281  }
282  $totalRecords = calculateNumberOfRecordsToRecode($dbManager);
283 
284  if ($totalRecords == 0) {
285  // Migration not required
286  return 0;
287  }
288  $envYes = getenv('FOSSENCODING');
289  if (!$force) {
290  $force = !empty($envYes);
291  }
292 
293  echo "*** Recoding $totalRecords records to UTF-8. ***\n";
294 
295  if (!$force && $totalRecords > 500000) {
296  $REDCOLOR = "\033[0;31m";
297  $NOCOLOR = "\033[0m";
298  echo "\n*********************************************************" .
299  "***********************\n";
300  echo "*** " . $REDCOLOR . "Error, script will take too much time. Not " .
301  "recoding entries. " . $NOCOLOR . " ***\n";
302  echo "*** Either rerun the fo-postinstall with \"--force-encode\" flag " .
303  "or set ***\n" .
304  "*** \"FOSSENCODING=1\" in environment or run script at " .
305  " ***\n";
306  echo "*** \"" . dirname(__FILE__) .
307  "/dbmigrate_change_db_encoding.php\" to continue as a separate process ***\n";
308  echo "*********************************************************" .
309  "***********************\n";
310  return -25;
311  }
312 
313  try {
314  echo "*** Recoding entries in copyright and sister tables ***\n";
315  startRecodingTables($dbManager, $MODDIR);
316  updateDbEncoding($dbManager);
317  } catch (Exception $e) {
318  echo "*** Something went wrong. Try again! ***\n";
319  $dbManager->rollback();
320  return -1;
321  }
322 }
323 
328 function Migrate_37_38($dbManager, $MODDIR)
329 {
330  if (! checkMigrate3738Required($dbManager)) {
331  // Migration not required
332  // Still change encoding of database from SQL_ASCII to UTF-8
333  updateDbEncoding($dbManager);
334  return;
335  }
336  try {
337  recodeTables($dbManager, $MODDIR);
338  } catch (Exception $e) {
339  echo "Something went wrong. Try running postinstall again!\n";
340  $dbManager->rollback();
341  }
342 }
recodeTables($dbManager, $MODDIR, $force=false)
Migrate_37_38($dbManager, $MODDIR)
updateRecodedValues($dbManager, $table, $rows)
updateDbEncoding($dbManager)
const MAX_ROW_SIZE
checkMigrate3738Required($dbManager)
DB_TableExists($tableName)
Check if table exists.
Definition: common-db.php:225
recodeContents(&$rows, $MODDIR)
calculateNumberOfRecordsToRecode($dbManager)
startRecodingTables($dbManager, $MODDIR)
const ENCODE_TABLES
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:695
getDbEncoding($dbManager)