/**
* Gets the children of the root nodes in the correct order from highest in the tree first to the
* lowest. Taken from HIPO_Job_Update_Lookups->prepare().
*
* @return array
* @access public
*/
function getTreeSortedChildren($assetids)
{
    $db = MatrixDAL::getDb();
    $todo_normal = array();
    $todo_shadows = array();
    foreach ($assetids as $assetid) {
        // check if we are updating lookups for a shadow asset, or a bridge
        $id_parts = explode(':', $assetid);
        if (isset($id_parts[1])) {
            $todo_shadows = array_merge($todo_shadows, array_keys($GLOBALS['SQ_SYSTEM']->am->getChildren($assetid)));
        } else {
            $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
            if ($asset instanceof Bridge) {
                if (!method_exists($asset, 'getChildren')) {
                    trigger_localised_error('SYS0204', translate('Shadow asset handler "%s" can not get children'), E_USER_WARNING, $asset->name);
                } else {
                    $todo_shadows = array_merge($todo_shadows, array_keys($asset->getChildren($assetid)));
                }
            }
            $where = 'l.minorid = :assetid';
            $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 't');
            $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'l');
            $sql = 'SELECT t.treeid
					FROM ' . SQ_TABLE_RUNNING_PREFIX . 'ast_lnk_tree t INNER JOIN ' . SQ_TABLE_RUNNING_PREFIX . 'ast_lnk l ON t.linkid = l.linkid
					' . $where;
            $sql = db_extras_modify_limit_clause($sql, MatrixDAL::getDbType(), 1);
            try {
                $query = MatrixDAL::preparePdoQuery($sql);
                MatrixDAL::bindValueToPdo($query, 'assetid', $assetid);
                $treeid = MatrixDAL::executePdoOne($query);
            } catch (Exception $e) {
                throw new Exception('Unable to get treeid for minorid: ' . $assetid . ' due to database error: ' . $e->getMessage());
            }
            $sql = 'SELECT l.minorid, MAX(LENGTH(t.treeid)) as length
					FROM ' . SQ_TABLE_RUNNING_PREFIX . 'ast_lnk_tree t
							 INNER JOIN ' . SQ_TABLE_RUNNING_PREFIX . 'ast_lnk l ON t.linkid = l.linkid
					';
            $where = 't.treeid LIKE :treeid
					  GROUP BY l.minorid ORDER BY length';
            $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 't');
            $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'l');
            try {
                $query = MatrixDAL::preparePdoQuery($sql . $where);
                MatrixDAL::bindValueToPdo($query, 'treeid', $treeid . '%');
                $new_assets = MatrixDAL::executePdoAssoc($query);
            } catch (Exception $e) {
                throw new Exception('Unable to get minorids for treeid: ' . $treeid[0]['treeid'] . ' due to database error: ' . $e->getMessage());
            }
            $todo_normal = array_merge($todo_normal, $new_assets);
        }
        //end else
    }
    //end foreach
    // Make sure lower assets are done after higher ones
    usort($todo_normal, create_function('$a, $b', 'return $a[\'length\'] > $b[\'length\'];'));
    $todo_assetids = array();
    foreach ($todo_normal as $asset_info) {
        $todo_assetids[] = $asset_info['minorid'];
    }
    $todo_assetids = array_unique(array_merge($todo_assetids, $todo_shadows));
    return $todo_assetids;
}
// Because DAL doesn't support row-by-row fetch, we'll do chunked fetch instead,
// 2000 at a time. If we don't get that many results, we'll do one last query
// in case anything had been added since - if we get zero results, we are done
$base_sql = 'SELECT l.majorid, l.linkid, l.minorid
		FROM
			sq_ast_lnk l
		WHERE
			' . db_extras_bitand(MatrixDAL::getDbType(), 'l.link_type', MatrixDAL::quote(SQ_SC_LINK_SIGNIFICANT)) . ' > 0
		ORDER BY
			l.sort_order, l.linkid, l.majorid, l.minorid';
$offset = 0;
$chunk_size = 2000;
$echo_i = 0;
$index = array();
while (TRUE) {
    $sql = db_extras_modify_limit_clause($base_sql, MatrixDAL::getDbType(), $chunk_size, $offset);
    $result = MatrixDAL::executeSqlAssoc($sql);
    // If no further results, we're done.
    if (count($result) == 0) {
        break;
    }
    foreach ($result as $data) {
        $majorid = $data['majorid'];
        unset($data['majorid']);
        if (!isset($index[$majorid])) {
            $index[$majorid] = array();
        }
        $index[$majorid][] = $data;
        $echo_i++;
        if ($echo_i % 200 == 0) {
            fwrite(STDERR, '.');
         printName('Inserting Data (' . number_format($start) . ' - ' . number_format($start + $count) . ' rows)');
         printUpdateStatus('OK', "\r");
         MatrixDAL::commit();
         /**
          * Switch to the source db connector to get the data..
          */
         MatrixDAL::changeDb($source_db);
         /**
          * we got less than the limit?
          * no point hitting the db again, we won't get anything.
          */
         if (count($source_data) < $num_to_fetch) {
             break;
         }
         $start += $num_to_fetch;
         $fetch_source_sql = db_extras_modify_limit_clause($source_sql, $source_dsn['type'], $num_to_fetch, $start);
         $source_data = MatrixDAL::executeSqlAll($fetch_source_sql);
         $count = count($source_data);
     }
     printUpdateStatus(null, "\n");
     /**
      * switch back to the dest db
      */
     MatrixDAL::restoreDb();
 }
 //end foreach
 pre_echo('Rebuilding Indexes');
 foreach ($info['tables'] as $tablename => $table_info) {
     if (!empty($table_info['indexes'])) {
         foreach ($table_info['indexes'] as $index_col => $index_info) {
             printName('Creating index sq_' . $tablename . '_' . $index_info['name']);