if (true !== ($tmp = mysqli_debug($control_string))) {
        printf("[%03d][control string '%s'] Expecting boolean/true, got %s/%s.\n", $offset + 1, $control_string, gettype($tmp), $tmp);
        return false;
    }
    if (!($res = mysqli_query($link, 'SELECT * FROM test'))) {
        printf("[%03d][control string '%s'] [%d] %s.\n", $offset + 2, $control_string, mysqli_errno($link), mysqli_error($link));
        return false;
    }
    clearstatcache();
    if (!file_exists($trace_file)) {
        printf("[%03d][control string '%s'] Trace file has not been written.\n", $offset + 3, $control_string, gettype($tmp), $tmp);
        return false;
    }
    unlink($trace_file);
}
$trace_file = sprintf('%s%s%s', sys_get_temp_dir(), DIRECTORY_SEPARATOR, 'mysqli_debug_phpt.trace');
try_control_string($link, 't:,,:o,' . $trace_file, $trace_file, 10);
try_control_string($link, ':' . chr(0) . 'A,' . $trace_file, $trace_file, 20);
try_control_string($link, 't:o,' . $trace_file . ':abc', $trace_file, 30);
try_control_string($link, 't:o,' . $trace_file . ':ABC,123:b', $trace_file, 40);
try_control_string($link, 't:ABC,123:b;:o,' . $trace_file, $trace_file, 50);
try_control_string($link, 't:A;BC,123:b;:o,' . $trace_file, $trace_file, 60);
try_control_string($link, 't:p:o,' . $trace_file, $trace_file, 70);
try_control_string($link, 't:p,1,,2:o,' . $trace_file, $trace_file, 80);
try_control_string($link, 't:z,1,,2:o,' . $trace_file, $trace_file, 90);
#
mysqli_close($link);
print "done";
if ($IS_MYSQLND) {
    print "libmysql/DBUG package prints some debug info here.";
}
foreach ($lines_trace as $k => $line) {
    $line = trim($line);
    if (preg_match("@^[|\\s]*>([\\w:]+)@ism", $line, $matches)) {
        $functions_trace[$matches[1]] = $matches[1];
    }
}
$found = 0;
foreach ($memory_funcs as $k => $name) {
    if (isset($functions_trace[$name])) {
        $found++;
    }
}
if ($found < count($memory_funcs) - 2) {
    printf("[016] Only %d memory functions have been found, expecting at least %d.\n", $found, count($memory_funcs) - 2);
}
$trace = try_control_string($link, 't:O,' . $trace_file, $trace_file, 20);
if (!strstr($trace, 'SELECT * FROM test') && !strstr($trace, 'mysql_real_query')) {
    printf("[025] SELECT query cannot be found in trace. Trace contents seems wrong.\n");
}
$lines_trace = explode("\n", $trace);
$functions_trace = array();
foreach ($lines_trace as $k => $line) {
    $line = trim($line);
    if (preg_match("@^[|\\s]*>([\\w:]+)@ism", $line, $matches)) {
        $functions_trace[$matches[1]] = $matches[1];
    }
}
$found = 0;
foreach ($memory_funcs as $k => $name) {
    if (isset($functions_trace[$name])) {
        $found++;
}
foreach ($test_functions['doubledot'] as $func) {
    if (isset($functions_trace[$func])) {
        unset($functions_trace[$func]);
        unset($test_functions['doubledot'][$func]);
    }
}
if (!empty($functions_trace)) {
    printf("[115] Dumping list of unexpected functions which should have not been shown when using control string '%s'.\n", $control_string);
    var_dump($functions_trace);
}
$tmp = array_merge($test_functions['doubledot'], $test_functions['simple']);
if (!empty($tmp)) {
    printf("[116] Dumping list of functions which should have been shown when using control string '%s'.\n", $control_string);
    var_dump($tmp);
}
if ($IS_MYSQLND) {
    // mysqlnd only option
    // m - trace memory allocations
    $trace = try_control_string($link, 't:O,' . $trace_file . ':m', $trace_file, 120);
    if (!preg_match("@^[|\\s]*>\\_mysqlnd_pefree@ismU", $trace, $matches) && !preg_match("@^[|\\s]*>\\_mysqlnd_pemalloc@ismU", $trace, $matches)) {
        printf("[125] Memory dump does neither contain _mysqlnd_pefree nor _mysqlnd_pemalloc calls - check manually.\n");
        var_dump($trace);
    }
}
mysqli_close($link);
print "done";
if ($IS_MYSQLND) {
    print "libmysql/DBUG package prints some debug info here.";
}
@unlink($trace_file);