Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
system_integrity_check_indexes.php
1 <?php
34 if (ini_get('memory_limit') != '-1') ini_set('memory_limit', -1);
35 error_reporting(E_ALL);
36 
40 if (php_sapi_name() != 'cli') trigger_error("You can only run this script from the command line\n", E_USER_ERROR);
41 
42 $SYSTEM_ROOT = (isset($_SERVER['argv'][1])) ? $_SERVER['argv'][1] : '';
43 if (empty($SYSTEM_ROOT)) {
44  echo "ERROR: You need to supply the path to the System Root as the first argument\n";
45  exit();
46 }
47 
48 if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT.'/core/include/init.inc')) {
49  echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
50  exit();
51 }
52 
53 require_once $SYSTEM_ROOT.'/data/private/conf/db.inc';
54 require_once $SYSTEM_ROOT.'/core/include/init.inc';
55 require_once $SYSTEM_ROOT.'/core/lib/DAL/DAL.inc';
56 require_once $SYSTEM_ROOT.'/core/lib/MatrixDAL/MatrixDAL.inc';
57 
58 $db_error = false;
59 try {
60  $db_connection = MatrixDAL::dbConnect($db_conf['db']);
61 } catch (Exception $e) {
62  echo "Unable to connect to the db: " . $e->getMessage() . "\n";
63  $db_error = true;
64 }
65 
66 if ($db_error) {
67  exit;
68 }
69 
71 
87 $skip_definition_checks = array (
88  'sq_ast_attr_val_concat',
89  'sq_rb_ast_attr_val_concat',
90 );
91 
92 
97 $dbtype = _getDbType();
98 
99 $index_info = getIndexes();
100 $full_index_list = $index_info['index_list'];
101 $parallel_list = $index_info['parallel_list'];
102 $constraint_list = $index_info['constraint_list'];
103 
104 pre_echo('Checking Indexes');
105 
106 $sql_commands = array();
107 $bad_indexes = array();
108 $parallel_warnings = array();
109 $postgres_primary_key_warnings = array();
110 
111 $packages = $GLOBALS['SQ_SYSTEM']->getInstalledPackages();
112 foreach ($packages as $_pkgid => $pkg_details) {
113  $pkg_name = $pkg_details['code_name'];
114  if ($pkg_name == '__core__') {
115  $file = $SYSTEM_ROOT.'/core/assets/tables.xml';
116  } else {
117  $file = SQ_PACKAGES_PATH . '/' . $pkg_name . '/tables.xml';
118  }
119 
124  if (!is_file($file)) {
125  continue;
126  }
127  $info = parse_tables_xml($file, $db_conf['db']['type']);
128 
129  foreach($info['tables'] as $tablename => $table_info) {
130  $tables = array ($tablename);
131  if ($table_info['rollback']) {
132  $tables[] = 'rb_' . $tablename;
133  }
134 
135  if (!empty($table_info['primary_key'])) {
136  foreach ($tables as $tablename) {
150  $expected_idx_name = $tablename . '_pk';
151  $full_idx_names = array (
152  $expected_idx_name,
153  $tablename . '_pkey',
154  'sq_' . $tablename . '_pkey',
155  'sq_' . $tablename . '_pk',
156  );
157 
158  $tablename = 'sq_' . $tablename;
159 
160  printName('Checking table ' . $tablename . ' for a primary key');
161  $error = true;
162  $idx_name = null;
163  foreach ($full_idx_names as $_idx_pos => $idx_name) {
164  if (in_array($idx_name, array_keys($full_index_list[$tablename]))) {
165  $error = false;
166  break;
167  }
168  }
169 
170  $idx_columns = $table_info['primary_key'];
171  if (substr($tablename, 3, 3) == 'rb_') {
172  array_unshift($idx_columns, 'sq_eff_from');
173  }
174 
181  if ($error) {
182  $temp_idx_cols = implode(',', $idx_columns);
183  if (in_array($temp_idx_cols, $full_index_list[$tablename])) {
184  $idx_name = array_search($temp_idx_cols, $full_index_list[$tablename]);
185  $error = false;
186  }
187  }
188 
194  if (!$error) {
195  if ($db_conf['db']['type'] == 'pgsql') {
196  if ($idx_name !== $expected_idx_name) {
197  $postgres_primary_key_warnings[$tablename] = array (
198  'current' => $idx_name,
199  'expected' => $expected_idx_name,
200  'fields' => $idx_columns,
201  );
202  }
203  }
204  }
205 
206  $create_index_statement = create_index_sql($tablename, $idx_columns, $tablename . '_pk', NULL, true);
207 
208  if ($error) {
209  printUpdateStatus('Missing');
210  $sql_commands[] = $create_index_statement;
211  } else {
212 
213  check_index_parallel($tablename, $idx_name);
214 
215  $index_definition = $full_index_list[$tablename][$idx_name];
216  $found_index_columns = explode(',', $index_definition);
217  if ($found_index_columns === $idx_columns) {
218  printUpdateStatus('OK');
219  } else {
220  printUpdateStatus('Incorrect');
221  $bad_indexes[] = array('table_name' => $tablename, 'index_name' => $idx_name, 'expected' => implode(',', $idx_columns), 'found' => $index_definition, 'primary_key' => true);
222  $sql_commands[] = $create_index_statement;
223  }
224  unset($full_index_list[$tablename][$idx_name]);
225  }
226  }
227  }
228 
229  if (!empty($table_info['indexes'])) {
230  foreach ($table_info['indexes'] as $index_col => $index_info) {
235  if (isset($index_info['db_type'])) {
236  if ($index_info['db_type'] !== $db_conf['db']['type']) {
237  continue;
238  }
239  }
240 
241  foreach ($tables as $tablename) {
242  $tablename = 'sq_' . $tablename;
243  $full_idx_name = $tablename . '_' . $index_info['name'];
244  printName('Checking for index ' . $full_idx_name);
245 
246  $error = true;
247  if (isset($full_index_list[$tablename][$full_idx_name])) {
248  $error = false;
249  } else {
256  $temp_idx_cols = implode(',', $index_info['columns']);
257  if (in_array($temp_idx_cols, $full_index_list[$tablename])) {
258  $full_idx_name = array_search($temp_idx_cols, $full_index_list[$tablename]);
259  $error = false;
260  }
261  }
262 
263  if ($error) {
264  printUpdateStatus('Missing');
265  } else {
266 
267  if (in_array($full_idx_name, $skip_definition_checks)) {
268  unset($full_index_list[$tablename][$full_idx_name]);
269  printUpdateStatus('OK');
270  continue;
271  }
272 
273  check_index_parallel($tablename, $full_idx_name);
274 
275  $index_definition = $full_index_list[$tablename][$full_idx_name];
276  $found_index_columns = explode(',', $index_definition);
277 
278  unset($full_index_list[$tablename][$full_idx_name]);
279 
280  if ($found_index_columns === $index_info['columns']) {
281  printUpdateStatus('OK');
282  continue;
283  } else {
284  printUpdateStatus('Incorrect');
285  $bad_indexes[] = array('index_name' => $full_idx_name, 'expected' => implode(',', $index_info['columns']), 'found' => $index_definition);
286  continue;
287  }
288  }
289 
290  $sql_commands[] = create_index_sql($tablename, $index_info['columns'], $index_info['name'], $index_info['type']);
291  }
292  }// end foreach
293  }//end if
294 
295  if (!empty($table_info['unique_key'])) {
296  foreach ($tables as $tablename) {
297 
298  $tablename = 'sq_' . $tablename;
299 
300  $idx_columns = $table_info['unique_key'];
301  if (substr($tablename, 3, 3) == 'rb_') {
302  array_unshift($idx_columns, 'sq_eff_from');
303  }
304 
310  $full_idx_name = $tablename . '_' . $idx_columns[0] . '_key';
311  printName('Checking for index ' . $full_idx_name);
312 
313  $create_index_statement = create_index_sql($tablename, $idx_columns, $full_idx_name, NULL, false, true);
314 
315  $error = true;
316  if (isset($full_index_list[$tablename][$full_idx_name])) {
317  $error = false;
318  } else {
325  $temp_idx_cols = implode(',', $idx_columns);
326  if (in_array($temp_idx_cols, $full_index_list[$tablename])) {
327  $full_idx_name = array_search($temp_idx_cols, $full_index_list[$tablename]);
328  $error = false;
329  }
330  }
331 
332  if ($error) {
333  printUpdateStatus('Missing');
334  $sql_commands[] = $create_index_statement;
335  continue;
336  } else {
337  if (in_array($full_idx_name, $skip_definition_checks)) {
338  unset($full_index_list[$tablename][$full_idx_name]);
339  printUpdateStatus('OK');
340  continue;
341  }
342 
343  check_index_parallel($tablename, $full_idx_name);
344 
345  $index_definition = $full_index_list[$tablename][$full_idx_name];
346  $found_index_columns = explode(',', $index_definition);
347 
348  unset($full_index_list[$tablename][$full_idx_name]);
349 
350  if ($found_index_columns === $idx_columns) {
351  printUpdateStatus('OK');
352  continue;
353  }
354 
355  printUpdateStatus('Incorrect');
356 
357  $bad_indexes[] = array('index_name' => $full_idx_name, 'expected' => implode(',', $idx_columns), 'found' => $index_definition);
358  $sql_commands[] = $create_index_statement;
359  }
360  }
361  }// end foreach
362  }
363 }
364 
365 $extra_message_shown = false;
366 $dbtype = _getDbType();
367 if ($dbtype === 'pgsql') {
368  pre_echo('Checking locale settings');
369  $locale_query = "select setting from pg_settings where name='lc_ctype'";
370  $locale_info = MatrixDAL::executeSqlAll($locale_query);
371  $locale = $locale_info[0]['setting'];
372  if ($locale !== 'C') {
373  $extra_message_shown = true;
374  $msg = "Your database 'locale' setting is " . $locale . "\n";
375  $msg .= "You may get some performance improvements changing this to 'C'\n";
376  $msg .= "However changing this requires re-initializing the whole db cluster.\n";
377  $msg .= "See http://www.postgresql.org/docs/8.1/static/charset.html for more information.";
378  pre_echo($msg);
379  }
380 }
381 
382 pre_echo('Check complete');
383 if (!empty($bad_indexes)) {
384  $extra_message_shown = true;
385  $msg = "Some indexes had incorrect definitions.\n";
386  $msg .= "To fix these, you will need to drop the old indexes before re-adding them:\n\n";
387  foreach ($bad_indexes as $details) {
388  // oracle is case sensitive ..
389  if ($dbtype == 'oci') {
390  $details['index_name'] = strtoupper($details['index_name']);
391  }
392 
400  if (
401  ($dbtype == 'pgsql' && isset($details['primary_key'])) ||
402  ($dbtype == 'oci' && isset($constraint_list[$details['index_name']]))
403  ) {
404  $tablename = $details['table_name'];
405  if (substr($tablename, 0, 3) != 'sq_') {
406  $tablename = 'sq_' . $tablename;
407  }
408  $msg .= "ALTER TABLE " . $details['table_name'] . " DROP CONSTRAINT " . $details['index_name'] . ";\n";
409  continue;
410  }
411  $msg .= "DROP INDEX " . $details['index_name'] . ";\n";
412  }
413  pre_echo($msg);
414 }
415 
416 if (!empty($sql_commands)) {
417  $extra_message_shown = true;
418  $msg = "Some expected indexes were missing or incorrect.\n";
419  $msg .= "To fix the database, please run the following queries:\n\n" . implode("\n", $sql_commands);
420  pre_echo($msg);
421 }
422 
423 if (!empty($parallel_warnings)) {
424  $extra_message_shown = true;
425  $msg = "Some indexes may have issues.\n";
426  $msg .= "If these changes have been made deliberately, ignore this warning.\n\n";
427  $msg .= "The following indexes have been made to run in parallel:\n";
428  foreach ($parallel_warnings as $row) {
429  foreach ($row as $idx_name => $parallel_setting) {
430  $msg .= $idx_name . " (" . $parallel_setting . ")\n";
431  }
432  }
433  $msg .= "This can lead to performance loss.\n\n";
434 
435  $msg .= "To reset these, run the following command(s):\n";
436  foreach ($parallel_warnings as $row) {
437  foreach ($row as $idx_name => $parallel_setting) {
438  $msg .= "ALTER INDEX " . $idx_name . " REBUILD PARALLEL 1;\n";
439  }
440  }
441  pre_echo($msg);
442 }
443 
444 if (!empty($postgres_primary_key_warnings)) {
445  $extra_message_shown = true;
446  $msg = "Some tables have incorrect names for primary keys.\n";
447  $msg .= "This won't cause any problems, but upgrade guides may be harder to follow\n";
448  $msg .= "as they expect the names to be a certain way.\n";
449  $msg .= "To fix these tables, run the following commands\n";
450  $msg .= "They can take a while depending on the size of the table.\n\n";
451  $msg .= "BEGIN;\n";
452  foreach ($postgres_primary_key_warnings as $tablename => $details) {
453  $msg .= "ALTER TABLE ONLY " . $tablename . " DROP CONSTRAINT " . $details['current'] . ";\n";
454  $msg .= "ALTER TABLE " . $tablename . " ADD CONSTRAINT " . $details['expected'] . " PRIMARY KEY (" . implode(',', $details['fields']) . ");\n";
455  }
456  $msg .= "COMMIT;\n";
457  pre_echo($msg);
458 }
459 
460 $show_extra_indexes_message = false;
461 $extra_indexes_message = "Extra indexes have been found on the following tables.\n";
462 $extra_indexes_message .= "If these changes have been made deliberately, ignore this warning.\n";
463 $extra_indexes_message .= "This can lead to performance loss.\n";
464 $extra_indexes_message .= "To remove these, run the following command(s):\n\n";
465 foreach ($full_index_list as $tablename => $info) {
466  if (strpos($tablename, 'sq_rb_') !== FALSE) {
467  continue;
468  }
469  if (empty($info) === TRUE) {
470  continue;
471  }
472  $extra_message_shown = true;
473  $show_extra_indexes_message = true;
474  $extra_indexes_message .= "These were found on table ".$tablename.":\n";
475  foreach ($info as $index_name => $fields) {
476  $extra_indexes_message .= "\tDROP INDEX ".$index_name.";\n";
477  }
478  $extra_indexes_message .= "\n";
479 }
480 
481 if ($show_extra_indexes_message) {
482  pre_echo(trim($extra_indexes_message));
483 }
484 
485 if (!$extra_message_shown) {
486  pre_echo('Everything has been checked and no problems were found.');
487 }
488 
489 
499 function parse_tables_xml($xml_file, $db_type)
500 {
501 
502  $dbtype = _getDbType();
503 
504  try {
505  $root = new SimpleXMLElement($xml_file, LIBXML_NOCDATA, TRUE);
506  } catch (Exception $e) {
507  throw new Exception('Could not parse tables XML file: '.$e->getMessage());
508  }
509 
510  if (($root->getName() != 'schema') || !isset($root->tables) || !isset($root->sequences)) {
511  throw new Exception('Tables XML file is not valid.');
512  trigger_localised_error('SYS0012', E_USER_WARNING);
513  return FALSE;
514  }
515 
516  $info = Array();
517  $info['tables'] = Array();
518  $info['sequences'] = Array();
519 
520  //-- TABLES --//
521 
522  foreach ($root->tables->table as $table) {
523  $table_name = (string)$table->attributes()->name;
524 
525  $info['tables'][$table_name] = Array();
526  $info['tables'][$table_name]['rollback'] = (($table->attributes()->{'require_rollback'} == 1) ? TRUE : FALSE);
527 
528  //-- TABLE COLUMNS --//
529  $info['tables'][$table_name]['columns'] = Array();
530 
531  foreach ($table->columns->column as $table_column) {
532  $column_name = (string)$table_column->attributes()->name;
533 
534  $info['tables'][$table_name]['columns'][$column_name] = Array();
535  $info['tables'][$table_name]['columns'][$column_name]['allow_null'] = (($table_column->attributes()->{'allow_null'} == 1) ? TRUE : FALSE);
536 
537  //-- TABLE COLUMN VARS --//
538 
539  $type = NULL;
540  $default = NULL;
541 
542  foreach ($table_column->children() as $column_var) {
543  switch (strtolower($column_var->getName())) {
544  case 'type' :
545  // set the type of the column if it hasnt already been
546  // set in a variation (this is the default column type)
547  if (is_null($type)) $type = (string)$column_var;
548  break;
549  case 'type_variations' :
550  // check for varitions of the column type for his database
551  foreach ($column_var->children() as $variation) {
552  if ($variation->getName() == $dbtype) {
553  $type = (string)$variation;
554  break;
555  }
556  }
557  break;
558  case 'default' :
559  if (trim((string)$column_var) != '') {
560  $default = (string)$column_var;
561  }
562  break;
563  default :
564  continue;
565  break;
566  }
567  }
568  $info['tables'][$table_name]['columns'][$column_name]['type'] = $type;
569  $info['tables'][$table_name]['columns'][$column_name]['default'] = $default;
570 
571  //-- KEYS --//
572 
573  $info['tables'][$table_name]['primary_key'] = Array();
574  $info['tables'][$table_name]['unique_key'] = Array();
575 
576  if (isset($table->keys) && (count($table->keys->children()) > 0)) {
577  foreach ($table->keys->children() as $table_key) {
578  $index_db_type = $table_key->attributes()->db;
579  if (!is_null($index_db_type) && ((string)$index_db_type != $dbtype)) {
580  continue;
581  }
582 
583  // work out the columns in this key
584  $key_columns = Array();
585  foreach ($table_key->column as $table_key_column) {
586  $col_name = (string)$table_key_column->attributes()->name;
587  $key_columns[] = $col_name;
588 
589  // cache the primary key columns for this table
590  if ($table_key->getName() == 'primary_key') {
591  $info['tables'][$table_name]['primary_key'][] = $col_name;
592  }
593  if ($table_key->getName() == 'unique_key') {
594  $info['tables'][$table_name]['unique_key'][] = $col_name;
595  }
596  }//end foreach
597  }//end foreach
598  }//end if
599 
600  //-- INDEXES --//
601 
602  // check for any indexes that need creating
603  if (!empty($table->indexes->index)) {
604  foreach ($table->indexes->index as $table_index) {
605 
606  // work out the columns in this index
607  $index_cols = Array();
608  foreach ($table_index->column as $table_index_column) {
609  $index_cols[] = (string)$table_index_column->attributes()->name;
610  }
611 
612  // work out the name of the index
613  $index_name = isset($table_index->attributes()->name) ? (string)$table_index->attributes()->name : reset($index_cols);
614  $index_type = isset($table_index->attributes()->type) ? (string)$table_index->attributes()->type : NULL;
615  $index_db_type = isset($table_index->attributes()->db) ? (string)$table_index->attributes()->db : NULL;
616 
617  $index_info = Array(
618  'name' => $index_name,
619  'columns' => $index_cols,
620  'type' => $index_type,
621  'db_type' => $index_db_type,
622  );
623  $info['tables'][$table_name]['indexes'][$index_name] = $index_info;
624  }//end for
625  }//end if
626  }//end for
627  }//end for
628 
629  foreach ($root->sequences->sequence as $sequence) {
630  $sequence_name = (string)$sequence->attributes()->name;
631  $info['sequences'][] = $sequence_name;
632  }
633 
634  return $info;
635 
636 }//end parse_tables_xml()
637 
651 function create_index_sql($tablename, $column, $index_name=null, $index_type=null, $primary_key=false, $unique_key=false)
652 {
653  if (substr($tablename, 0, 3) != 'sq_') {
654  $tablename = 'sq_' . $tablename;
655  }
656 
657  if (is_array($column)) {
658  $column = implode(',', $column);
659  }
660 
661  if (is_null($index_name)) {
662  $index_name = str_replace(',', '_', $column);
663  }
664 
665  if (!$primary_key && !$unique_key) {
666  $sql = 'CREATE INDEX '.$tablename.'_'.$index_name.' ON '.$tablename;
667  if (!empty($index_type)) {
668  $sql .= '('.$column.') indextype is '.$index_type;
669  } else {
670  $sql .= ' ('.$column.')';
671  }
672  return $sql.';';
673  }
674 
675  if ($primary_key) {
680  $constraint_name = $tablename . '_pk';
681  if (substr($constraint_name, 0, 3) == 'sq_') {
682  $constraint_name = substr($constraint_name, 3);
683  }
684 
685  return 'ALTER TABLE ' . $tablename . ' ADD CONSTRAINT ' . $constraint_name . ' PRIMARY KEY (' . $column . ');';
686  }
687 
688  if ($unique_key) {
689  return 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $tablename . '(' . $column . ');';
690  }
691 
692 }//end create_index_sql()
693 
694 
696  // HELPER FUNCTIONS //
698 function printName($name)
699 {
700  printf ('%s%'.(60 - strlen($name)).'s', $name, '');
701 
702 }//end printName()
703 
704 
705 function printUpdateStatus($status)
706 {
707  echo "[ $status ]\n";
708 
709 }//end printUpdateStatus()
710 
711 
718 function getIndexes()
719 {
720  global $db_conf;
721 
722  $dbtype = _getDbType();
723 
724  switch ($dbtype) {
725  case 'oci':
726  $sql = "SELECT u.table_name as tablename, u.index_name as indexname, DBMS_METADATA.GET_DDL('INDEX',u.index_name) AS indexdef, TRIM(u.degree) AS parallel, CASE WHEN c.constraint_name IS NULL THEN 0 ELSE 1 END AS constraint FROM USER_INDEXES u LEFT JOIN user_constraints c ON (u.index_name=c.constraint_name) WHERE u.TABLE_NAME LIKE 'SQ_%' ORDER BY u.table_name";
727  break;
728  case 'pgsql':
729  $sql = 'SELECT tablename, indexname, indexdef from pg_indexes where tablename like \'sq_%\'';
730  break;
731  }
732 
733  $constraint_list = array();
734 
735  $idx_list = array();
736 
737  $parallel_list = array();
738 
739  if ($sql !== false) {
740  $indexes = MatrixDAL::executeSqlAll($sql);
741  foreach($indexes as $key => $value) {
742  $tablename = strtolower($value['tablename']);
743  if (!isset($idx_list[$tablename])) {
744  $idx_list[$tablename] = array();
745  }
746  switch ($dbtype) {
747  case 'oci':
748  $idx_def = $value['indexdef'];
749  $idx_columns = '';
750 
751  $idx_name = $value['indexname'];
752 
757  preg_match('/index "' . $db_conf['db']['user'] . '"."' . $idx_name . '" on "' . $db_conf['db']['user'] . '"."(.*?)" \((.*?)\)/i', $idx_def, $matches);
758 
759  if (!empty($matches) && !empty($matches[2])) {
760  $idx_columns = str_replace(array(' ', '"'), '', strtolower($matches[2]));
761  }
762 
763  $idx_name = strtolower($idx_name);
764 
769  if (empty($idx_columns) === TRUE) {
770  break;
771  }
772 
773  $idx_list[$tablename][$idx_name] = $idx_columns;
774 
775  $parallel_list[$tablename][$idx_name] = $value['parallel'];
776 
781  if ($value['constraint'] == 1) {
782  $constraint_list[strtoupper($idx_name)] = 1;
783  }
784  break;
785 
786  case 'pgsql':
787  $idx_def = $value['indexdef'];
788  $idx_columns = '';
789 
798  preg_match('/USING btree \((.*?)\)$/i', $idx_def, $matches);
799  if (!empty($matches[1])) {
800  // clean up special quoted names (like "type" in 8.1 dbs)
801  $idx_columns = str_replace(' ', '', str_replace('"', '', $matches[1]));
802  }
803  $idx_list[$tablename][strtolower($value['indexname'])] = $idx_columns;
804  break;
805  }
806  }
807  }
808  return array (
809  'index_list' => $idx_list,
810  'parallel_list' => $parallel_list,
811  'constraint_list' => $constraint_list,
812  );
813 }
814 
824 function _getDbType()
825 {
826  $dbtype = MatrixDAL::GetDbType();
827 
828  if ($dbtype instanceof PDO) {
829  $dbtype = $dbtype->getAttribute(PDO::ATTR_DRIVER_NAME);
830  }
831  return strtolower($dbtype);
832 }
833 
834 function check_index_parallel($tablename=null, $idx_name=null)
835 {
836 
837  if ($tablename === null || $idx_name === null) {
838  return;
839  }
840 
841  $dbtype = _getDbType();
842 
843  global $parallel_list;
844  global $parallel_warnings;
845 
846  if ($dbtype == 'oci') {
847  $parallel_check = $parallel_list[$tablename][$idx_name];
848  if ($parallel_check > 1) {
849  $parallel_warnings[] = array($idx_name => $parallel_check);
850  }
851  }
852 }
853