function _db_update(&$qstruct)
{
    global $ERROR;
    global $SCHEMA;
    global $debug;
    if ($debug) {
        echo "_db_update: ";
        print_r($qstruct);
        echo "<br>\n";
    }
    $ERROR = "";
    $tp_table = $qstruct["TABLE"];
    // robustness against wrong calling with *_tp
    if (_db_temporal($tp_table, $table)) {
        $qstruct["TABLE"] = $table;
    }
    // handle callback hooks
    foreach (array("CB_BEFORE", "CB_BEFORE_" . $qstruct["MODE"]) as $cb) {
        if ($test = @$SCHEMA[$table][$cb]) {
            if ($debug) {
                echo "CALLBACK {$cb} -> {$test}<br>\n";
            }
            $qstruct["DATA"] = $test($table, $qstruct["DATA"]);
            if ($ERROR) {
                return null;
            }
        }
    }
    $database = _db_database($table);
    if (!@$qstruct["RAW_MODE"]) {
        $qstruct["DATA"] = _db_prepare_data($table, $qstruct["DATA"]);
    }
    $query = _db_make_update($database, $qstruct, $cb_list);
    if (!$query && !$ERROR) {
        $ERROR = "internal error: cannot create SQL statements";
    }
    if ($ERROR) {
        return null;
    }
    if ($debug) {
        echo "-----------QUERY: {$query};<br>\n";
    }
    $env = array("DB" => $database, "CB" => "_db_cb_process_data");
    $ok = _db_multiquery($env, true, $query, $cb_list);
    if (!$ok || $ERROR) {
        if (!$ERROR) {
            $ERROR = "internal error: cannot execute SQL statements";
        }
        return null;
    }
    // handle callback hooks
    foreach (array("CB_AFTER", "CB_AFTER_" . $qstruct["MODE"]) as $cb) {
        if ($test = @$SCHEMA[$table][$cb]) {
            if ($debug) {
                echo "CALLBACK {$cb} -> {$test}<br>\n";
            }
            $qstruct["DATA"] = $test($table, $qstruct["DATA"]);
            if ($ERROR) {
                return null;
            }
        }
    }
    return true;
}
function mysql_make_update($qstruct, &$cb_list)
{
    // initialize $stack with first qstruct
    $stack = array("UPDATE" => array($qstruct));
    $tp_table = $qstruct["TABLE"];
    if (_db_temporal($tp_table, $table)) {
        $qstruct["TABLE"] = $table;
    }
    $mode = $qstruct["MODE"];
    // add special checks/requests only for the _first_ qstruct
    foreach ($qstruct["DATA"] as $row) {
        if (!@$qstruct["RAW_MODE"] && $mode == "INSERT") {
            _db_check_unique($stack, $table, $row);
        }
        foreach ($row as $field => $value) {
            if (is_array($value)) {
                _db_push_subdata($stack, $table, $field, $value, $row);
            }
        }
    }
    // now do the transitive closure on everything
    $cb_list = array();
    $res = _mysql_make_allref($stack, $qstruct, $cb_list);
    return $res;
}
function app_display_download($tp_table, $cond, $download, $filename)
{
    global $SCHEMA;
    $tp = _db_temporal($tp_table, $table);
    $data = _app_getdata($table, $cond);
    $data["FILENAME"] = $filename;
    if ($filename) {
        if ($cb = @$SCHEMA[$table]["FIELDS"][$download]["CB_DOWNLOAD"]) {
            $data = $cb($data);
        }
        tpl_header_download($data);
        print $data["DATA"][0][$download];
        exit(0);
    } else {
        tpl_header($data);
        tpl_body_start($data);
        print "<tt>" . _tpl_format_ascii($data["DATA"][0][$download]) . "</tt>";
        tpl_body_end($data);
        tpl_footer($data);
    }
}
function _db_realname($tp_table, $field = null)
{
    global $SCHEMA;
    global $RAW_ID;
    if (is_array($field)) {
        // structured case
        $res = array();
        foreach ($field as $item) {
            $res[] = _db_realname($tp_table, $item);
        }
        return $res;
    }
    if (is_string($field) && preg_match("/^\\\\(.*)/", $field, $matches)) {
        return $matches[1];
    }
    if (is_string($field) && preg_match("/^({$RAW_ID})\\.({$RAW_ID})\$/", $field, $matches)) {
        //return $matches[1] . "." . _db_realname($matches[1], $matches[2]);
        return $field;
    }
    if (is_array($tp_table)) {
        // no _exact_ table given -> search for one
        $tlist = "";
        $res = "";
        $res2 = "";
        $count = 0;
        // number of matches
        foreach ($tp_table as $alias => $test) {
            if (is_array($test)) {
                $test = $alias;
            }
            $tlist .= "[{$test}]";
            $test2 = _db_realname($test, $field);
            if ($test2) {
                $count++;
                if (!$res) {
                    $res = _db_realname($test);
                    $res2 = $test2;
                }
            }
        }
        if ($res2) {
            if ($count > 1 && $field) {
                // resolve ambiguity by prepending
                return "{$res}.{$res2}";
            }
            return $res2;
        }
        die("no table found for field '{$field}' ({$tlist})\n");
    }
    // normal case
    _db_temporal($tp_table, $table);
    if (!$table || !@$SCHEMA[$table]) {
        // cannot translate
        return "";
    }
    if ($field) {
        return @$SCHEMA[$table]["FIELDS"][$field]["REALNAME"];
    }
    return @$SCHEMA[$table]["REALNAME"];
}